[GpGiki 대문으로]

지피껨 만들기 03


지피껨 만들기.. (3)

샬롬~

이런 이런....

실은 이번에는 좀 게임다운 녀석(?)을 만들기 위해 스프라이트 에디터와 맵 에디터를 물색하고 있었는데..

GP32에 맞추려니... DOS 시절의 녀석을 찾아봤고...

결론은.....

Win2K에선 안돌아간다.....였습니다. (좌절)

게다가... 오랜만에 DOS 시절 아마추어 게임들을 받아서 플레이를 시도했으나......... 말끔히 실패....... 재부팅까지 하는 놈도 있더군요. T_T

( 여담이지만.. 집에는 486DX2가 있습니다. +_+ ) ( 이런 일이 일어날 줄 알고... 모셔둔.... -_- ) ( 실은... 486DX2만 있습니다. T_T )

그래서... 무언가 툴을 이용하는 건.... 다음으로 미루도록 하고.. ^^;;;;;;

GP32에서 제공하는 기본적인 툴들을 활용하도록 하겠습니다. ^^

아참, 깜빡한 게 있는데.... GP32는 기본적으로 320x240에 8bit color입니다. 물론, 16bit color도 사용할 수 있습니다. ( 기본이 8bit color라는 거죠^^ )

그런데.. 특이한 점이.. 실제로 LCD가 16bit 컬러를 발현하기 때문에... DOS 시절의 8bit color와는 다르죠. T_T

( 원래는 RGB가 각각 64 단계였죠? 즉, 64x64x64 컬러인데... GP32는 RGB가 각각 5bit, 즉, 2^5=32 단계죠... 32x32x32 컬러니까.... 2x2x2=8분의 1로 줄어든 셈이죠. 문제는... 작업할 때는 RGB가 각각 64단계인데... GP32로 보면 32단계가 된다는 점입니다. 즉, 그래픽의 질적 차이가 두드러지겠죠. 물론.... 애뮬레이팅을 했을 때도 그런지는 잘 모르겠지만요-_- )

4. 캐릭터를 움직여보자~ ^^

으윽........

일단 신음 소리 먼저 냅니다. 실은 이거 하나 하려고 제가 삽질을 좀 많이 해서... -_-

위에서 툴이 없었다고 이야기를 했죠? 그래서.. 어떻게 할까.. 고민하다가.. 그냥 GPSDK 예제에 있는 그림을 바이너리 파일로 뽑아서 쓰기로 했죠.

그.런.데... 거기서 문제가 생긴 겁니다. 이미지의 가로 길이가 무조건 4의 배수여야 한다는 걸 몰랐었기 때문에.. 이상하게도 오른쪽에 남는 검은 띠로 졸라 고생을 했죠. T_T

하여튼... 그런 겁니다. -_-;;;;

일단, GPSDK 예제에 있는 그림을 바이너리로 뽑아보죠!!

#include <stdio.h>
#include "img_background.c"
#include "img_sprite.c"

void main()
{
	int width, height, size;
	FILE *fp;

	width = 320;
	height = 240;

	fp = fopen( "back.img", "wb" );
	fwrite( &width, 2, 1, fp );
	fwrite( &height, 2, 1, fp );
	if( height % 4 )	height += 4 - ( height % 4 );
	size = width * height;
	fwrite( img_back, size, 1, fp );
	fclose( fp );

	width = 80;
	height = 150;

	fp = fopen( "char.img", "wb" );
	fwrite( &width, 2, 1, fp );
	fwrite( &height, 2, 1, fp );
	if( height % 4 )	height += 4 - ( height % 4 );
	size = width * height;
	fwrite( img_char, size, 1, fp );
	fclose( fp );
}

맨 위의 img_background.c하고 img_sprite.c는 ex008이나 ex009에서 챙기면 됩니다. ^^

하여튼, Build & Run을 해주면 back.img하구 char.img라는 파일이 떨어지죠.

자, 그럼 그 두 녀석을 어케 쓸까여? ^^

이전까지는 test.smc( 다른 이름일 수도 있음. 그냥 Virtual SMC )가 아무 의미가 없었죠. 이제부터는... 여기에 이런 데이터, 저런 데이터를 넣는 겁니다.

( 그렇게 해도 되나? 맞겠지.. 뭐... -_- ) ( 역시... 정식 GP32 개발자가 아니라서 벌이는 뻘짓인가... )

gpdev.exe를 실행하고, SMC manager를 띄운 뒤... Open을 해서 test.smc를 엽니다.

