SDLボンバーマ○風ゲーム7 ExplosionGame - SDL_Game
こんにちは!
前々からちょくちょく作ってた、ボンバーマ○風ゲームが
ようやく完成?しました。(★≧▽^))★☆
後は暇を見つけて、適当に更新していくつもりです。
興味のある方は、ソースをいじって自分好みのゲームに改造してみてください。
アプリケーションのダウンロードはこちら! → http://www.geocities.jp/finnissy/data/expgame_bin_1_0.zip
ソースコード一式のダウンロードはこちら! → http://www.geocities.jp/finnissy/data/expgame_dev.zip
アプリケーションのダウンロードはこちら! → http://www.geocities.jp/finnissy/data/expgame_bin.zip
ソースコード一式のダウンロードはこちら! → http://www.geocities.jp/finnissy/data/expgame_dev.zip
一応ソースコードも紹介。
game.c
#include "main.h" #include "game.h" #include "import.h" #include "libttf.h" #include "gfx.h" #include "snd.h" #include "color.h" #include "id.h" #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MVAL (2) //移動量 #define FUNC_MAX (10) //同時に実行する関数の最大値 #define MENU01_X (132) #define MENU01_Y (164) #define MENU02_X (164) #define MENU02_Y (204) #define MENU03_X (196) #define MENU03_Y (244) #define FONT_SIZE_MENU (FONT_SIZE+8) #define MOVE_VALUE (BLOCK_SIZE/2) #define SCREEN_X_INIT (1*BLOCK_SIZE) #define SCREEN_Y_INIT (1*BLOCK_SIZE) #define EFFECT_RECT (48) #define MAX_GAMELEVEL (3) //ゲームレベル #define MAX_CHARSIZE (128) #define PLAYER_INIT (8) //残機数 /****************************************************/ /* private member */ /****************************************************/ /************************/ /* flags */ /************************/ static boolean active; //ゲームフラグ static boolean pressed; //押下 static boolean flg_bomb; //爆弾フラグ static int game_state; //状態 static Uint32 frame_count; //カウント /************************/ /* parameter */ /************************/ static Uint32 elapsed_ms; //経過ミリ秒 static SDLKey key_state; //Key Code static Sint16 move_state; static Sint8 key_count = 0; static Sint8 now_menu; static SDLKey old_keys; static SDLKey direction; static int player_num = PLAYER_INIT; extern Uint16 game_level = 1; extern Sint16 screenX = SCREEN_X_INIT; extern Sint16 screenY = SCREEN_Y_INIT; extern Uint16 bomb_level = 1; extern Uint16 fire_level = 1; static struct game_func{ void (*f[FUNC_MAX])(void); int numfunc; } games; static union { char ms_arr[3][MAX_CHARSIZE]; struct { char normal[MAX_CHARSIZE]; char adventure[MAX_CHARSIZE]; char exit[MAX_CHARSIZE]; }; } title; /****************************************************/ /* private method */ /****************************************************/ static void title_event(void); static void fade_event(SDL_Rect *map, int count, int interval, const int arr_size); static void proc_event(void); static void death_event(void); static void end_event(SDL_Rect *map, int count, int interval, const int arr_size, const char *ms); static void menu_blit(void); static void key_event(SDLKey key); static void notify_end(void); static void notify_state(gstate state); static void wait(void); static void frame_blit(void); static void death_frame_blit(void); static void move_abs(int x,int y,int mval); static void move_pos(int x,int y); static boolean dec_keys(SDLKey key); static void proc_keys(SDLKey key); static boolean get_state(void); static void init_position(void); static void chk_endevent(void); static void reset_param(void); static void reset_item(void); static void read_txt(void); static int freads(char *str,FILE *fp,int n,int nline); /************************************************/ /* Public Method */ /************************************************/ void init_game(void) { read_txt(); } gstate proc_title(void) { active = TRUE; play_bgm(sounds.opening); draw_scene(STATE_TITLE); blit_text(MENU01_X,MENU01_Y,COL_BLUE,COL_AQUA,title.normal,ID_MENU01); #if 0 blit_text(MENU02_X,MENU02_Y,COL_BLACK,COL_GRAY,title.adventure,ID_MENU02); #endif blit_text(MENU03_X,MENU03_Y,COL_BLACK,COL_GRAY,title.exit,ID_MENU03); while(active) { title_event(); menu_blit(); draw(); update(); wait(); } return game_state; } gstate proc_fade(void) { int i,j, count; const int size = (FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT); const int interval = 1; SDL_Rect map[(FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT)]; const int w = FRAME_WIDTH/EFFECT_RECT; const int h = FRAME_HEIGHT/EFFECT_RECT; for(j = 0;j < h; j++) { for(i = 0;i < w;i++) { map[i+(j*w)].x = i*EFFECT_RECT; map[i+(j*w)].y = j*EFFECT_RECT; map[i+(j*w)].w = EFFECT_RECT; map[i+(j*w)].h = EFFECT_RECT; } } for(i = 0;i < size; i++) //シャッフル処理 { j = rand()%size-i; swap(&map[i], &map[i+j]); } count = 0; active = TRUE; stop_bgm(); while(active) { fade_event( map, count++, interval, size); update(); wait(); } return game_state; } gstate proc_play(void) { active = TRUE; init_position(); draw_scene(STATE_PLAY); set_player_icon( player_num ); blit_human(screenX,screenY,ID_HUMAN, SDLK_DOWN,0); stop_bgm(); play_bgm(sounds.play); pressed = FALSE; key_count = 0; while(active) { proc_event(); frame_blit(); chk_endevent(); fps(elapsed_ms,FRAME_RATE); draw(); update(); wait(); } return game_state; } gstate proc_death(void) { active = TRUE; //TODO:方向キー押しっぱなしの時の対策。キー入力情報をクリアする play_se(effect.death); death_effect(screenX,screenY); while(active) { death_event(); death_frame_blit(); fps(elapsed_ms,FRAME_RATE); draw(); update(); wait(); } return game_state; } gstate proc_end(void) { if(player_num < 0) { int i,j, count; const int size = (FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT); const int interval = 1; SDL_Rect map[(FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT)]; const int w = FRAME_WIDTH/EFFECT_RECT; const int h = FRAME_HEIGHT/EFFECT_RECT; /********************************/ /* 残りプレイヤーのリセット */ /********************************/ player_num = PLAYER_INIT; /********************************/ /* ゲームレベルのリセット */ /********************************/ game_level = 1; /********************************/ /* 描画情報のリセット */ /********************************/ reset_gfx(); for(j = 0;j < h; j++) { for(i = 0;i < w;i++) { map[i+(j*w)].x = i*EFFECT_RECT; map[i+(j*w)].y = j*EFFECT_RECT; map[i+(j*w)].w = EFFECT_RECT; map[i+(j*w)].h = EFFECT_RECT; } } for(i = 0;i < size; i++) //シャッフル処理 { j = rand()%size-i; swap(&map[i], &map[i+j]); } count = 0; active = TRUE; stop_bgm(); while(active) { end_event( map, count++, interval, size, "Game Over!! (+ _ +)"); update(); wait(); } reset_param(); } else if(game_level+1 > MAX_GAMELEVEL) //ステージオールクリア { int i,j, count; const int size = (FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT); const int interval = 1; SDL_Rect map[(FRAME_WIDTH/EFFECT_RECT)*(FRAME_HEIGHT/EFFECT_RECT)]; const int w = FRAME_WIDTH/EFFECT_RECT; const int h = FRAME_HEIGHT/EFFECT_RECT; /********************************/ /* ゲームレベルのリセット */ /********************************/ game_level = 1; /********************************/ /* 描画情報のリセット */ /********************************/ reset_gfx(); for(j = 0;j < h; j++) { for(i = 0;i < w;i++) { map[i+(j*w)].x = i*EFFECT_RECT; map[i+(j*w)].y = j*EFFECT_RECT; map[i+(j*w)].w = EFFECT_RECT; map[i+(j*w)].h = EFFECT_RECT; } } for(i = 0;i < size; i++) //シャッフル処理 { j = rand()%size-i; swap(&map[i], &map[i+j]); } count = 0; active = TRUE; stop_bgm(); while(active) { end_event( map, count++, interval, size, "Congratulations!!"); update(); wait(); } reset_param(); } else { //ステージを一つクリア ++game_level; /********************************/ /* 描画情報のリセット */ /********************************/ reset_gfx(); reset_item(); notify_state( STATE_FADE ); } return game_state; } void add_func(void (*f)(void)) { int i; for(i = 0;i < games.numfunc;i++) { if(games.f[i] == f) { i = -1; break; } } if(i >= 0 && games.numfunc < FUNC_MAX) { games.f[games.numfunc] = f; games.numfunc++; } } void del_func(void (*f)(void)) { int i; for(i = 0;i < games.numfunc;i++) { if(games.f[i] == f) { int idx = i + 1; while(idx < games.numfunc) { games.f[i] = games.f[idx]; i++; idx++; } games.f[i] = NULL; games.numfunc--; break; } } } /****************************************************/ /* private method */ /****************************************************/ static boolean get_state(void) { return (screenX%MOVE_VALUE) || (screenY%MOVE_VALUE); } static void chk_endevent(void) { if(isdeath(screenX, screenY) || isenemy(screenX,screenY)) //死亡フラグ確定 { game_state = STATE_DEATH; notify_end(); if(--player_num < 0) { notify_end(); notify_state(STATE_END); } else { set_player_icon( player_num ); } } else if( isplay() ) { notify_end(); notify_state(STATE_END); } } static void title_event(void) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ notify_end(); notify_state(STATE_QUIT); break; case SDL_KEYDOWN: /*キーダウン*/ switch( ev.key.keysym.sym ) { case SDLK_UP: key_state = SDLK_UP; play_se( effect.cursor ); break; case SDLK_DOWN: key_state = SDLK_DOWN; play_se( effect.cursor ); break; case SDLK_RETURN: key_state = SDLK_RETURN; play_se( effect.select ); break; default: return; //------abort } pressed = TRUE; break; case SDL_KEYUP: break; case SDL_MOUSEBUTTONDOWN: /*マウスダウン*/ break; default: break; } } } static void menu_blit(void) { if( pressed ) { switch( key_state ) { #if 0 case SDLK_UP: now_menu = (now_menu-1) < 0 ? STATE_END : now_menu-1; break; case SDLK_DOWN: now_menu = (now_menu+1) % (STATE_END+1); break; //unused state_quit #else case SDLK_UP: now_menu = (now_menu-1) < 0 ? STATE_PLAY : now_menu-1; break; case SDLK_DOWN: now_menu = (now_menu+1) % (STATE_PLAY+1); break; //unused state_quit #endif case SDLK_RETURN: notify_end(); if(now_menu == 0) notify_state(STATE_FADE); else #if 0 if(now_menu == 1) notify_state(STATE_FADE); else #else if(now_menu == 1) notify_state(STATE_QUIT); else #endif if(now_menu == 2) notify_state(STATE_QUIT); break; default: break; } #if 0 switch(now_menu) { case 0: blit_text(MENU01_X,MENU01_Y,COL_BLUE,COL_AQUA,title.normal,ID_MENU01); blit_text(MENU02_X,MENU02_Y,COL_BLACK,COL_GRAY,title.adventure,ID_MENU02); blit_text(MENU03_X,MENU03_Y,COL_BLACK,COL_GRAY,title.exit,ID_MENU03); break; case 1: blit_text(MENU01_X,MENU01_Y,COL_BLACK,COL_GRAY,title.normal,ID_MENU01); blit_text(MENU02_X,MENU02_Y,COL_BLUE,COL_AQUA,title.adventure,ID_MENU02); blit_text(MENU03_X,MENU03_Y,COL_BLACK,COL_GRAY,title.exit,ID_MENU03); break; case 2: blit_text(MENU01_X,MENU01_Y,COL_BLACK,COL_GRAY,title.normal,ID_MENU01); blit_text(MENU02_X,MENU02_Y,COL_BLACK,COL_GRAY,title.adventure,ID_MENU02); blit_text(MENU03_X,MENU03_Y,COL_BLUE,COL_AQUA,title.exit,ID_MENU03); break; default: break; } #else switch(now_menu) { case 0: blit_text(MENU01_X,MENU01_Y,COL_BLUE,COL_AQUA,title.normal,ID_MENU01); blit_text(MENU03_X,MENU03_Y,COL_BLACK,COL_GRAY,title.exit,ID_MENU03); break; case 1: blit_text(MENU01_X,MENU01_Y,COL_BLACK,COL_GRAY,title.normal,ID_MENU01); blit_text(MENU03_X,MENU03_Y,COL_BLUE,COL_AQUA,title.exit,ID_MENU03); break; default: break; } #endif pressed = FALSE; } } static void fade_event(SDL_Rect *map, int count, int interval, const int arr_size) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ notify_end(); notify_state(STATE_QUIT); break; case SDL_KEYDOWN: /*キーダウン*/ if(ev.key.keysym.sym == SDLK_ESCAPE) { notify_end(); notify_state(STATE_QUIT); } break; } } if(count/interval < arr_size) { if(count%interval == 0) { paint(map[count/interval], images.field, FALSE); printf("paint : x = %d, y = %d\n",map[count/interval].x,map[count/interval].y); } } else if(count < arr_size+1) { char text[20] = ""; sprintf(text,"ROUND %d START",game_level); play_bgm_once( sounds.fade ); blit_text( (FRAME_WIDTH - (sizeof(text)/4)*get_ttfsize(0))/3, FRAME_HEIGHT/2, COL_BLUE, COL_ORANGE, text, ID_MS_STAGE); draw(); } else if(count < arr_size*5){} else if(count < arr_size*5+1) { draw_scene(STATE_FADE); printf("draw_scene_fade\n"); } else if(count <= arr_size*6) { if(count%interval == 0) { paint(map[(count%arr_size)/interval], images.field, TRUE); //printf("paint : x = %d, y = %d\n",map[count/interval].x,map[count/interval].y); } } else { notify_end(); notify_state( STATE_PLAY ); printf("end fadeevent ...\n"); } } static void proc_event(void) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ // printf("QUIT\n"); notify_end(); notify_state(STATE_QUIT); break; case SDL_KEYDOWN: /*キーダウン*/ // printf("KeyDonw\n"); proc_keys( ev.key.keysym.sym ); break; case SDL_KEYUP: // printf("KeyUp\n"); if( dec_keys(ev.key.keysym.sym) ) { pressed = FALSE; key_count = 0; } break; case SDL_MOUSEBUTTONDOWN: /*マウスダウン*/ // printf("MouseDonw\n"); break; default: break; } } } static void death_event(void) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ notify_end(); notify_state(STATE_QUIT); break; case SDL_KEYDOWN: /*キーダウン*/ if(ev.key.keysym.sym == SDLK_ESCAPE) { notify_end(); notify_state(STATE_QUIT); } break; default: break; } } } static void end_event(SDL_Rect *map, int count, int interval, const int arr_size, const char *ms) { SDL_Event ev; while( SDL_PollEvent(&ev) ) { switch(ev.type) { case SDL_QUIT: /*ウィンドウの[×]ボタン*/ notify_end(); notify_state(STATE_QUIT); break; case SDL_KEYDOWN: /*キーダウン*/ if(ev.key.keysym.sym == SDLK_ESCAPE) { notify_end(); notify_state(STATE_QUIT); } break; } } if(count/interval < arr_size) { if(count%interval == 0) { paint(map[count/interval], images.field, FALSE); } } else if(count < arr_size+1) { char text[20] = ""; sprintf(text,ms); play_bgm_once( sounds.fade ); blit_text( (FRAME_WIDTH - (sizeof(text)/4)*get_ttfsize(0))/3, FRAME_HEIGHT/2-get_ttfsize(0), COL_RED, COL_YELLOW, text, ID_MS_END); draw(); } else if(count < arr_size*6){} else if(count < arr_size*6+1) { draw_scene(STATE_END); printf("draw_scene_title\n"); } else if(count <= arr_size*7) { if(count%interval == 0) { paint(map[(count%arr_size)/interval], images.field, TRUE); } } else { notify_end(); notify_state( STATE_TITLE ); } } static void frame_blit(void) { int i; for(i = 0;i < games.numfunc;i++) { if(games.f[i] != NULL) games.f[i](); } if(flg_bomb && !get_state()) { bomb_start(screenX,screenY); flg_bomb = FALSE; } else if( get_state() ) //自動で移動する { if(key_state == SDLK_ESCAPE) key_event(key_state); else key_event(old_keys); } else if( pressed ) { key_event(key_state); old_keys = key_state; if( get_state() ) frame_count = (direction != key_state) ? 0 : frame_count+1; } blit_human(screenX, screenY, ID_HUMAN, old_keys, frame_count); } static void death_frame_blit(void) { int i; for(i = 0;i < games.numfunc;i++) { if(games.f[i] != NULL) games.f[i](); } if( isfire() ) { notify_end(); game_state = STATE_PLAY; //TODO:残基数により、続行か終了する init_position(); } } static void key_event(SDLKey key) { switch(key) { case SDLK_ESCAPE: notify_end(); notify_state(STATE_QUIT);break; case SDLK_RIGHT: move_abs(1,0,MVAL); break; case SDLK_LEFT: move_abs(-1,0,MVAL); break; case SDLK_UP: move_abs(0,-1,MVAL); break; case SDLK_DOWN: move_abs(0,1,MVAL); break; default: break; } if(key != SDLK_ESCAPE) direction = key; } static boolean dec_keys(SDLKey key) { switch(key) { case SDLK_RIGHT: key_count--; break; case SDLK_LEFT: key_count--; break; case SDLK_UP: key_count--; break; case SDLK_DOWN: key_count--; break; default: return FALSE; } return key_count <= 0 ? TRUE : FALSE; } static void proc_keys(SDLKey key) { switch(key) { case SDLK_ESCAPE: key_state = key; break; case SDLK_RIGHT: key_state = key; key_count++; break; case SDLK_LEFT: key_state = key; key_count++; break; case SDLK_UP: key_state = key; key_count++; break; case SDLK_DOWN: key_state = key; key_count++; break; case SDLK_SPACE: flg_bomb = TRUE; return; default: return; } pressed = TRUE; } void swap(SDL_Rect *a,SDL_Rect *b) { SDL_Rect t; t = (*a); (*a) = (*b); (*b) = t; } 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 notify_state(gstate state) { game_state = state; } 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 init_position(void) { screenX = SCREEN_X_INIT; screenY = SCREEN_Y_INIT; } static void reset_param(void) { pressed = FALSE; flg_bomb = FALSE; frame_count = 0; key_state = 0; key_count = 0; move_state = 0; now_menu = 0; old_keys = 0; direction = 0; game_level = 1; init_position(); player_num = PLAYER_INIT; reset_item(); } static void reset_item(void) { bomb_level = 1; fire_level = 1; } static void read_txt(void) { FILE *fp; fp = fopen(PATH_TEXT02, "r"); if(fp == NULL) { sprintf(title.normal,title.normal); sprintf(title.adventure,title.adventure); sprintf(title.exit,title.exit); } else { freads(title.normal,fp,0,0); freads(title.adventure,fp,0,1); freads(title.exit,fp,0,2); } } /******************************************* 引数の説明 str : ファイルから取得する文字列を格納 fp : ファイルポインタ n : ファイルから取得する文字数(行数単位か、文字数単位) nline : ファイルから取得する行番号を指定 ********************************************/ static int freads(char *str,FILE *fp,int n,int nline) { int i; int c; char *t; if(fp == NULL || n > sizeof(str)) return FALSE; memset(str,0,sizeof(str)); if( nline >= 0 ) { /* 指定行数の文字列取得 */ c = i = 0; if( nline > 0 ) { while(!feof(fp) && !ferror(fp)) { if(fgetc(fp) == '\n') { if(++i >= nline) break; } } if( !feof(fp) && !ferror(fp) ) { fgets(str,1000,fp); t = strrchr(str,'\n'); if(t != NULL) *t = '\0'; } } else { if( !feof(fp) && !ferror(fp) ) { fgets(str,1000,fp); t = strrchr(str,'\n'); if(t != NULL) *t = '\0'; } } } else { /* 指定した文字数を取得する */ for(c = i = 0; i < n; i++) { if(!feof(fp) && !ferror(fp)) { if((c = fgetc(fp)) != '\n') str[i] = c; } } } fseek(fp,0,SEEK_SET); return TRUE; } |