도트 먹기 게임의 연구 목적으로, 메가드라이브에 팩맨을 제멋대로 이식하고 있습니다만, 깊게 연구하면 할 수록, 정말 대단한 게임이었구나 하는 것을 실감하고 있습니다. 단순한 게임인 것처럼 보이지만, 실은 꽤나 복잡한 구조로 만들어져 있는 게임입니다.

 

 

 메가드라이브 실기 + 브라운관 환경에서 촬영한 영상입니다.

 

 <고생했던 점>

 

* 속도가 미묘하게 달라지는 캐릭터를 제대로 맵의 길에 올려서 벽에 파묻히거나 하지 않고 움직이게 하는 것

* 팩맨의 숏컷

* 몬스터는 방향을 전환하기 3~4프레임 전쯤에 이동하는 방향으로 눈을 향하고 있다

* 메가드라이브의 PSG(DCSG)로 딱딱 떨어지는 좋은 소리를 내는 것

* 세로 해상도가 부족하므로 맵을 스크롤할 필요가 있었다

 

등이 있습니다만, 메가드라이브의 처리가 빠른 것과 개발 환경인 SGDK가 매우 잘 되어 있어서 최적화를 그리 신경쓰지 않아도 느려지거나 하는 일 없이 움직일 수 있었습니다.

 

 잊어버리지 않도록, 제가 프로그래밍한 내용을 정리해 두려고 합니다. 이번에는 구조체에 대해서입니다.

 게임을 만들 때에는 변수를 잔뜩 사용하게 됩니다만, 대충 변수를 막 늘려 가다 보면 수가 늘어남과 동시에 머릿 속이 혼란스러워져 대처하기가 어렵게 됩니다.

 C++에서는 클래스를 준비하여, 클래스별로 변수를 관리하면 혼란을 막을 수 있지만, SGDK는 C언어이므로 저의 경우 구조체를 이용해서 변수를 기능별로 정리하여 관리하고 있습니다. 만들었던 구조체를 소개합니다.

 

<Col구조체>

 

 Collision의 줄임말로 "Col"이라고 했는데, 캐릭터의 좌표와 충돌 판정용의 정보를 멤버로 가진 구조체입니다.

 게임에 등장하는 플레이어, 몬스터, 과일은 이 구조체에서 좌표와 충돌 판정용의 범위를 관리합니다. 팩맨의 캐릭터는 16x16도트가 기준으로 되어 있어, 그 중심부를 캐릭터의 좌표로 하여 계산하고 있습니다.

 캐릭터끼리의 미묘한 이동속도를 표현하기 위해서, 단위는 16도트의 고정소수점을 이용했습니다.

 각각의 캐릭터는 충돌 판정용의 테두리(??)의 좌표인 iX, iY, iW, iH를 전부 설정해놓고 있습니다. 이 범위를 늘리거나 줄이거나 하여 충돌 판정의 빡빡하거나 여유있는 정도를 조정할 수 있습니다.

 

* 충돌 판정에 사용하고 있는 ??의 좌표를 계산하는 함수

 

void    Colli_updateParemeter(Col *col) 
{
    col->x0 = fix16ToInt(col->fPosX) + col->iX;
    col->y0 = fix16ToInt(col->fPosY) + col->iY;
    col->x1 = col->x0 + col->iW;
    col->y1 = col->y0 + col->iH;
}

 

 이 함수를 이용하여, 중심 좌표에서 충돌 판정용 박스의 좌표 x0, y0, x1, y1을 계산합니다. 충돌 판정에 캐릭터가 닿았는지는 매 프레임마다 계산할 필요가 있습니다. 

 

*1. fix16은 SGDK에 준비되어 있는 16비트용 고정 소수점 수

*2. s16은 SGDK에 준비되어 있는 16비트의 정수형으로 short와 같습니다.

*3. fix16ToInt()는 16비트의 고정 소수점을 정수형으로 변환하는 함수 매크로입니다.

 

* 충돌 판정용 함수

 

u8      Colli_check(Col *col_1, Col *col_2) 
{
    if(col_1->x0 < col_2->x1 && col_2->x0 < col_1->x1 &&
       col_1->y0 < col_2->y1 && col_2->y0 < col_1->y1) return TRUE;
    else return FALSE;
}

 

 이 함수에 판정하고 싶은 2개의 Col구조체(col_1과 col_2)의 포인터를 넘기면, 바로 Colli_updateParemeter(Col *col)로 계산한 2개의 사각형 좌표가 겹쳐있는지 어떤지를 판단합니다. 겹쳐 있다면 TRUE, 겹치지 않았다면 FALSE를 돌려줍니다.

 

