SHOOT DOWN 完成!
いよいよ完成お披露目です!
本当は昨日の時点で完成していましたが、サイトにアップしたところで力尽きました(笑
↓そのサイト。こちらでダウンロード出来ます。
http://tenkomorituuhan2.com/products/shootdown/top.html
プレイするまでもないという方のために、プレイ動画もアップしてます(笑
最後の最期で、ウインドウの閉じるボタン(×ボタン)を押しても処理が残ることに気付きました(こういうところがコンピュータの融通が利かないところ!)。急遽ウインドウの×ボタンを押せないようにして stdlib.h を追加して exit() するようにしました。でもって atexit( DxLib_End ) としようとしたら、登録する関数は void型じゃないとエラーになります。仕方ないので void EndDivision() を新たに作成し、そこで終了させています。・・・でもこれって exit いらね~~~!
if( GetWindowUserCloseFlag( TRUE ) ) exit( 0 );
↑この行を↓こうすればいいだけwww
if( GetWindowUserCloseFlag( TRUE ) ) DxLib_End();
無駄なことをしてしまいましたが、動作に影響するわけではありません。数バイト容量が増えただけなので、もう変更しません!手を加えるとしたら、それは "SHOOT DOWN2" として新たに作り直すときです。その日が来るのか、来たとしても記憶に残っているかは怪しいですが。
で、
出来上がってから、息子にプレイさせてみました。数十回やりましたが、やっと400点超えるくらいです。プレイ中に「弾を見ないで敵ばっか見てるんだよな~」とか、ごちゃごちゃと言い訳していました(笑。息子は動きのあるゲームが苦手なので、ま、こんなもんです。私はテストプレイも含め数百回プレイしました(数秒で終わるときもあるしw)。今のところ17054点が最高です。ガツガツやるより、安全重視のほうがレベルが上がっていき、レベルが上がると1機あたりの点数も上がっていくので、最初はそれである程度スコアが稼げます。でもレベルアップすると難しくもなってくるので、高得点を出すには最初からガツガツやるしかなくなります。とはいえ、それほど真剣にならず気軽に楽しむゲームだと思います。真剣にプレイすると、この手のゲームはマバタキを忘れてしまいます。ドライアイ、気をつけてください。
ブログとしては長くなってしまいますが、完成品のソースコードを掲載します。
※素人が書いたものです。このままコピペして実行するとPCが爆発する恐れもありますので、解かる人が確認した上で使用してください。
#include <stdio.h> #include <stdlib.h> #include "DxLib.h" const int wX = 640; //ウインドウ横幅 const int wY = 480; //ウインドウ縦幅 const int tamakazu = 5; //自機の弾の最大数 const int tekikazu = 10; //敵機の最大数 const int ttamakazu = 100; //敵機の弾の最大数 const int expkazu = 50; //爆発エフェクトの最大数 const int starkazu = 10; //背景星の数 const int tamamx = 7; //自機の弾の発射間隔 int tama[tamakazu]; //自機の弾フラグ int tamaX[tamakazu]; //自機の弾のX座標 int tamaY[tamakazu]; //自機の弾のY座標 int tamacnt; //次弾発射までのカウンタ int tamaNo; //弾の順番 int teki[tekikazu]; //敵機フラグ int tekiX[tekikazu]; //敵機のX座標 int tekiY[tekikazu]; //敵機のY座標 int spd[tekikazu]; //敵機の速度 int tekicnt[tekikazu]; //次弾発射までのカウンタ int tekicntmx[tekikazu]; //次弾発射までの間隔 int ttama[ttamakazu]; //敵機の弾フラグ int ttamaX[ttamakazu]; //敵機の弾のX座標 int ttamaY[ttamakazu]; //敵機の弾のY座標 int ttamaXspd[ttamakazu]; //敵機の弾のX方向速度 int ttamaYspd[ttamakazu]; //敵機の弾のY方向速度 int exp[expkazu]; //爆発フラグ int expX[expkazu]; //爆発のX座標 int expY[expkazu]; //爆発のY座標 int expXspd[expkazu]; //爆発のX方向速度 int expYspd[expkazu]; //爆発のY方向速度 int expcnt[expkazu]; //爆発が消えるまでのカウンタ int starX[starkazu]; //星のX座標 int starY[starkazu]; //星のY座標 int starspd[starkazu]; //星の速度 int score; //スコア int highscore[6]; //ハイスコア int level; //レベル int mouX , mouY; //マウスの座標取得用 int X ,Y; //自機描画用 int miss; //ミスフラグ int gameF; //ゲーム全体のフラグ int Ghandle[5]; //メイングラフィック用ハンドル int Ghandlestar[5]; //星グラフィック用ハンドル int Shandleexp; //爆発音ハンドル int Shandlebgm; //BGMハンドル //プロトタイプ宣言 void Title(); //タイトル画面 void Play(); //メイン void Allinit(); //スタート時初期化 void Tekiinit(); //編隊ごとの初期化 void Load(); //ロード void Save(); //セーブ void EndDivision(); //終了処理 // プログラムは WinMain から始まります int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { SetOutApplicationLogValidFlag( FALSE ); //ログ出力しない SetMainWindowText( "Shoot Down" ); //ウインドウタイトル指定 SetGraphMode( wX , wY , 32 ); //ウインドウの大きさとカラービット数指定 ChangeWindowMode( TRUE ); //ウインドウで表示 SetDrawScreen( DX_SCREEN_BACK ); //ちらつき防止設定 SetWaitVSyncFlag( TRUE ); //フレーム同期 SetMouseDispFlag( TRUE ); //マウスカーソル表示 SetWindowUserCloseEnableFlag( FALSE ); //×ボタンで終了しない if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 LoadDivGraph( "img/sd_main.png" , 5 , 5 , 1 , 32 , 32 , Ghandle ); //メイン画像読込み LoadDivGraph( "img/sd_star.png" , 5 , 5 , 1 , 8 , 8 , Ghandlestar ); //星画像読込み Shandleexp = LoadSoundMem( "sound/sd_exp.wav" ); Shandlebgm = LoadSoundMem( "sound/sd_bgm1.wav" ); atexit( EndDivision ); Load(); //ハイスコアロード { // Main Loop START ///////////////////////////////////////////// while( gameF != 1 ){ Title(); Play(); } } // Main Loop END ////////////////////////////////////////////// DxLib_End() ; // DXライブラリ使用の終了処理 return 0 ; // ソフトの終了 } void Title(){ //タイトル画面///////////////////////////////// for( int i=4 ; i>-1 ; i-- ){ if( score > highscore[i] ){ if( i == 4 ) continue; highscore[i+1] = highscore[i]; highscore[i] = score; } else { if( i < 4 ) highscore[i+1] = score; break; } } if( ( score > 0)||( level > highscore[5] ) )Save(); if( level > highscore[5] ) highscore[5] = level; ClearDrawScreen(); gameF = 0; LoadGraphScreen( 50 , 50 , "img/title.png" , TRUE ); //タイトル画像描画 //スコア表示 int col = GetColor( 255 , 255 , 255 ); DrawFormatString( 5 , 5 , col , "SCORE %d" , score ); DrawFormatString( 540 , 5 , col , "LEVEL %d" , level ); //ハイスコア表示 DrawString( 420 , 100 , "HIGH SCORE" , GetColor( 255 , 255 , 0 ) ); for( int i=0 ; i<5 ; i++ ){ DrawFormatString( 420 , 140+i*20 , GetColor( 255 , 255 , 0 ) , "%d %d" , i+1 , highscore[i] ); } DrawFormatString( 420 , 260 , GetColor( 255 , 255 , 0 ) , "LEVEL %d" , highscore[5] ); DrawString( 50 , 420 , "http://dgen.hatenablog.com/" , GetColor( 255 , 255 , 255 ) ); ScreenFlip(); //描画をウインドウへ反映 while( 1 ){ if( GetWindowUserCloseFlag( TRUE ) ) exit( 0 ); if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) !=0 ) break; if( ( GetMouseInput() & MOUSE_INPUT_RIGHT ) !=0 ){ gameF = 1; break; } WaitVSync( 1 ); } //右クリックで終了 Allinit(); //スタート時初期化 } void Play(){ //メイン///////////////////////////////////////// while( gameF == 0 ){ ClearDrawScreen(); //敵機がいなかったら出現させる int j=0; for( int i=0 ; i<tekikazu ; i++ ){ if( teki[i]<1 ) j++; } if( j == tekikazu ) Tekiinit(); //マウスの位置を取得 if( miss == 0 ){ GetMousePoint( &mouX , &mouY ); if( 16>mouX ) X = 16; else if( mouX>wX-16 ) X = wX-16; else X = mouX; if( 16>mouY ) Y = 16; else if( mouY>wY-16 ) Y = wY-16; else Y = mouY; //自弾発射処理 if( tamacnt>tamamx ){ tama[tamaNo] = 1; tamaX[tamaNo] = X-16; tamaY[tamaNo] = Y-16; tamacnt = 0; tamaNo = ( tamaNo+1 )%tamakazu; } tamacnt++; } else { //ミス処理 for( int i=0 ; i<expkazu ; i++ ){ if( exp[i] > 0 ) continue; exp[i] = 1; expX[i] = (X-16)*10; expY[i] = (Y-16)*10; expXspd[i] = GetRand( 120 )-60; expYspd[i] = GetRand( 120 )-60; expcnt[i] = GetRand( 150 )+105; break; } if( miss == 1 ){ StopSoundMem( Shandlebgm ); PlaySoundMem( Shandleexp , DX_PLAYTYPE_BACK ); } miss++; if( miss > 120 ) gameF = 2; } //自機描画 DrawGraph( X-16 , Y-16 , Ghandle[0] , TRUE ); //自弾移動処理 for( int i=0 ; i<tamakazu ; i++ ){ if( tama[i]>0 ){ tamaY[i] = tamaY[i]-16; if( tamaY[i]<-16 ){ tama[i] = 0; continue; } DrawGraph( tamaX[i] , tamaY[i] , Ghandle[2] , TRUE ); } } //敵機移動処理 for( int i=0 ; i<tekikazu ; i++ ){ if( teki[i]<1 ) continue; tekiY[i] = tekiY[i]+spd[i]; if( tekiY[i]/10 > wY ){ teki[i] = 0; continue; } for( int j=0 ; j<tamakazu ; j++ ){ //自弾と敵機の当たり判定 if( tama[j] < 1 ) continue; if( ( tamaX[j]-tekiX[i]/10 > -30 )&&( tamaX[j]-tekiX[i]/10 < 30 )&&( tamaY[j]-tekiY[i]/10 > -30 )&&( tamaY[j]-tekiY[i]/10 < 30 ) ){ for( int k=0 ; k<expkazu ; k += 5 ){ if( exp[k] > 0 ) continue; PlaySoundMem( Shandleexp , DX_PLAYTYPE_BACK ); score = score+8+level*2; for( int l=k ; l<k+5 ; l++ ){ exp[l] = 1; expX[l] = tekiX[i]; expY[l] = tekiY[i]; expXspd[l] = GetRand( 120 )-60; expYspd[l] = GetRand( 120 )-60; expcnt[l] = GetRand( 150 )+105; } break; } tama[j] = 0; teki[i] = 0; } } tekicnt[i]++; //敵弾発射処理 if( tekicnt[i] > tekicntmx[i] ){ tekicnt[i] = 0; for( int t=0 ; t<ttamakazu ; t++ ){ if( ttama[t] > 0 ) continue; ttama[t] = 1; ttamaX[t] = tekiX[i]+100; ttamaY[t] = tekiY[i]+100; int tempX , tempY; if( X*10-ttamaX[t] > 0 ) tempX = 1; else tempX = -1; if( Y*10-ttamaY[t] > 0 ) tempY = 1; else tempY = -1; ttamaXspd[t] = ( GetRand( 30 )+5+level/5 )*tempX; ttamaYspd[t] = ( GetRand( 30 )+5+level/5 )*tempY; break; } } //自機と敵機の当たり判定 if( ( X-tekiX[i]/10 > -14 )&&( X-tekiX[i]/10 < 46 )&&( Y-tekiY[i]/10 > -14 )&&( Y-tekiY[i]/10 < 46 )&&( miss == 0 ) ) miss = 1; DrawGraph( tekiX[i]/10 , tekiY[i]/10 , Ghandle[1] , TRUE ); } //敵爆発処理 for( int i=0 ; i<expkazu ; i++ ){ if( exp[i] < 1 ) continue; expX[i] = expX[i]+expXspd[i]; expY[i] = expY[i]+expYspd[i]; expcnt[i] -= 5; if( expcnt[i] < 1 ){ exp[i] = 0; expcnt[i] = 0; continue; } SetDrawBlendMode( DX_BLENDMODE_ALPHA , expcnt[i] ); DrawGraph( expX[i]/10 , expY[i]/10 , Ghandle[4] , TRUE ); } SetDrawBlendMode( DX_BLENDMODE_NOBLEND , 0 ); //敵弾処理 for( int i=0 ; i<ttamakazu ; i++ ){ if( ttama[i] < 1 ) continue; ttamaX[i] = ttamaX[i]+ttamaXspd[i]; ttamaY[i] = ttamaY[i]+ttamaYspd[i]; if( ( ttamaX[i] < -120 )||( ttamaX[i] > wX*10 )||( ttamaY[i] < -120 )||( ttamaY[i] > wY*10 ) ){ ttama[i] = 0; continue; } //自機と敵弾の当たり判定 if( ( ttamaX[i]/10-X > -16 )&&( ttamaX[i]/10-X < 4 )&&( ttamaY[i]/10-Y > -16 )&&( ttamaY[i]/10-Y < 4 )&&( miss == 0 ) ) miss = 1; DrawGraph( ttamaX[i]/10 , ttamaY[i]/10 , Ghandle[3] , TRUE ); } //星描画 for( int i=0 ; i<starkazu ; i++ ){ starY[i] = starY[i] + starspd[i]; if( starY[i] > wY*10 ){ starX[i] = GetRand( wX*10-80 ); starY[i] = -80; } DrawGraph( starX[i]/10 , starY[i]/10 , Ghandlestar[GetRand(4)] , TRUE ); } //スコア表示 int col = GetColor( 255 , 255 , 255 ); DrawFormatString( 5 , 5 , col , "SCORE %d" , score ); DrawFormatString( 540 , 5 , col , "LEVEL %d" , level ); ScreenFlip(); //右クリックで終了 if( ( GetMouseInput() & MOUSE_INPUT_RIGHT ) !=0 ) gameF = 1; //×ボタンで終了 if( GetWindowUserCloseFlag( TRUE ) ) exit( 0 ); } } void Allinit(){ //スタート時初期化/////////////////////////// PlaySoundMem( Shandlebgm , DX_PLAYTYPE_LOOP ); for( int i=0 ; i<tamakazu ; i++ ) tama[i] = 0; for( int i=0 ; i<tekikazu ; i++ ) teki[i] = 0; for( int i=0 ; i<ttamakazu ; i++ ) ttama[i] = 0; for( int i=0 ; i<expkazu ; i++ ) exp[i] = 0; level = 0; X = wX/2; Y = wY-64; tamacnt = 0; tamaNo = 0; score = 0; miss = 0; for( int i=0 ; i<starkazu ; i++ ){ starX[i] = GetRand( wX*10-80 ); starY[i] = GetRand( wY*10 ); starspd[i] = GetRand( 20 )+20; } } void Tekiinit(){ //編隊ごとの初期化/////////////////////////// level++; for( int i=0 ; i<tekikazu ; i++ ){ teki[i] = 1; tekiX[i] = GetRand( wX*10-640 )+320; tekiY[i] = -GetRand( 3200 ); spd[i] = GetRand( 50 )+20+level/6; tekicnt[i] = 0; tekicntmx[i] = GetRand( 30 )+25-( level/4 ); if( tekicntmx[i] < 10 ) tekicntmx[i] = 10; } } void Load(){ //ロード FILE *fp; errno_t error; if( ( error = fopen_s( &fp , "highscore.sv" , "r" )) !=0 ){ DrawString( 50 , 50 , "セーブデータがありません" , GetColor( 255 , 255 , 0 ) ); DrawString( 50 , 70 , "ファイルを作成します" , GetColor( 255 , 255 , 0 ) ); ScreenFlip(); WaitVSync( 60 ); } else { fread( highscore , sizeof( int ) , 6 , fp ); fclose( fp ); } } void Save(){ //セーブ FILE *fp; errno_t error; if( ( error = fopen_s( &fp , "highscore.sv" , "w" )) !=0 ){ DrawString( 50 , 50 , "セーブできません" , GetColor( 255 , 255 , 0 ) ); ScreenFlip(); WaitVSync( 60 ); } else { fwrite( highscore , sizeof( int ) , 6 , fp ); fclose( fp ); } } void EndDivision(){ //終了処理 DxLib_End(); } |