SDLでボン○ーマンを作ってみる
今回から数回に分けてボン○ーマン風ゲームを、
少しずつ作成していきたいと思います。
まずは簡単な処理から。
キャラクターデータの表示と、FPSの表示を行います。
サンプル画像
main.c
#include "main.h" #include "import.h" static boolean init(void); static void run(void); static void proc_event(void); static void key_event(SDLKey key); static void notify_end(void); static void quit(void); static void wait(void); static void fps(void); extern void blit(int x,int y,SDL_Surface *surface); static void push(int x,int y,Uint16 w,Uint16 h); static void update(void); static void move_abs(int x,int y,int mval); static void move_pos(int x,int y); static SDL_Surface *screen; //ウィンドウ画像ポインタ static SDL_Surface *back_buffer; //バックバッファー static SDL_Rect rects[UPDATE_MAX]; //更新情報テーブル static struct { //前フレーム更新情報 SDL_Rect rect; Uint32 address; } old_draw[UPDATE_MAX]; static struct { //矩形情報の合計 int now; int old; } numrect; static boolean active; //ゲームフラグ static Uint32 elapsed_ms; //経過ミリ秒 static Uint32 fps_rate; //fps計算用 static Uint16 fps_cnt; //fpsカウント static SDLKey key_state; //Key Code static Sint16 screenX = FRAME_WIDTH/2; //横軸 static Sint16 screenY = FRAME_HEIGHT/2; //縦軸 static boolean pressed; //押下 #define MVAL (2) //移動量 #define FPS_X (0) #define FPS_Y (0) #define FPS_W (FRAME_WIDTH/2) #define FPS_H (FONT_SIZE) /* イメージ構造体 */ struct Images{ SDL_Surface *back; SDL_Surface *ball; //必要になればここに追加する }images; int main(int argc, char *argv[]) { if(init()) run(); quit(); return 0; } static boolean init(void) { int x,y; /****************************/ /* ライブラリを初期化する */ /****************************/ if(SDL_Init(INIT_FLAG_SUBSYSTEM) < 0) { printf("初期化に失敗"); return FALSE; } /****************************/ /* スクリーンの初期化 */ /****************************/ screen = SDL_SetVideoMode( FRAME_WIDTH,FRAME_HEIGHT,FRAME_BPP,INIT_FLAG_VIDEO ); if(screen == NULL) { printf("Error get video memory"); return FALSE; } /********************************/ /* バックバッファーの初期化 */ /********************************/ back_buffer = SDL_AllocSurface( screen->flags, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask ); if(back_buffer == NULL) { printf("Error get video memory"); return FALSE; } /********************************/ /* フォントの初期化 */ /********************************/ if( !ttf_init(screen,PATH_FONT,FONT_SIZE, NULL) ){ printf("Error open fontimage"); return FALSE; } /************************************/ /* 画像の読み込み */ /************************************/ images.back = SDL_LoadBMP(PATH_IMAGE01); images.ball = SDL_LoadBMP(PATH_IMAGE02); if(!images.back || !images.ball) { printf("Error open picture image"); return FALSE; } /* 透過色を設定する */ // TODO:マルチプラットフォーム対応なら // 画像からピクセル値を取得する方が良い SDL_SetColorKey(images.ball, SDL_SRCCOLORKEY, 0x000000); /************************/ /* 背景の用意 */ /************************/ for(y = 0;y < WIDTH_SIZE;y++) { for(x = 0;x < HEIGHT_SIZE;x++) { SDL_Rect r; r.x = x*BLOCK_SIZE; r.y = y*BLOCK_SIZE; SDL_BlitSurface(images.back,NULL,back_buffer, &r); } } // screen Blit Image SDL_BlitSurface(back_buffer,NULL,screen,NULL); blit(screenX, screenY, images.ball); rects[0].x = 0; rects[0].y = 0; rects[0].w = screen->w; rects[0].h = screen->h; numrect.now++; return TRUE; } static void run(void) { active = TRUE; while(active) { proc_event(); if(pressed) { key_event(key_state); blit(screenX, screenY, images.ball); } wait(); fps(); update(); } } static void proc_event(void) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ printf("QUIT\n"); notify_end(); break; case SDL_KEYDOWN: /*キーダウン*/ printf("KeyDonw\n"); pressed = TRUE; key_state = ev.key.keysym.sym; break; case SDL_KEYUP: printf("KeyUp\n"); pressed = FALSE; break; case SDL_MOUSEBUTTONDOWN: /*マウスダウン*/ printf("MouseDonw\n"); break; default: break; } } } static void key_event(SDLKey key) { if(key == SDLK_ESCAPE) //終了 notify_end(); else if(key == SDLK_RIGHT) //右移動 move_abs(1,0,MVAL); else if(key == SDLK_LEFT) //左移動 move_abs(-1,0,MVAL); else if(key == SDLK_UP) //上移動 move_abs(0,-1,MVAL); else if(key == SDLK_DOWN) //下移動 move_abs(0,1,MVAL); else ; } static void move_abs(int x,int y,int mval) { screenX = (screenX + x*mval) <= -BLOCK_SIZE ? FRAME_WIDTH - BLOCK_SIZE : (screenX + x*mval) % FRAME_WIDTH; screenY = (screenY + y*mval) <= -BLOCK_SIZE ? FRAME_HEIGHT - BLOCK_SIZE : (screenY + y*mval) % FRAME_HEIGHT; } static void move_pos(int x,int y) { screenX = (x < 0) ? 0 : x % FRAME_WIDTH; screenY = (y < 0) ? 0 : y % FRAME_HEIGHT; } static void notify_end(void) { active = FALSE; } static void wait(void) { Uint32 ms; const Uint8 frate = 16; ms = SDL_GetTicks() - elapsed_ms; if(ms < frate) { SDL_Delay(frate - ms); //printf("wait() : %d\n", frate - ms); } elapsed_ms = SDL_GetTicks(); } static void fps(void) { if( !fps_cnt ) { fps_rate = SDL_GetTicks(); fps_cnt++; } else if(++fps_cnt >= FRAME_RATE) { Uint32 elapsed = SDL_GetTicks() - fps_rate; Uint32 fps = (Uint32)(1000.0f/((double)elapsed/(double)FRAME_RATE)); SDL_Rect r = { FPS_X,FPS_Y,FPS_W,FPS_H }; SDL_BlitSurface(back_buffer, &r, screen, &r); r = ttf_puta_color(FPS_X,FPS_Y,0x000000,"FPS : %.2d",fps); push(FPS_X,FPS_Y,FPS_W,FPS_H); fps_rate = 0; //60回分の処理時間をリセット fps_cnt = 0; //1秒間の処理回数カウントをリセット } } static void quit(void) { if(screen != NULL) SDL_FreeSurface( screen ); SDL_Quit(); } static void blit(int x,int y,SDL_Surface *surface) { SDL_Rect tmp; int old; old = -1; if(numrect.old < UPDATE_MAX) { int i; for(i = 0;i < numrect.old;i++) { if(old_draw[i].address == (Uint32)surface) { /****************************/ /* 裏画面を描画 */ /****************************/ SDL_Rect tmp = old_draw[i].rect; push(tmp.x,tmp.y,tmp.w,tmp.h); SDL_BlitSurface(back_buffer, &tmp, screen, &tmp); old = i; break; } } } tmp.w = surface->w; tmp.h = surface->h; tmp.x = x; tmp.y = y; /* 画像データを描画 */ SDL_BlitSurface(surface, NULL, screen, &tmp); push(tmp.x,tmp.y,tmp.w,tmp.h); /* 描画情報をコピー */ if(old != -1) { old_draw[old].rect = tmp; } else { old_draw[numrect.old].address = (Uint32)surface; old_draw[numrect.old].rect = tmp; numrect.old++; } } static void push(int x,int y,Uint16 w,Uint16 h) { if(numrect.now < UPDATE_MAX) { int i = numrect.now; #if 0 rects[i].x = x < 0 ? 0 : x%FRAME_WIDTH; rects[i].y = y < 0 ? 0 : y%FRAME_HEIGHT; rects[i].w = w % (FRAME_WIDTH - rects[i].x); rects[i].h = h % (FRAME_HEIGHT - rects[i].y); #else rects[i].x = x; rects[i].y = y; rects[i].w = w; rects[i].h = h; #endif numrect.now++; } } static void update(void) { /********************************************/ /* 与えられた矩形情報を元に画面の更新 */ /********************************************/ SDL_UpdateRects(screen, numrect.now, rects); /********************************************/ /* 矩形情報をクリアする */ /********************************************/ memset(rects,0,sizeof(rects)); numrect.now = 0; } |