스프라이트의 표시 위치를 지정하는 함수

 

void    HC_setSpritePosition(u16 index, fix16 x, fix16 y, s16 scrolly)
{
    VDPSprite *sprite = &vdpSpriteCache[index];

    sprite->y = fix16ToInt(y) + 0x80 - 8 - scrolly;
    sprite->x = fix16ToInt(x) + 0x80 - 8;
}

 

 스프라이트는 통상 VBlank의 사이에 설정되어 있습니다만, SGDK에는 스프라이트를 표시하기 위한 캐쉬가 준비되어 있어, VBlank에 들어가기 전에, vdpSpriteCache[]에 수치를 넣어, VBlank에서 정리하여 VDP에 데이터를 전송합니다.

 스프라이트의 좌표는 왼쪽 위가 (0x80, 0x80)의 정수형이므로, 매번 고정소수점 값을 정수로 변환할 필요가 있습니다. 매번 변환하는 것은 귀찮으므로 이와 같은 독자적인 함수를 만들어, 직접 스프라이트의 캐쉬에 써넣도록 하고 있습니다. 또한, 알기 쉽게 화면 왼쪽 위를 (0, 0)으로 하고 있습니다.

 

* s15 scrolly는, 화면의 스크롤용 변수입니다.

 

<Game구조체>

멤버로 하이스코어나 크레딧, 게임 모드 등의 변수가 있습니다.

 

<Player 구조체, PlayerProperty 구조체>

플레이어의 위치, 충돌 판정, 잔기나 라운드 등

 

<Enemy 구조체>

 몬스터 용의 구조체입니다. 4마리 있으므로 사용할 때에는 배열로 선언하고 있습니다.

 

<Fruit 구조체>

 

과일 용입니다. 

 

이게 거의 전부입니다.

 

 소스를 공개하기 위해서, 캐릭터나 음악은 전부 다른 오리지널로 해 봤습니다. 디자인이나 음악이 바뀐 것만으로, 완전히 재미없게 되어 버리는 것은 왜일까요?

 

 소스 : CookieMan.zip

 

SGDK 1.22를 사용해 컴파일하면 돌아갈거라고 생각합니다.

Posted by windship

 도트 먹기 게임의 샘플 프로그램을 만들어, 블로그에 공개하려고 생각하고 있었습니다만, 좀처럼 오리지널 게임을 만들기가 어렵습니다. 아주 좋아하는 게임인 팩맨을 먼저 연구하여, 메가드라이브로 이식해 보기로 했습니다. 전파신문사의 "ALL ABOUT NAMCO"와 Root 씨가 개발한 유선당의 "DOTEAT"가 엄청나게 도움이 되었습니다.

 

<프로그래밍의 메인 부분>

 프로그램의 메인 부분입니다.

 

 Hard_int() 함수를 실행한 뒤, white 안에서 영구적으로 루프를 돌리는 것입니다만, 루프의 제일 마지막에 VDP_waitVSync()를 실행하는 것으로, 60분의 1초가 1사이클이 됩니다. 변수 game.state의 내용으로, 게임의 각 씬에 대응한 함수가 실행됩니다. 처리는 60분의 1초 이내에 행할 필요가 있어서, 그것을 조금이라도 오버하면 1사이클 늦게 처리 지연이 발생합니다.

 

 알기 쉽게, 열거형으로 게임의 씬(GAME_SCENE)을 정의하고 있습니다.

 

<각 씬의 함수 일람>

 프로그램의 내용은, 씬별로 준비한 함수에 채워넣고 있습니다.

 이 메인 함수와 각 씬의 함수가, 프로그램의 기본 구조가 되어 있습니다.

 아직 C언어는 공부한지 2년 정도입니다만, 저의 프로그램의 방침은 우선 전체의 기본적인 구조를 설계하고, 거기에서부터 세부의 설계를 해나간다는 것입니다.

 이것은 ?체 제작과 마찬가지로, 먼저 컨트롤 패널 등의 세부를 만들어 버리면 나중에 기본 구조인 ?체를 만들 떼에 큰 문제가 일어나거나 전체의 밸런스가 나빠지거나 합니다. 우선 전체의 큰 윤곽(?체)를 만들고 나서, 컨트롤 패널 등의 세부를 설계하는 편이 보다 좋게 만들 수 있다고 생각합니다.

 

<함수 일람>

 SGDK는 C++이 아니고 C언어이므로, 클래스는 사용할 수 없습니다. 하지만 클래스와 같은 구조를 상정하고, 함수를 Hard, Game, Round, Player, Enemy, Fruit, Panel, Sprite, Collision 과 같이 나누었습니다.

 

