シューティングゲームの館

今日 昨日


19. プレイヤーの弾と敵との当たり判定。


プレイヤーの弾と敵との当たり判定をつけるために、敵の情報にもう一つ当たり判定であるrangeを付け加えましょう。

//敵
typedef struct{
	double x,y,size;
	int flag,counter,hp,pattern,range;
} BODY_enemy_t;

こういう事ですね。enemy.cppのEnemyCalcDisp()関数で敵の情報を初期化するとき、この値も同時に初期化しましょう。

今、敵の画像はサイズがdefineで定義されています。

#define MONSTER1_X_SIZE 140.0
#define MONSTER1_Y_SIZE 128.0

横140 縦128なんですが、そのうち両サイド60ピクセルは余白または翼の部分で、あたっても当たり判定をしたくない部分です。

ですからあたり判定の範囲は

enemy[i].range=(MONSTER1_X_SIZE-60)/2.0f*enemy[i].size;

で、当たり判定の円の半径が設定できます。

実際の当たり判定の処理はplayer.cppに新しく作るCollisionDetection()関数で行います。

プレイヤーのショットは最高15個のたまが11列あるので15*11

敵が最大で100体いるので、15*11*100回比較が必要です。

しかし、表示中でないものが大半ですから、flagを用いて、表示中のもののみ比較していきましょう。

15*11*100という掛け算からも、for文が3ついることがわかりますね。

敵と、弾との距離をx,yとすると

x=(int)(PlayerShot[i][j].x-enemy[s].x);
y=(int)(PlayerShot[i][j].y-enemy[s].y);

このように計算できます。

この距離を計算するにはsqrt(x*x+y*y)で計算できます。直角三角形の斜辺の2乗は他の2辺の平方の和に等しいというピタゴラスの定理がありますね。

それを利用します。当たり判定の総合範囲は、ショットの弾の大きさの半径と、敵の大きさの半径をたしたものでおこないます。

switch(i){//iはショットの列
      case 0://0列目と
      case 5://5列目と
      case 6://6列目の
            range=12;//大きさは半径12
            break;
      default://それ以外の
            range=9;//大きさは半径9
            break;
}
  

この処理で列ごとに大きさの違う弾をrangeに仕分けします。

そうすることで

if( (int)sqrt(x*x+y*y) < range+enemy[s].range)

で当たり判定の処理が出来ますね。

では実際関数の中身をみてください。最後に消滅音を鳴らしています。

void CollisionDetection(){
        for(int i=0;i<PLAYER_MAX_SHOT1;i++){//ショットの全列分
                for(int j=0;j<PLAYER_MAX_SHOT2;j++){//1列全弾分
                        if(PlayerShot[i][j].flag==1){//その弾が発射中なら
                                for(int s=0;s<ENEMY_TOTAL_NUM;s++){//全敵100体分
                                        if(enemy[s].flag==1){//その敵のショットが出現中なら
                                                double x,y;
                                                int range;
                                                x=(int)(PlayerShot[i][j].x-enemy[s].x);
                                                y=(int)(PlayerShot[i][j].y-enemy[s].y);
                                                switch(i){//iはショットの列
                                                        case 0://0列目と
                                                        case 5://5列目と
                                                        case 6://6列目の
                                                                range=12;//大きさは半径12
                                                                break;
                                                        default://それ以外の
                                                                range=9;//大きさは半径9
                                                                break;
                                                }
                                                if( (int)sqrt(x*x+y*y) < range+enemy[s].range){//当たり判定内なら
                                                        enemy[s].flag=0;//表示フラグを戻す
                                                        PlayerShot[i][j].flag=0;//あたった弾を消す
                                                        if(CheckSoundMem(sound_enemy_death)==1)//消滅音がなっていなかったら
                                                                StopSoundMem(sound_enemy_death);//とめて
                                                        PlaySoundMem(sound_enemy_death,DX_PLAYTYPE_BACK);//消滅音をならす。
                                                        }
                                                }
                                        }
                                }
                        }
                }
        }
}

複雑にネストが深くなっていますけど行っている処理は単純な事です。

forが3つあって、その中で出現しているかどうかifで判定しているだけですから。

では全てのプログラムを表示します。

お持ちのファイルに赤い字の部分をコピーまたは上書きしてもらったらいいです。


/* player.cpp */
/* 素材 ver 1.11以上必要 */

#include "DxLib.h"
#include "ExternGV.h"
#include <math.h>

void PlayerControl(){
        if(Key[KEY_INPUT_LEFT]==1){
                Player.x-=4.0f;
                if(Player.x<10.0)
                        Player.x=10.0;
        }
        if(Key[KEY_INPUT_RIGHT]==1){
                Player.x+=4.0f;
                if(Player.x>409.0)
                        Player.x=409.0;
        }
        if(Key[KEY_INPUT_UP]){
                Player.y-=4.0f;
                if(Player.y<15.0)
                        Player.y=15.0;
        }
        if(Key[KEY_INPUT_DOWN]==1){
                Player.y+=4.0f;
                if(Player.y>465.0)
                        Player.y=465.0;
        }
        DrawGraph((int)Player.x-16,(int)Player.y-24,img_player[0],TRUE);
}

