


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.