<Hard_함수, Game_함수 일람>

게임 전체를 관리하는 함수입니다.

 

<Round_함수 일람>

라운드(각 판)을 관리하는 함수입니다.

 

<Player_함수 일람>

플레이어(팩맨)의 조작과 움직임, 도트를 먹는 처리를 행하는 함수입니다.

 

<Enemy_함수 일람>

몬스터의 처리를 행하는 함수입니다.

 

<Fruit_함수 일람>

과일을 관리하는 함수입니다.

 

<Panel_함수 일람>

스코어 패널(화면 우측)에 스코어 표시나 잔기 표시를 행합니다.

 

<Sprite_함수 일람>

스프라이트의 표시, 우선순위의 설정 등을 행하고 있습니다.

 

<Colli_함수 일람>

충돌 판정을 행하는 함수입니다.

 

<변수>

 변수는 위의 구조체 7개입니다.

 구조상, 어떤 함수에서도 액세스할 수 있지만, 기본적으로 player는 Player_함수로부터만, enemy는 Enemy_함수로부터만 조작할 수 있도록 하고 있습니다.

 

 이런 느낌으로 구조 설계를 하고 있습니다.

 

 팩맨만 계속 들여다보고 있었더니, 어제 업무 관계로 읽어야만 하는 서류에 이런 일러스트가 눈에 띄었습니다. 어떻게 봐도 팩맨이군요!

Posted by windship

 "메가드라이브 게임을 만드는 방법"이란 주제로 블로그를 시작했지만, 이제서야 이 테마를 다루게 된 것을 반성하고 있습니다. 

  C에서 게임 프로그래밍을 거의 독학으로 공부하기 시작하여 아직 2년도 되지 않았습니다. 그것도 복고풍의 슈팅 게임밖에 공부하지 않았는데 도트 먹기 게임의 프로그래밍, 제작을 개인 용도의 메모를 목적으로 쓰기 시작했다지만, 뭔가 잘난체 하는 듯한 테마로 일반에 공개한다고는...

 최근 일주일간, 플레이어의 조작과 맵과의 충돌 판정의 프로그래밍에 대해서 독학으로 정리하고 있습니다만, 좀처럼 제대로 되지 않고 있습니다. 가끔씩 위 그림과 같이 벽에 파고들어가서 움직이지 못하게 되거나 합니다. 

 플레이어를 항상 길의 정 중앙에서만 움직이면, 의외로 간단한 처리만으로 문제는 해결되지만, 오리지널 팩맨은 코너링을 할 때는 최단거리로 움직인다든지, 60분의 1초에 1도트를 움직이는 것 같은 단순한 움직임이 아니라 몬스터를 포함하여 미묘한 속도로 움직입니다. 팩맨은 플레이어나 몬스터 이동이, 미묘한 속도로 조정되어 있는 게임이었습니다.

 

 캐릭터의 좌표는 직관적으로 알기 쉽게 캐릭터의 중심을 기준으로 하기로 했습니다. 또한 팩맨은 플레이어와 몬스터의 미묘한 이동 속도를 표현하기 위해 고정 소수점으로 계산하기로 했습니다. 그런데 고정 소수점을 제대로 이해하지 않고 사용했기 때문에 계산에 미묘한 차이가 발생했던 것입니다.

 그래서 이번에는 고정 소수점에 대해 정리해 보았습니다.

 

<고정 소수점에 대해>

 

 고정 소수란, 정수를 사용하여 소수를 표현한 것으로, 정수 연산밖에 없는 CPU에서도 빠르게 계산할 수 있습니다. 정수에서 고정 소수점 형식으로 변환하려면 시프트 연산을 사용합니다.

 

  SGDK에는 16비트와 32비트의 고정 소수점이 준비되어 있습니다만, 좌표의 계산은 16비트로 충분하다고 생각했습니다. 16비트라고 하는 것은, 16개의 비트의 ON/OFF로 숫자를 표현하는 것입니다. 위의 표와 같이 SGDK의 16비트 고정 소수점은 최상위 비트가 부호(양수인가 음수인가), 하위 6비트가 소수, 나머지 9비트가 정수 부분으로 구성되어 있습니다. 정수 부분의 자릿수는 2의 0승, 2의 1승 등 2의 거듭제곱 단위의 값을 가지며, 같은 방식으로 소수는 2의 -1승, 2의 -2승 등등 음수의 지수값을 가집니다.

 

 최하위 비트가 10진수로 0.015625 (= 2의 -6승)의 값을 갖는다는 것은 더 이상 작은 수치를 다룰 수 없다는 뜻입니다. 예를 들어 0.1이라고 하는 수치는 정확하게 처리할 수 없고, 0.09370을 근사치로 사용하게 됩니다. 반대로, 0.015625 (또는 1/64)로 나눠 떨어지는 숫자로만 계산하면 오차 없이 정확하게 계산할 수 있습니다.

 

 덧붙여서, 이 16비트 고정 소수점으로 취급할 수 있는 값의 범위는 

 

