SDLでボン○ーマンを作ってみる2
ソースコードはこちら
http://www.geocities.jp/finnissy/data/090711.zip
main.c
border-style: solid; border-width: 1px; border-color: #c1ffc1"> #include "main.h" #include "import.h" static boolean init(void); static void back_graund(SDL_Surface *surface,const char *path); 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,int id); static void frame_blit(void); static void push(SDL_Rect *r); static void update(void); static void draw(void); static boolean map_calc(int x,int y,int state); 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 struct { SDL_Rect r; //前フレーム更新情報 int id; } old_draw[UPDATE_MAX]; static struct { SDL_Surface *surface; SDL_Rect r; //更新情報テーブル int id; } now_draw[UPDATE_MAX]; static struct { //矩形情報の合計 int now; int old; int update; } numrect; static SDL_Rect rects[UPDATE_MAX]; 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 = 7*BLOCK_SIZE; static Sint16 screenY = 7*BLOCK_SIZE; static Sint16 move_state; static boolean pressed; //押下 static Sint16 map[HEIGHT_SIZE][WIDTH_SIZE];//2次元表 #define MVAL (2) //移動量 #define FPS_X (0) #define FPS_Y (0) #define FPS_W (FRAME_WIDTH/2) #define FPS_H (FONT_SIZE) #define ID_BALL (0) #define MV_LEFT (0) #define MV_RIGHT (1) #define MV_UP (2) #define MV_DOWN (4) /* イメージ構造体 */ struct Images{ SDL_Surface *back; SDL_Surface *ball; SDL_Surface *wall1; SDL_Surface *wall2; //必要になればここに追加する }images; int main(int argc, char *argv[]) { if(init()) run(); quit(); return 0; } static boolean init(void) { /****************************/ /* ライブラリを初期化する */ /****************************/ 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); images.wall1 = SDL_LoadBMP(PATH_IMAGE03); images.wall2 = SDL_LoadBMP(PATH_IMAGE04); if(!images.back || !images.ball || !images.wall1 || !images.wall2) { printf("Error open picture image"); return FALSE; } /* 透過色を設定する */ // TODO:マルチプラットフォーム対応なら // 画像からピクセル値を取得する方が良い SDL_SetColorKey(images.ball, SDL_SRCCOLORKEY, 0x000000); SDL_SetColorKey(images.wall2, SDL_SRCCOLORKEY, 0x000000); /************************/ /* 背景の用意 */ /************************/ back_graund(back_buffer,PATH_MAP01); // screen Blit Image SDL_BlitSurface(back_buffer,NULL,screen,NULL); blit(screenX, screenY, images.ball, ID_BALL); rects[0].x = 0; rects[0].y = 0; rects[0].w = screen->w; rects[0].h = screen->h; numrect.update++; return TRUE; } static void back_graund(SDL_Surface *surface,const char *path) { FILE *fp; boolean flg; int x,y; fp = fopen(path,"r"); if(fp == NULL) { printf("Error Mapfile loading\n"); return; } flg = FALSE; for(y = 0;y < WIDTH_SIZE;y++) { for(x = 0;x < HEIGHT_SIZE;x++) { SDL_Rect r; int c; r.x = x*BLOCK_SIZE; r.y = y*BLOCK_SIZE; while(!isdigit(c = fgetc(fp)) && !feof(fp) && !ferror(fp)); if(feof(fp) || ferror(fp)) { flg = TRUE; break; } map[y][x] = c = c - '0'; switch( c ) { case 0: SDL_BlitSurface(images.back,NULL,surface, &r); break; case 1: SDL_BlitSurface(images.wall1,NULL,surface, &r); break; case 2: SDL_BlitSurface(images.back,NULL,surface, &r); SDL_BlitSurface(images.wall2,NULL,surface, &r); break; default : break; } } if( flg ) break; } fclose(fp); } static void run(void) { active = TRUE; while(active) { proc_event(); frame_blit(); fps(); draw(); update(); wait(); } } 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 frame_blit(void) { if(pressed) { key_event(key_state); blit(screenX, screenY, images.ball, ID_BALL); } } 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 boolean map_calc(int x,int y, int state) { int x1 = x / BLOCK_SIZE; int y1 = y / BLOCK_SIZE; int x2 = (x + BLOCK_SIZE-1) / (BLOCK_SIZE); int y2 = (y + BLOCK_SIZE-1) / (BLOCK_SIZE); switch( state ) { case MV_LEFT: return (!map[y1][x1] && !map[y2][x1]); case MV_RIGHT: return (!map[y1][x2] && !map[y2][x2]); case MV_UP: return (!map[y1][x1] && !map[y1][x2]); case MV_DOWN: return (!map[y2][x1] && !map[y2][x2]); default: break; } printf("move start point\n"); return TRUE; } static void move_abs(int x,int y,int mval) { int x_dumy; int y_dumy; int x_flg; int y_flg; int now_state; x_dumy = (screenX + x*mval) <= -BLOCK_SIZE ? FRAME_WIDTH - BLOCK_SIZE : (screenX + x*mval) % FRAME_WIDTH; y_dumy = (screenY + y*mval) <= -BLOCK_SIZE ? FRAME_HEIGHT - BLOCK_SIZE : (screenY + y*mval) % FRAME_HEIGHT; x_flg = screenX - x_dumy; y_flg = screenY - y_dumy; now_state = (x_flg > 0) ? MV_LEFT : (x_flg < 0) ? MV_RIGHT : (y_flg > 0) ? MV_UP : (y_flg < 0) ? MV_DOWN : MV_LEFT; printf("%d : %d\n",x_dumy,y_dumy); if( map_calc(x_dumy, y_dumy, now_state) ) //進行方向にトライ { move_state = now_state; screenX = x_dumy; screenY = y_dumy; } else if(move_state != now_state) //前回と今回が同じ進行方向は無理 { //前回の進行方向にトライ switch( move_state ) { case MV_LEFT: if( map_calc(screenX - MVAL,screenY,move_state) ) screenX -= MVAL; break; case MV_RIGHT: if( map_calc(screenX + MVAL,screenY,move_state) ) screenX += MVAL; break; case MV_UP: if( map_calc(screenX,screenY - MVAL,move_state) ) screenY -= MVAL; break; case MV_DOWN: if( map_calc(screenX,screenY + MVAL,move_state) ) screenY += MVAL; break; default: break; } } } 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,0xAABBFF,"FPS : %.2d",fps); push( &r ); 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,int id) { 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 now_draw[i].r.x = x; now_draw[i].r.y = y; now_draw[i].r.w = surface->w; now_draw[i].r.h = surface->h; now_draw[i].surface = surface; now_draw[i].id = id; #endif numrect.now++; } } static void draw(void) { boolean flg; int i,j; /****************************/ /* 裏画面を描画 */ /****************************/ for(i = 0;i < numrect.now;i++) { flg = FALSE; for(j = 0;j < numrect.old;j++) //前フレームで描画した場所は裏画面を描画 { if(now_draw[i].id == old_draw[j].id) { SDL_Rect tmp = old_draw[j].r; push( &tmp ); SDL_BlitSurface(back_buffer, &tmp, screen, &tmp); old_draw[j].r = now_draw[i].r; //update the Rect Infomation flg = TRUE; break; } } if( !flg && (numrect.old < UPDATE_MAX)) //初登録のID { old_draw[numrect.old].r = now_draw[i].r; old_draw[numrect.old].id = now_draw[i].id; numrect.old++; } } /****************************/ /* 画像を描画 */ /****************************/ for(i = 0;i < numrect.now;i++) { SDL_Rect tmp = now_draw[i].r; push( &tmp ); SDL_BlitSurface(now_draw[i].surface, NULL, screen, &tmp); memset( now_draw, 0, sizeof(now_draw)); numrect.now = 0; } } static void push(SDL_Rect *r) { if(numrect.update < UPDATE_MAX) { int i = numrect.update; #if 0 rects[i].x = r->x < 0 ? 0 : r->x%FRAME_WIDTH; rects[i].y = r->y < 0 ? 0 : r->y%FRAME_HEIGHT; rects[i].w = r->w % (FRAME_WIDTH - rects[i].x); rects[i].h = r->h % (FRAME_HEIGHT - rects[i].y); #else rects[i] = (*r); #endif numrect.update++; } } static void update(void) { /********************************************/ /* 与えられた矩形情報を元に画面の更新 */ /********************************************/ SDL_UpdateRects(screen, numrect.update, rects); /********************************************/ /* 矩形情報をクリアする */ /********************************************/ memset(rects,0,sizeof(rects)); numrect.update = 0; }
|