8. ショットをうつ。
今回はそれぞれのファイルの変更点が多いので、一つ一つみていきましょう。
まず、グローバル宣言のヘッダに、定義と、画像ハンドル変数と弾の構造体を追加します。
弾のかずは、縦いっぱいで15個、それが11列飛ぶものとします。
(写真では縦方向に10行しか発射されていませんが、余裕を持って1列あたり15個用意します。)
一度に11列ショットをうつので
#define PLAYER_MAX_SHOT1 11
1列には最大で15個の弾を使用するので
#define PLAYER_MAX_SHOT2 15
このように定義します。
いきなり全部作るのは大変なので、今の節では、中心の一列だけ、
作ってみます。
弾の画像のハンドルを格納する変数を用意します。
弾の画像は2種類あるので配列で宣言します。
int img_player_shot[2];
次に弾の情報を格納する構造体を宣言します。
構造体には座標であるx,yの他に、弾が今発射されている状態か(1)発射されていない状態か(0)を格納するflagを用意します。
この構造をもった変数を2次元配列で、弾の数だけ用意します。
typedef struct{
double x,y;
int flag;
} SHOT_t;
11列、各15個ですから
SHOT_t PlayerShot[PLAYER_MAX_SHOT1][PLAYER_MAX_SHOT2];
こうなります。
/* GlobalVariable.h*/
/* 素材 ver1.00以上必要*/
/* 定義 */ #define PLAYER_MAX_SHOT1 11 #define PLAYER_MAX_SHOT2 15 /* グローバル宣言 */ int counter=0; int color_white; char Key[256]; //画像ファイルハンドル int img_background[2]; int img_player[4]; //弾の画像 int img_player_shot[2]; //構造体 typedef struct{ double x,y; int status,counter; } BODY_player_t; BODY_player_t Player; typedef struct{ double x,y; int flag; } SHOT_t; SHOT_t PlayerShot[PLAYER_MAX_SHOT1][PLAYER_MAX_SHOT2];
グローバル宣言にともない、extern宣言情報を格納するExternGV.hも変更します。
/* ExternGV.h */
/* 素材 ver1.00以上必要*/
/* 定義 */ #define PLAYER_MAX_SHOT1 11 #define PLAYER_MAX_SHOT2 15 /* 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_player_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; int flag; } SHOT_t; extern SHOT_t PlayerShot[PLAYER_MAX_SHOT1][PLAYER_MAX_SHOT2];
実際にプレイヤーから発射する弾の計算と描画はplayer.cppファイルで行います。
ショットの計算を行うPlayerShotDisp関数と描画を行うPlayerShotDisp関数を作ります。
下のサンプルを見てください。
まず、
PlayerShotDisp関数内の処理から説明します。
if(Key[KEY_INPUT_Z]==1 && counter%5==0){
for(j=0;j<PLAYER_MAX_SHOT2;j++){
if(PlayerShot[0][j].flag==0){
PlayerShot[0][j].flag=1;
PlayerShot[0][j].x=Player.x;
PlayerShot[0][j].y=Player.y;
break;
}
}
}
最初のif文は「Zキーが押されているとき かつ 処理が5周に1回行う」処理で、
縦方向に表示する最大数のショットまでflagを調べていきます。
表示できるショットは最大でPLAYER_MAX_SHOT2つまり15個で、
flagはその弾が発射しているか発射していないかを表します。
1なら発射している。 0なら発射していない。
for文でjをまわしながら
if(PlayerShot[0][j].flag==0){
を行うことで、[0]配列の弾で、発射していないものを探すことが出来ます。
今回は1列しか発射させないので[0]しか使いません。最終的に11列発射させるようにします。
if文の条件にマッチした弾は使用可能であるので、
弾の座標を初期化し、弾のフラグを発射中にします。
次に
for(j=0;j<PLAYER_MAX_SHOT2;j++){
if(PlayerShot[0][j].flag==1){
PlayerShot[0][j].y-=10;
if(PlayerShot[0][j].y<-20)
PlayerShot[0][j].flag=0;
}
}
ここでは、発射中の弾を探し、座標を上に10シフトします。
もし画面外に出たら、発射フラグを0に戻します。
PlayShotDisp関数の中身の説明をします。
for(j=0;j<PLAYER_MAX_SHOT2;j++){
if(PlayerShot[0][j].flag==1){
DrawGraph(PlayerShot[0][j].x-10,PlayerShot[0][j].y-18,img_player_shot[0],TRUE);
}
}
この処理は単に、発射フラグのたっている弾を描画しているだけです。座標は画像サイズが20x36のものを使っているので
x座標に-10, y座標に-18する必要があります。
/* player.cpp*/
/* 素材 ver1.00以上必要*/
#include "DxLib.h" #include "ExternGV.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; if(Key[KEY_INPUT_Z]==1 && counter%5==0){ for(j=0;j<PLAYER_MAX_SHOT2;j++){ if(PlayerShot[0][j].flag==0){ PlayerShot[0][j].flag=1; PlayerShot[0][j].x=Player.x; PlayerShot[0][j].y=Player.y; break; } } } for(j=0;j<PLAYER_MAX_SHOT2;j++){ if(PlayerShot[0][j].flag==1){ PlayerShot[0][j].y-=10; if(PlayerShot[0][j].y<-20) PlayerShot[0][j].flag=0; } } } void PlayerShotDisp(){ int i,j; for(j=0;j<PLAYER_MAX_SHOT2;j++){ if(PlayerShot[0][j].flag==1){ DrawGraph(PlayerShot[0][j].x-10,PlayerShot[0][j].y-18,img_player_shot[0],TRUE); } } }
今回表示する画像を増やしたので、その画像を読み込みます。
/* img_sound_load.cpp*/
/* 素材 ver1.00以上必要*/
#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"); LoadDivGraph( "Sh/img/char/player.png" , 4 , 4 , 1 , 32 , 48 , img_player ) ; }
今回、弾の発射フラグを作ったので初めは全部0である必要があります。そこで、初期化を行います。
/* initial.cpp*/
/* 素材 ver1.00以上必要*/
#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; } void SetColor(){ color_white = GetColor(255,255,255); //白色ハンドルを取得 }
main関数から作った関数を呼び出します。
/* main.cpp */
/* 素材 ver1.00以上必要*/
#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 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(); 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.