최대 '0111111111111111' = 10진수 511.984375,

최소 '1000000000000000' = 10진수 -512

 

가 됩니다. 메가드라이브의 화면 해상도는 가로 320, 세로 224 도트이므로 적절한 범위입니다. 단지 빠듯하기 때문에 계산시에는 오버플로우에 주의해야 합니다.

 

 그런데 2의 0승이 1이 된다는 것, 여러분은 알고 있었습니까? 위의 표를 엑셀로 만들고 나서야 이해할 수 있었습니다. 옛날에 배웠었을지도 모르지만요. 산수는 재미있네요.

Posted by windship

 메가드라이브에서 이미지와 텍스트를 표시하기 위해서는 이미지의 형식에 대해 이해할 필요가 있습니다. SGDK에는 ResComp라고 하는, 이미지나 음악 파일을 다루기 위한 유용한 도구가 포함되어 있어, 비교적 쉽게 이미지를 다룰 수 있도록 되어 있습니다. 여기서는 그 사용법을 정리해 보겠습니다.

 

<메가드라이브의 이미지 형식>

 

 이것은 메가드라이브에서 표시가 가능한 512색의 컬러 차트입니다. 각 채널이 3비트인 RGB 색상으로 되어 있습니다.

 

 일반적으로 메가드라이브라고 하면 발색 수가 적다는 인상이 있지만, 사실 사용 가능한 색상은 이 정도로 많습니다. 인간의 눈은 인접한 색상의 차이와 색의 조합은 섬세하게 식별할 수 있지만, 하나하나의 색상의 인식은 상당히 모호합니다. 그렇다는 것은, 결국 궁리하기 나름이라는 것으로, 512색으로도 상당한 표현을 할 수 있다고 생각합니다.

 

 다만 이 512색 중에서, 한 장의 그림에는 임의의 15색을 골라 사용해야 합니다(16색 중 1색은 배경색이 되므로).

 

 EDGE 등의 이미지 편집 소프트웨어는 8비트의 RGB 색상( 빨강, 초록, 파랑 각 채널이 각각 256단계)에서 편집하는 것이 표준적인 사양입니다. 그래서 필자는 각 채널의 값을 0, 36, 73, 109, 146, 182, 219, 255 8단계로 분류하여 이 값에 한정한 이미지 편집을 하고 있습니다.

 

 EDGE에서 팩맨 스타일의 도트 그림을 그려 보았습니다(여전히 센스가 없습니다).

 

 색상 파레트의 맨 위쪽 16색만을 사용하고 있고, 가장 왼쪽의 0번째의 색은 투명색(첫번째 파레트 : PAL 0의 경우 배경색)입니다.

 

 파레트의 빨강, 초록, 파랑 채널의 각 값을 0, 36, 73, 109, 146, 182, 219, 255 중의 하나로 하면 SGDK에 가져와도 감색되지 않고 원한 색이 그대로 출력되는 것입니다. 

 

 '16색으로 저장한다'를 체크하고, PNG 형식으로 저장합니다. 이 파일은 스프라이트로 사용할 예정입니다.

 

gr_char.png

 

 마찬가지로 배경 이미지를 만들고 16색 포맷으로 저장합니다.

 

gr_map.png

 

 SGDK에는 폰트도 준비가 되어 있지만, 이번에는 ATARI FONT로 변경했습니다. ASCII 코드로, 0x20 ~ 0x7F(32 ~ 127)까지의 문자입니다.

 

gr_font.png

 

<이미지와 문자를 표시해 본다>

 

 실제로 메가드라이브에서 이미지와 문자를 표시해 보겠습니다.

 

 그림을 넣을 res 폴더를 프로젝트 안에 만들고, 방금 전의 이미지 파일(gr_font.png, gr_map.png)를 만든 res 폴더에 넣습니다. 또한 ResComp에서 이미지를 로드하게 해 주는 파일 gfx.res를 생성한 뒤, 안에는 다음 두 줄의 코드를 넣습니다. gfx.h는 자동으로 생성되는 것 같습니다.

 

IMAGE image_font "gr_font.png"-1