잘 보면 창이 위/아래 둘인데.. 위가 SMC의 내용이고, 아래가 Local Disk의 내용이죠.

즉, 필요한 내용을 아래에서 위로 끌어서 저장할 수 있고, 반대로 아래로 끌어와 SMC에서 하드로 읽어올 수도 있죠.

일단 저는 gp:/game/data까지 폴더를 생성해서 거기에 데이터를 넣습니다. 폴더를 만들었으면.... back.img와 char.img가... 잘 들어갔죠?

자, 그럼 이번에 다루는 소스를 봅시다. 전보다는 조금 길지도... ^^

( 아차, 저번에 다룬 내용에 빼먹은 점을 지적합니다. 키 입력을 얻는 함수는 gpstdlib.h에 정의되어 있는데.. 그걸 include 안했더군요. T_T 컴파일 시에 warning이 뜨는데.. 급히 하느라 깜빡.. 죄송 ^^ )

#include "gpdef.h"
#include "gpstdio.h"
#include "gpstdlib.h"
#include "gpgraphic.h"
#include "gpfont.h"
#include "gpmain.h"

unsigned char keydata;

GPDRAWSURFACE gpDraw[2];
int nflip = 0;

ubyte *img_back = NULL;
ubyte *img_char = NULL;

ubyte *read_image( char *name )
{
	ubyte *image = NULL;
	int size, rcount;
	F_HANDLE h_file;

	GpFileGetSize( name, &size );

	GpFileOpen( name, OPEN_R, &h_file );
	image = gp_mem_func.malloc( size );
	GpFileRead( h_file, image, size, &rcount );
	GpFileClose( h_file );

	return image;
}

void put_image( int x, int y, ubyte *image )
{
	if( image )
	{
		int width = *(word*)image;
		int height = *(word*)( image + 2 );
		GpBitBlt( NULL, &gpDraw[nflip], x, y, width, height, image + 4, 0, 0, width, height );
	}
}

void put_sprite( int x, int y, ubyte *image )
{
	if( image )
	{
		int width = *(word*)image;
		int height = *(word*)( image + 2 );
		GpTransBlt( NULL, &gpDraw[nflip], x, y, width, height, image + 4, 0, 0, width, height, 0xEF );
	}
}

int init()
{
	GpLcdSurfaceGet( &gpDraw[0], 0 );
	GpLcdSurfaceGet( &gpDraw[1], 1 );

	GpSurfaceSet( &gpDraw[0] );

	if ( !( GPC_LCD_ON_BIT & GpLcdStatusGet() ) )	GpLcdEnable();

	GpFatInit();

	img_back = read_image( "gp:gamedataback.img" );
	img_char = read_image( "gp:gamedatachar.img" );

	return 0;
}

void GpMain( void *arg )
{
	int x = 0, y = 0;

	if( init() )	return;

	while( 1 )
	{
		keydata = GpKeyGet();

		if( keydata & GPC_VK_UP )	y--;
		if( keydata & GPC_VK_DOWN )	y++;
		if( keydata & GPC_VK_LEFT )	x--;
		if( keydata & GPC_VK_RIGHT )	x++;

		put_image( 0, 0, img_back );
		put_sprite( x, y, img_char );

		GpTextOut( NULL, &gpDraw[nflip], 0, 0, "TEST +_+", 0xFF );

		GpSurfaceFlip( &gpDraw[nflip++] );
		nflip %= 2;
	}
}

뭐, 조금 길다고 했지만... 그래봤자 얼마 안 길기 때문에.. -_-

일단, 기본적인 세팅은 init 함수로 빼버렸습니다. GpMain이 한결 깔끔해졌죠? ^^

init부터 살펴보면.... GpFatInit();란 놈이 추가됐죠. SMC FAT을 사용할 수 있게 세팅하는 거죠. 왜 그짓을 하냐구요? 우리의 그림 파일들이 SMC에 들어가있으니까... 그런 거죠. -_- 뭐, 나중에 게임 저장/불러오기 같은 거도 해야 하고... 쿨럭...^^

그 아래 있는게 img_back = read_image( "gp:gamedataback.img" ); img_char = read_image( "gp:gamedatachar.img" ); 이 두놈인데.. read_image는.. put_image/put_sprite하고 함께 설명하죠.. 하여튼... 그림 파일을 읽어오는 건지는 아시겠죠? ^^

다시 GpMain으로 돌아가면... put_image하고 put_sprite를 사용하는 부분이랑 GpTextOut이 추가되어 있죠? ^^

