18. 敵に弾を発射させる。
では、具体的にプログラムの変更点を紹介します。
今回敵の弾に関する事を行ったので、新しくファイルを作ります。
先ほども言いましたが
enemy_shot.cpp をソースに新規で追加してください。
そこに以下のようにコピーしてください。
enemy_shot.cppの中身で解説していない部分は注釈を書いています。難しいことはしていません。
また、enemy_shot.cpp と enemy.cpp は非常によく似ているので、アルゴリズムに関して同じものだと思ってください。
見比べてみるとほとんど同じことしているのがわかります。関数名も似たものにしておきました。
/* enemy_shot.cpp */
/* 素材 ver 1.11以上必要 */
#include "DxLib.h" #include "ExternGV.h" #include <math.h> #define PI 3.141593 #define PATTERN1SPEED 4.0f void EnemyShotPattern1(int i){ if(EnemyShot[i].counter==0){ EnemyShot[i].EnemyShots[0].flag=1; EnemyShot[i].EnemyShots[0].x=EnemyShot[i].mem_ex; EnemyShot[i].EnemyShots[0].y=EnemyShot[i].mem_ey; EnemyShot[i].Angle[0] = atan2(EnemyShot[i].mem_py-EnemyShot[i].mem_ey,EnemyShot[i].mem_px-EnemyShot[i].mem_ex); PlaySoundMem(sound_enemy_shot[0],DX_PLAYTYPE_BACK); } EnemyShot[i].EnemyShots[0].x+=PATTERN1SPEED*cos(EnemyShot[i].Angle[0]); EnemyShot[i].EnemyShots[0].y+=PATTERN1SPEED*sin(EnemyShot[i].Angle[0]); } void EnemyShotControl(){//ショットパターン1を呼ぶための関数enemy.cppのEnemyControl関数と役目一緒 int i; for(i=0;i<ENEMY_TOTAL_NUM;i++){//敵の最大数100体だけループ if(EnemyShot[i].flag==1){//ショットしている玉があれば if(EnemyShot[i].pattern==1)//しかもそれがショットパターン1ならば EnemyShotPattern1(i);//ショットパターン1へ } } } void EnemyShotCalcDisp(){//描画と、画面外に出たらフラグを戻す事を行う関数 for(int i=0;i<ENEMY_TOTAL_NUM;i++){//敵の最大数100体だけループ if(EnemyShot[i].flag==1){//ショットしている弾の組があれば EnemyShot[i].counter++;//ショットカウントをアップ for(int j=0;j<ENEMY_TOTAL_SHOT_NUM;j++){//調べたショットの組の全ての弾(200個)ループ if(EnemyShot[i].EnemyShots[j].flag==1){//ショットしている組の弾で、実際にショットしている弾なら //弾を描画、今回はDrawGraphでもいい。 DrawRotaGraph( (int)EnemyShot[i].EnemyShots[j].x , (int)EnemyShot[i].EnemyShots[j].y , 1.0f , 0.0f , img_enemy_shot[EnemyShot[i].img] , TRUE ) ; //弾が画面より外にあるときは発射フラグを戻す。 if(EnemyShot[i].EnemyShots[j].x<-20.0||EnemyShot[i].EnemyShots[j].x>440.0||EnemyShot[i].EnemyShots[j].y<-20.0||EnemyShot[i].EnemyShots[j].y>500) EnemyShot[i].flag=0; } } } } for(int i=0;i<ENEMY_TOTAL_NUM;i++){//敵の最大数100体分ループ if(EnemyShot[i].flag==1){//敵のショットが発射中なら for(int j=0;j<ENEMY_TOTAL_SHOT_NUM;j++){//1組200個分のループ if(EnemyShot[i].EnemyShots[j].flag==1){//1個でも発射中の弾があれば終了 return; } } EnemyShot[i].flag=0;//全部発射中でなければその組全体の発射フラグを戻す。 } } }
enemy.cppの内容は長いですが、今は使用しない記述が多いのでコメントアウトしておきました。
コメントアウトしていない部分だけみてもらったらいいです。
/* enemy.cpp */
#include "DxLib.h" #include "ExternGV.h" #include <math.h> #define PI 3.141593 /* void EnemyPattern1(int i){ enemy[i].y+=1.5f; } */ void EnemyPattern2(int i){//前章で説明した通り int j; if(enemy[i].counter<50) enemy[i].y+=4.0f; if(enemy[i].counter==75){ for(j=0;j<ENEMY_TOTAL_NUM;j++) if(EnemyShot[j].flag==0) break; EnemyShot[j].mem_ex=enemy[i].x; EnemyShot[j].mem_ey=enemy[i].y; EnemyShot[j].mem_px=Player.x; EnemyShot[j].mem_py=Player.y; EnemyShot[j].counter=0; EnemyShot[j].flag=1; EnemyShot[j].pattern=1; EnemyShot[j].img=0; } if(enemy[i].counter>100) enemy[i].y-=4.0f; } /* void EnemyPattern3(int i){ enemy[i].x+=sin(PI*enemy[i].counter/40.0f)*5.0f; enemy[i].y+=1.5f; } void EnemyPattern4(int i){ if(enemy[i].counter<100) enemy[i].y+=2.5f; if(enemy[i].counter>=100){ enemy[i].x+=sin(PI*(enemy[i].counter-100.0f)/160.0f)*2.5f; enemy[i].y+=sin(PI*(enemy[i].counter-20.0f )/160.0f)*2.5f; } } */ void EnemyControl(){//現在はパターン2の動きだけさせる for(int i=0;i<100;i++){ if(enemy[i].flag==1){ // if(enemy[i].pattern==1) // EnemyPattern1(i); if(enemy[i].pattern==2) EnemyPattern2(i); // if(enemy[i].pattern==3) // EnemyPattern3(i); // if(enemy[i].pattern==4) // EnemyPattern4(i); } } } void EnemyCalcDisp(){ int i; for(i=0;i<100;i++) if(enemy[i].flag==0) break; switch(counter){//今回はパターン2の動きだけさせる case 50: enemy[i].pattern=2; //どういう軌道を描くか enemy[i].flag=1; //出現フラグを立てる enemy[i].counter=0;//出現して何カウント目か測るカウンター初期化 enemy[i].size=0.5f;//敵の大きさ enemy[i].x=100.0; //xの初期座標 enemy[i].y=-10.0; //yの初期座標 break; default: break; } int enemy_img[8]={0,1,2,3,4,3,2,1}; for(i=0;i<100;i++){ if(enemy[i].flag==1){ enemy[i].counter++; DrawRotaGraph( (int)enemy[i].x , (int)enemy[i].y , enemy[i].size , 0.0f , img_enemy1[enemy_img[counter%32/4]] , TRUE ) ; if(enemy[i].x<0.0-MONSTER1_X_SIZE/2.0*enemy[i].size || enemy[i].x>420.0+MONSTER1_X_SIZE/2.0*enemy[i].size || enemy[i].y<0.0-MONSTER1_Y_SIZE/2.0*enemy[i].size || enemy[i].y<0.0-MONSTER1_Y_SIZE/2.0*enemy[i].size) enemy[i].flag=0; } } }
説明はしませんでしたが、今回、ショットの画像を表示するために、配列を用意しました。
音楽ファイルも同様です。赤い字の部分を見てください。
/* GlobalVariable.h */
/* 定義 */ #define PLAYER_MAX_SHOT1 11 #define PLAYER_MAX_SHOT2 15 #define ENEMY_TOTAL_NUM 100 #define ENEMY_TOTAL_SHOT_NUM 200 #define MONSTER1_X_SIZE 140.0 #define MONSTER1_Y_SIZE 128.0 /* グローバル宣言 */ int counter=0; int color_white; char Key[256]; //画像ファイルハンドル int img_background[2]; int img_player[4]; int img_enemy1[5]; //弾 int img_player_shot[2]; int img_enemy_shot[20]; //各種変数 int ShotLevel=11; //音声ファイルハンドル int sound_player_shot[2]; int sound_enemy_shot[2]; //構造体 //プレイヤー typedef struct{ double x,y; int status,counter; } BODY_player_t; BODY_player_t Player; //敵 typedef struct{ double x,y,size; int flag,counter,hp,pattern; } BODY_enemy_t; BODY_enemy_t enemy[ENEMY_TOTAL_NUM];//[100] //ショット typedef struct{ double x,y; int flag; } SHOT_t; SHOT_t PlayerShot[PLAYER_MAX_SHOT1][PLAYER_MAX_SHOT2];//[11][15] typedef struct{ int flag; double x,y; } ENEMY_SHOTS_t; //敵ショット typedef struct{ int flag,pattern,counter,img; double mem_ex,mem_ey,mem_px,mem_py,Angle[ENEMY_TOTAL_SHOT_NUM];//[200]; ENEMY_SHOTS_t EnemyShots[ENEMY_TOTAL_SHOT_NUM];//[200]; } ENEMY_SHOT_t; ENEMY_SHOT_t EnemyShot[ENEMY_TOTAL_NUM];//[100];
/* ExternGV.h */
/* 定義 */ #define PLAYER_MAX_SHOT1 11 #define PLAYER_MAX_SHOT2 15 #define ENEMY_TOTAL_NUM 100 #define ENEMY_TOTAL_SHOT_NUM 200 #define MONSTER1_X_SIZE 140.0 #define MONSTER1_Y_SIZE 128.0 /* extern 宣言 */ extern int counter; extern int color_white; extern char Key[256]; //画像ファイルハンドル extern int img_background[2]; extern int img_player[4]; extern int img_enemy1[5]; //玉 extern int img_player_shot[2]; extern int img_enemy_shot[20]; //各種変数 extern int ShotLevel; //音声ファイルハンドル extern int sound_player_shot[2]; extern int sound_enemy_shot[2]; //構造体 //プレイヤー typedef struct{ double x,y; int status,counter; int shot [11][15]; } BODY_player_t; extern BODY_player_t Player; //敵 typedef struct{ double x,y,size; int flag,counter,hp,pattern; } BODY_enemy_t; extern BODY_enemy_t enemy[100]; //ショット typedef struct{ double x,y; int flag; } SHOT_t; extern SHOT_t PlayerShot[PLAYER_MAX_SHOT1][PLAYER_MAX_SHOT2]; typedef struct{ int flag; double x,y; } ENEMY_SHOTS_t; //敵ショット typedef struct{ int flag,pattern,counter,img; double mem_ex,mem_ey,mem_px,mem_py,Angle[ENEMY_TOTAL_SHOT_NUM];//[200]; ENEMY_SHOTS_t EnemyShots[ENEMY_TOTAL_SHOT_NUM];//[200]; } ENEMY_SHOT_t; extern ENEMY_SHOT_t EnemyShot[ENEMY_TOTAL_NUM];//[100];
/* initial.cpp */
#include "DxLib.h" #include "ExternGV.h" void initialization(){ Player.x=200.0; Player.y=400.0; Player.counter=0; Player.status=0; for(int i=0;i<PLAYER_MAX_SHOT1;i++) for(int j=0;j<PLAYER_MAX_SHOT2;j++) PlayerShot[i][j].flag=0; for(int i=0;i<ENEMY_TOTAL_NUM;i++){ enemy[i].flag=0; EnemyShot[i].flag=0; for(int j=0;j<ENEMY_TOTAL_SHOT_NUM;j++) EnemyShot[i].EnemyShots[j].flag=0; } } void SetColor(){ color_white = GetColor(255,255,255); //白色ハンドルを取得 }
/* img_sound_load.cpp */
#include "DxLib.h" #include "ExternGV.h" void img_sound_load(){ //画像ハンドル取得 img_background[0] = LoadGraph("Sh/img/back/background0.png"); img_background[1] = LoadGraph("Sh/img/back/background1.png"); img_player_shot[0] = LoadGraph("Sh/img/shot/player/1.png"); img_player_shot[1] = LoadGraph("Sh/img/shot/player/2.png"); img_enemy_shot[0] = LoadGraph("Sh/img/shot/enemy/shot1.png"); img_enemy1[0] = LoadGraph("Sh/img/mons/mons1_0.png"); img_enemy1[1] = LoadGraph("Sh/img/mons/mons1_1.png"); img_enemy1[2] = LoadGraph("Sh/img/mons/mons1_2.png"); img_enemy1[3] = LoadGraph("Sh/img/mons/mons1_3.png"); img_enemy1[4] = LoadGraph("Sh/img/mons/mons1_4.png"); LoadDivGraph( "Sh/img/char/player.png" , 4 , 4 , 1 , 32 , 48 , img_player ) ; //音楽ハンドル取得 sound_player_shot[0]= LoadSoundMem("Sh/sound/Player/shot.ogg"); sound_enemy_shot[0]= LoadSoundMem("Sh/sound/enemy/normalshot.ogg"); }
/* main.cpp */
#include "DxLib.h" #include "GlobalVariable.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ extern void img_sound_load(); extern void initialization(); extern void SetColor(); extern void Background(); extern void PlayerShotCalc(); extern void PlayerShotDisp(); extern void PlayerControl(); extern void EnemyControl(); extern void EnemyCalcDisp(); extern void EnemyShotControl(); extern void EnemyShotCalcDisp(); extern void Background2(); extern void FpsTimeFanction(); int RefreshTime=0; ChangeWindowMode( TRUE ) ; if( DxLib_Init() == -1 ) return -1; SetDrawScreen( DX_SCREEN_BACK ) ; //裏画面を使用する。 img_sound_load(); initialization(); SetColor(); while(ProcessMessage() == 0 && GetHitKeyStateAll(Key) == 0){ RefreshTime = GetNowCount(); //今の時間を取得 ClearDrawScreen(); //裏画面のデータを全て削除 Background(); PlayerShotCalc(); PlayerShotDisp(); PlayerControl(); EnemyControl(); EnemyCalcDisp(); EnemyShotControl(); EnemyShotCalcDisp(); Background2(); FpsTimeFanction(); ScreenFlip() ; //裏画面データを表画面へ反映 counter++; if(Key[KEY_INPUT_ESCAPE]==1) break; //Escapeが押されたら終了 while(GetNowCount() - RefreshTime < 17);//1周の処理が17ミリ秒になるまで待つ } DxLib_End() ; return 0 ; }
実行画面
DXライブラリ著作権表示
DX Library Copyright (C) 2001-2006 Takumi
Yamada.