IMAGE image_map "gr_map.png"-1

 

 main.c의 코드는 다음과 같이 합니다.

 

#include <genesis.h>

#include "gfx.h"

#define TILE_MAP  TILE_USERINDEX  /* gr_map.png의 타일 셋의 VRAM 상의 위치 */

int main()
{

    /* 폰트 디자인의 설정 */
    VDP_loadFont(image_font.tileset, TRUE);

    /* 타일 셋을 읽어들인다 */
    VDP_loadTileSet(image_map.tileset, TILE_MAP, FALSE);

    /* 파레트 데이터를 읽어들인다 */
    VDP_setPalette(PAL0, image_map.palette->data);

    /* 폰트의 파레트 설정 */
    VDP_setTextPalette(PAL0);

    /* 배경맵을 표시 */
    VDP_setMap(PLAN_A, image_map.map, TILE_ATTR_FULL(PAL0, 0, 0, 0, TILE_MAP), 1, 0);

    /* 문자를 표시 */
    VDP_drawTextBG (PLAN_A, "HIGH SCORE", 30,1);
    VDP_drawTextBG (PLAN_A, "   000000", 30,3);
    VDP_drawTextBG (PLAN_A, "1UP", 30,5);
    VDP_drawTextBG (PLAN_A, "   000000", 30,7);
    VDP_drawTextBG (PLAN_A, "CREDIT 00", 30,26);

    while(1)
    {
        
// program
    }
    return (0);
}

 

 실행하면 이렇게 됩니다.

 

 소스 파일 : CookieMan.zip

 

<ResComp에서 사용하는 Image 구조체에 대해>

 

 SGDK에는 이미지를 다루는 구조체인 Image가 준비되어 있어, 여기에는 Palette, TileSet, Map 구조체의 포인터가 멤버로 포함되어 있습니다. ResComp에서 PNG 파일을 가져오면 Image 구조로 로드됩니다.

 

typedef struct
{
    Palette *palette;
    TileSet *tileset;
    Map *map;
} Image;

 

 이런 구조체입니다.

 

 Palette 구조체는, 512 색상 중 어떤 16색을 사용할 것인지에 대한 색상의 지정 데이터입니다.

 

typedef struct
{
    u16 index;
    u16 length;
    u16 *data;
} Palette;

 

 TileSet에는 이미지에 사용되는 타일 데이터(패턴)이 포함되어 있습니다.

 

typedef struct
{
    u16 compression;
    u16 numTile;
    u32 *tiles;
} TileSet;

 

Map에는 이미지의 크기, 타일 맵(이미지의 어떤 위치에서 어떤 패턴이 사용되고 있는지 알려주는 데이터)이 포함되어 있습니다.

 

typedef struct
{
    u16 compression;
    u16 w;
    u16 h;
    u16 *tilemap;
} Map;

 

 

 

Posted by windship

 이번에는, 메가드라이브의 화면 표시에 대해, 화면 모드와 VRAM의 매핑에 대해서 정리해 봤습니다. 자신이 생각하는 대로 표시를 하기 위해서는, 메가드라이브의 이미지 표시 방식에 대해 어느 정도 이해를 할 필요가 있습니다.

 

<메가드라이브의 화면 모드>

 

1. GRAPHIC IV 모드 : 마스터 시스템과의 호환 모드

2. GRAPHIC V 모드 : 메가드라이브의 16비트 모드

 

이렇게 2종류가 있습니다만, 기본적으로는 GRAPHIC V 모드를 사용합니다.

 

 

 위 그림과 같이 (1) 스프라이트 레이어(SPRITE), (2) 윈도우 레이어(WINDOW), (3) 스크롤 A 레이어(SCROLL A), (4) 스크롤 B 레이어(SCROLL B)의 4개 레이어가 존재합니다. 각각의 레이어(스프라이트 레이어는 제외)를 플랜(PLAN) 이라 부릅니다.

 PRIORITY CONTROLLER가 표시 순서를 관리하고 있어, 스프라이트 레이어는 스프라이트 단위로, 그 외의 배경 레이어는 CELL(셀) 단위(8x8 도트를 1 CELL이라고 부릅니다)로 표시 순서를 임의로 설정 가능합니다. PRIORITY의 설정이 같은 경우, 위 그림의 순서대로 표시됩니다.

 다만, 윈도우 레이어(WINDOW)와 스크롤 A 레이어(SCROLL A)는, 공통의 플랜에 표시되고 있기 때문에 겹쳐서 표시하는 것은 불가능합니다.

 

<화면의 해상도 설정>

 