GpTextOut은 글자를 출력하는 건데..

그냥 보시면 아시겠지만.. 대단히 간단합니다. 그냥 저렇게 쓰면 되죠. -_-

숫자 등의 데이터를 출력하려면..

	char tmp_string[256];
	gp_str_func.sprintf( tmp_string, "%d", data );
	GpTextOut( NULL, &gpDraw[nflip], x, y, tmp_string, 0xFF );

뭐, 이런 식으로 하면 되죠.

문자 출력 관련의 녀석을 쓰려면... gpfont.h를 include해야 하구요.. ^^

자, 그럼... 대망의 image 처리 부분을 보도록 하죠.

여기에는 File I/O와 Memory Management, Bitmap Blit 등이 복합적으로 쓰였는데요..

먼저, GP32에서 사용하는 Image Data Format을 보죠.

PCX 등의 전통적인 파일들은... 우측으로 X, 아래로 Y의 좌표계를 가지죠. ( PC Screen 좌표계와 동일하죠^^ )

하지만 BMP는 우측으로 X, 위로 Y인 수학에서 쓰이는 좌표계를 사용합니다.

여기까지는 좋.은.데...

문제는 GP32입니다.

이 녀석은 골때리게도...

위로 X 좌표, 오른쪽으로 Y 좌표를 가집니다. ( 화면의 X, Y와 혼동하지 마세요!! )

즉, 데이터가 그림의 왼쪽 아래에서부터 올라오는 방식입니다. -_- ( 진짜 골때리지 않습니까.... 누가 생각한 건지.. -_- )

게다가 그림의 가로 길이는 무조건 4의 배수여야 합니다. ( 이거 땜시 위에서 고생 쪼까 했죠. T_T )

뭐, 이건 나중에 직접 PCX나 BMP 등의 파일에서 데이터를 추출할 때 다시 보도록 하구요...

일단은 그렇게 뽑힌 데이터를 읽는 부분부터 보죠.

ubyte *read_image( char *name )
{
	ubyte *image = NULL;	// return용 Image Data Buffer
	int size, rcount;	// 파일 크기, 실제로 읽힌 크기
	F_HANDLE h_file;	// 파일 핸들. C의 FILE*과 동일하다고 보면.. 쿨럭.. ^^;

	GpFileGetSize( name, &size );	// 파일 크기를 얻습니다~

	GpFileOpen( name, OPEN_R, &h_file );	// 파일을 Read로 열고..
	image = gp_mem_func.malloc( size );	// 데이터 크기만큼 메모리를 할당합니다.
	GpFileRead( h_file, image, size, &rcount );	// 파일에서 읽어오는 거죠.
	GpFileClose( h_file );			// 파일을 닫아줍니다^^

	return image;
}

간단히 주석으로 처리했습니다. 예, 그런 거죠^^

여기서 읽어오는 데이터의 형태를 알아볼까요? ^^

(2byte) - Image의 가로 길이 (width) (2byte) - Image의 세로 길이 (height) (nbyte) - 실제 Image 데이터.. ( n = width * height )

자, 이번에는 그 이미지 데이터를 출력하는 겁니다.

함수가 두개가 있는데..

put_image는 그냥 그림을 그대로 출력하는 거고..

put_sprite는 투명 컬러(Color Key)를 적용해서 출력하는 거죠.

위의 예제에선 투명 컬러를 0xEF로 설정을 했죠. 쉽게 말해서 0xEF인 점은 화면에 찍지 않는 거죠^^

put_image는 내부적으로 GpBitBlt 함수를 이용해서 그대로 Blit하고 put_sprite는 내부적으로 GpTransBlt를 이용해 Color Key 적용 Blit를 하죠~

아아, 별거 아닌 걸로 길게 쓰려니... 내가 힘드네.. -_-

다음에는... 좀 더 게임 같은 녀석을 만들어 보죠. 뭐, 총알 발사....를 하고 싶지만.. 총알 그림이 없으니.. 분신 발사... 같은 거를 하는 예제로... 후후후.. +_+

2002.04.10 아샬


지피껨 만들기로 돌아가기


제일 위로
최종 수정 일시: 01월 05일(2003년) 12:53 AM 편집 | 정보 | 차이 | 비슷한 페이지 DebugInfo
유용한 페이지들: 분류 분류 | 자유로운 연습장 SandBox | 무작위 페이지들 RandomPages | 인기있는 페이지들 MostPopular