void PlayerShotCalc(){
        int i,j;
        int positionx[11]={0,-10,10,-10,10,-15,15,-10,10,-10,10},positiony[11]={-15,-2,-2,6,6,-6,-6,2,2,10,10};
        if(Key[KEY_INPUT_Z]==1 && counter%5==0){
                for(i=0;i<ShotLevel;i++){
                        for(j=0;j<PLAYER_MAX_SHOT2;j++){
                                if(PlayerShot[i][j].flag==0){
                                        PlayerShot[i][j].flag=1;
                                        PlayerShot[i][j].x=Player.x+(double)positionx[i];
                                        PlayerShot[i][j].y=Player.y+(double)positiony[i];
                                        if(CheckSoundMem(sound_player_shot[0])==0)
                                                PlaySoundMem(sound_player_shot[0],DX_PLAYTYPE_BACK);
                                        break;
                                }
                        }
                }
        }

        int sab[11]={0,-1,1,-3,3,0,0,-2,2,-5,5};
        for(i=0;i<PLAYER_MAX_SHOT1;i++){
                for(j=0;j<PLAYER_MAX_SHOT2;j++){
                        if(PlayerShot[i][j].flag==1){
                                PlayerShot[i][j].x+=(double)sab[i];
                                PlayerShot[i][j].y-=10.0;
                                if(PlayerShot[i][j].y<-20)
                                        PlayerShot[i][j].flag=0;
                        }
                }
        }
}

void PlayerShotDisp(){
        int i,j;
        for(i=0;i<PLAYER_MAX_SHOT1;i++){
                for(j=0;j<PLAYER_MAX_SHOT2;j++){
                        if(PlayerShot[i][j].flag==1){
                                switch(i){
                                        case 0:
                                        case 5:
                                        case 6:
                                                DrawGraph((int)PlayerShot[i][j].x-10,(int)PlayerShot[i][j].y-18,img_player_shot[0],TRUE);
                                                break;
                                        default:
                                                DrawGraph((int)PlayerShot[i][j].x-8,(int)PlayerShot[i][j].y-10,img_player_shot[1],TRUE);
                                                break;
                                }
                        }
                }
        }
}

void CollisionDetection(){
        for(int i=0;i<PLAYER_MAX_SHOT1;i++){//ショットの全列分
                for(int j=0;j<PLAYER_MAX_SHOT2;j++){//1列全弾分
                        if(PlayerShot[i][j].flag==1){//その弾が発射中なら
                                for(int s=0;s<ENEMY_TOTAL_NUM;s++){//全敵100体分
                                        if(enemy[s].flag==1){//その敵のショットが出現中なら
                                                double x,y;
                                                int range;
                                                x=(int)(PlayerShot[i][j].x-enemy[s].x);
                                                y=(int)(PlayerShot[i][j].y-enemy[s].y);
                                                switch(i){
                                                        case 0:
                                                        case 5:
                                                        case 6:
                                                                range=12;
                                                                break;
                                                        default:
                                                                range=9;
                                                                break;
                                                }
                                                if( (int)sqrt(x*x+y*y) < range+enemy[s].range){
                                                        enemy[s].flag=0;
							PlayerShot[i][j].flag=0;
                                                        if(CheckSoundMem(sound_enemy_death)==1)
                                                                StopSoundMem(sound_enemy_death);
                            PlaySoundMem(sound_enemy_death,DX_PLAYTYPE_BACK);
                                                }
                                        }
                                }
                        }
                }
        }
}


/* 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(){
        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){
                case 50:
                        enemy[i].pattern=2; //どういう軌道を描くか
                        enemy[i].flag=1;   //出現フラグを立てる
                        enemy[i].counter=0;//出現して何カウント目か測るカウンター初期化
                        enemy[i].size=0.5f;//敵の大きさ
                        enemy[i].range=(MONSTER1_X_SIZE-60)/2.0f*enemy[i].size;//あたり判定範囲
                        enemy[i].x=100;  //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;
                }
        }
}


/* 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");
        sound_enemy_death       = LoadSoundMem("Sh/sound/enemy/death.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 CollisionDetection();
        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();
                
                CollisionDetection();
                
                Background2();

                FpsTimeFanction();

                ScreenFlip() ;                                            //裏画面データを表画面へ反映

                counter++;

                if(Key[KEY_INPUT_ESCAPE]==1)    break;  //Escapeが押されたら終了
                while(GetNowCount() - RefreshTime < 17);//1周の処理が17ミリ秒になるまで待つ
        }
                
        DxLib_End() ;
        return 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];
int sound_enemy_death;

//構造体
//プレイヤー
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,range;
} 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];
extern int sound_enemy_death;

//構造体
//プレイヤー
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,range;
} 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];

実行画面


戻る                                  次へ
メニューへ戻る


トップページへ

DXライブラリ著作権表示
DX Library Copyright (C) 2001-2006 Takumi Yamada.