(1) 32x28 CELL(256x224 픽셀)과 (2) 40x28 CELL(320x224 픽셀)의 2종류 모드가 있습니다. 특징으로는 40x28셀 모드일 경우 스프라이트는 80장을 사용할 수 있고, 32x28셀의 경우에는 스프라이트 64장을 사용할 수 있습니다.

 

 SGDK에서는 다음과 같이 하여 해상도를 설정 가능합니다.

 

VDP_setScreenWidth320(); // 40x28셀 모드로 설정

VDP_setScreenWidth256(); // 32x28셀 모드로 설정

 

<스크롤 레이어의 사이즈 설정>

 

 스크롤 A 레이어(SCROLL A)와 스크롤 B 레이어(SCROLL B)는 사이즈 변경이 가능해서, 이하의 사이즈 중에서 선택이 가능합니다. 이 범위의 사이즈라면 한번에 이미지를 읽어들이는 것이 가능합니다. 다만, 판타지 존과 같이 배경 레이어가 넓은 경우(가로 256 CELL)는 한번에 읽어들일 수가 없으므로, 스크롤에 맞춰서 이미지를 다시 읽어줘야 할 필요가 있습니다. 범위가 넓어지면 당연히 VRAM의 사용량이 많아집니다. 보통은 64x32 셀로 설정하는 것으로 문제없지 않을까 라고 생각합니다.

 

(1) 32x32 셀 2Kbytes (32x32x2bytes = 2048 bytes 사용)

(2) 32x64 셀 4Kbytes 

(3) 32x128 셀 8Kbytes

(4) 64x32 셀 4Kbytes

(5) 64x64 셀 8Kbytes

(6) 128x32 셀 8Kbytes

 

 SGDK에서는 다음과 같이 하여 설정합니다.

 

VDP_setPlanSize(64, 32) // 64x32 셀로 설정

 

 

<윈도우 레이어의 설정>

 예를 들어, 판티지 존의 위쪽에 있는 스코어 패널의 표시 등에 사용합니다. 스크롤이 되지 않습니다. 설정 가능한 것은 4각형의 범위로, 한 군데 뿐입니다.

 화면에 대해서, 상단, 하단, 우측단, 좌측단, 좌상단, 우상단 같은 설정도 가능합니다. 최대 40x28 셀 범위에서 사용합니다. VRAM을 가로 한 줄로 40 셀이 아니라 64 셀을 사용하기 위해서, 세로 28 셀을 전부 사용하는 설정이라면, 윈도우 레이어에서 3584(64x28x2) bytes의 VRAM을 확보할 필요가 있습니다.

 

SGDK의 설정

 

VDP_setWindowVPos(FALSE, 5); // 상단의 5셀 부분을 윈도우 레이어로 사용

 

<VRAM의 매핑 설정>

 

 메가드라이브의 VRAM에는 64Kbytes의 용량이 있습니다. 매핑은 자유롭게 변경 가능하고, 이해의 내용이 VRAM에 사용됩니다.

 

(1) 스크롤 A 레이어의 패턴 네임 테이블(SCROLL A PATTERN NAME TABLE)

    각 플랜의 셀의 사용패턴, 파레트, 셀의 반전, 표시 우선순위 등을 정의한 데이터를 패턴 네임 테이블이라고 부르고, 1 셀로 2Bytes를 사용합니다. 최대 8Kbytes(128x32x2Btytes)

(2) 스크롤 B 레이어의 패턴 네임 테이블(SCROLL B PATTERN NAME TABLE). 최대 8k를 사용 가능.

(3) 스크롤 A 레이어와 스크롤 B의 수평 스크롤 양(H SCROLL DATA TABLE) 화면 전체를 한꺼번에 스크롤하는 모드, 셀 단위로 스크롤 시키는 모드, 그리고 라인 단위로 스크롤 시키는 모드가 있다.

(4) 라인 단위라면 1Kbytes(265x2x2화면) 사용. 전 화면이라면 4bytes 뿐입니다.

(5) 스프라이트 어트리뷰트 테이블(SPRITE ATTRIBUTE TABLE)

    스프라이트의 좌표, 사용 패턴, 파레트, 표시 우선순위, 다음에 묘화될 스프라이트의 번호를 정의한 데이터를 스프라이트 어트리뷰트 테이블이라고 부르고, 1 스프라이트에 8bytes 를 사용합니다. 80개의 스프라이트라면 640bytes를 사용하게 됩니다.

(6) 패턴 제네레이터(PATTERN & SPRITE GENERATOR TABLE

    스프라이트, 스크롤 A 레이어, 스크롤 B의 표시에 필요한 비트맵 이미지를 일반적으로 패턴(patterns)라고 부릅니다. 스프라이트에 사용되는 것을 스프라이트 제네레이터, 스크롤 레이어에 사용되는 것을 패턴 제네레이터라고 부릅니다. 패턴 데이터는 양쪽에서 공유 됩니다. 가장 첫 어드레스는 0x0000으로 고정입니다만 데이터 사이즈는 임의입니다.

    데이터는 셀 단위의 배치가 됩니다. 1 셀은 16tor(4비트)의 8x8 픽셀로, 1 셀은 4x8x8= 32bytes의 데이터가 됩니다.

 

SGDK의 설정

 

/* VRAM의 주소 설정 예 */

VDP_setWindowAddress(0xD000);
VDP_setAPlanAddress(0xC000);
VDP_setBPlanAddress(0xE000);

VDP_setHScrollTableAddress(0xF000);
VDP_setSpriteListAddress(0xFC00);

 

/* 스크롤 모드 설정의 예 *'

 

VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_PLANE);  

 

가로, 세로 양쪽 다 PLANE 전체로 스크롤하는 설정입니다.

Posted by windship

출처 : https://ameblo.jp/arcade-cabinet/entry-12268974254.html

 

『メガドライブのゲームの作り方 その1 - SGDKの環境設定』

SGDKを用いて、メガドライブのプログラミングを始めて約10か月。今年で48歳になる劣化した脳細胞は、一週間もすれば覚えたことを忘れてしまいます。そこで、自分…

ameblo.jp

 

 SGDK를 이용해서, 메가드라이브 프로그래밍을 시작한 지 약 10개월. 올해로 48세가 되어 늙어가는 뇌세포는, 1주일 정도면 기억한 것을 잊어 버립니다. 그래서, 제 나름대로 시행착오 끝에 체득한 메가드라이브 게임 만드는 방법을 기록으로 남겨 두기로 했습니다. 팩맨같은 도트 먹기 게임을 실제로 만들어 보려고 합니다.

 

<프로그래밍에 필요한 소프트웨어>

* SGDK : 메가 드라이브의 개발 키트. (Stephane씨에 의해 개발됨)

* Code::Blocks : 오픈 소스 C/C++ 통합개발환경

* EDGE : 256색 도트 그래픽을 위해 개발된 윈도우용 그래픽 에디터

* Fusion : 메가드라이브 에뮬레이터 (이외에도 Gens나 Regen 같은 것들도 있습니다)

 

<SGDK의 인스톨>

 

1. 여기에서 SGDK를 다운로드 한다

  (2017년 4월 25일 최신 버전은 SGDK 1.22)

 

2. 다운로드한 파일을 기억하기 쉬운 곳에 저장

  (여기에서는 C:\MEGADRIVE\sgdk122 로 합니다)

 

3. 윈도우의 환경변수를 설정합니다.

  윈도우 10의 경우, 데스크탑의 '컴퓨터'를 우클릭하고 속성 > 왼쪽 시스템에서 상세설정을 엽니다. 거기에서 뜨는 윈도우 아래쪽의 "환경변수(N)..."을 클릭하고, 유저 환경변수의 "신규(N)..."을 클릭합니다.

  "GDK"와 "GDK_WIN"의 두개의 환경 변수를 신규 등록합니다.

 

  * GDK의 등록 ('\'가 아니라 '/'로 해야합니다)

  * GDK_WIN의 등록

 

<Code::Blocks의 인스톨>

 

1. Code::Blocks 사이트에서 셋업 파일을 다운로드 합니다. codeblocks-16.01mingw-setup.exe 파일을 다운 받습니다(2017. 4. 25 현재 최신 버전).

 

2. 셋업 파일을 실행하여 Code::Blocks를 인스톨합니다. 설정은 전부 디폴트 값으로 해도 문제 없습니다.

 

3. 셋업이 완료되면 Code::Blocks가 실행됩니다.

처음에 컴파일러를 고르는 화면이 나오므로, GNU GCC Compiler를 선택하고 OK를 클릭합니다.

 

4. 다음으로 Code::Blocks의 확장자를 연결하는 과정이 있는데, 확장자 연결이 필요없다면 제일 위의 옵션을 선택합니다.

 

5. Code::Blocks의 메뉴에서 Setting -> Compiler...를 선택합니다.

6. 'Copy'를 클릭합니다.

7. 새로운 컴파일러의 이름을 물어보므로, 'Sega Genesis Compiler'라고 입력하고 OK를 클릭합니다.

 

8. OK를 클릭합니다.

 

9. Toolchain executables의 탭으로 가서 Compiler's installation directory에 있는 '...' 버튼을 클릭하고 SGDK를 설치한 폴더를 선택합니다.

10. Program Files를 아래와 같이 각각 '...' 버튼을 클릭해 선택해 줍니다.

모두 선택했다면 OK를 눌러줍니다. 이것으로 설정은 완료입니다.

 

<프로젝트의 신규 작성>

 

1. Code::Blocks의 메뉴에서 File > New > Project... 를 선택

2. Empty project 를 선택하고 'Go'를 클릭

3. 'Next >'를 클릭

4. 프로젝트 이름과 저장될 폴더를 설정합니다.

  여기에서는 프로젝트 이름을 'CookieMan', 프로젝트 폴더를 'C:\MEGADRIVE\sgdk122\projects'로 했습니다.

5. 아까 위에서 설정한 컴파일러 'Sega Genesis Compiler'를 선택하고, 아래와 같이 설정하고 'Finish'를 클릭하면 새 프로젝트가 만들어집니다.

6. 다음으로 작성한 프로젝트를 우클릭하여 Properties... 를 선택

7. Makefile을 SGDK용의 커스텀 Makefile로 설정하고 OK를 클릭하여 윈도우를 닫습니다.

8. 다시 프로젝트의 Properties...를 열고, 같은 방식으로 윈도우를 닫고, 'Project's build options...'를 클릭

9. 'defaults'에서 "Make" commands 탭을 열고, 아래와 같이 설정한 뒤 OK를 클릭

10. 프로젝트가 저장된 폴더에 아래외 같이 폴더를 추가로 만들어 줍니다.

src : 소스파일(*.c, *.s)

inc : 헤더 파일(*.h, *.inc)

res : 이미지/사운드 리소스 파일(*.wav, *.png)

가 저장될 폴더입니다.

11. 프로그램 소스(main.c)를 만듭니다.

  메뉴의 File > New > File... 을 선택

12. C/C++ source 를 선택하고 'Go'를 클릭

13. 'Next >' 를 클릭

14. C언어를 선택하고, 'Next >' 를 클릭

15. 파일명과 파일 경로를 물어오므로, 'Filename with full path:' 에 있는 '...' 버튼을 클릭

16. 파일명은 main.c로, 경로는 아까 만든 src 폴더를 지정합니다.

17. default에 체크

이것으로, main.c를 Code::Blocks에서 편집할 수 있게 되었습니다.

아래와 같이 코드를 짭니다. SGDK 사이트에 있던 Hello World의 코드입니다.

 

#include <genesis.h>

int main()
{
VDP_drawText("Hello Genny World!", 10, 13);

while(1)
{
//read input
//move sprite
//update score
//draw current screen (logo, start screen, settings, game, gameover, credits...)
}
return (0);
}

 

17. 프로젝트를 빌드합니다.

18. 문제없이 완료된다면, 프로젝트 경로에 있는 out 폴더에 rom.bin이 만들어질 것입니다.

  이 파일을 에뮬레이터로 실행시키면 아래와 같은 화면을 볼 수 있습니다.

  메가드라이브의 롬파일이 완성되었습니다!

 

* 내용은 SGDK의 공식 사이트에 자세하게 설명되어 있습니다.

* 내용에 잘못된 부분이 있을 수도 있습니다. 혹시 틀린 부분을 발견하셨다면, 코멘트로 지적해 주시면 감사하겠습니다.

Posted by windship

1. SGDK 다운로드


   - https://github.com/Stephane-D/SGDK/wiki/Download

   - 임의의 폴더에 압축을 푼다



2. 이클립스 다운로드


   - http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/oxygen3a

   - 다운로드 후 설치(Applications 폴더에 등록)



3. 환경변수 설정


   - http://huskdoll.tistory.com/97

   - 윈도우의 경우에는 내 PC의 속성에서 설정해주지만, 맥OS의 경우는 명령 프롬프트를 사용한다.

   - 명령 프롬프트에서 printenv 라고 입력하면 설정된 변수를 확인할 수 있음

   - GDK라는 환경변수를 세팅하고 그 값을 SGDK 압축 푼 폴더 경로로 지정해야 함

   - nano ~/.bash_profile 입력해서 편집함. bash_profile 파일이 없는 경우는 새로 만드는 것으로 OK

   - export GDK=/Applications/sgdk134 입력하고 저장 후 nano 종료

   - source ~/.bash_profile 입력

   - echo $GDK 입력하여 경로가 잘 지정되었는지 확인



4. 이클립스 세팅


   - https://github.com/Stephane-D/SGDK/wiki/Setup-SGDK-with-Eclipse 


Posted by windship