・敵画像の差し替え
・敵弾画像の差し替え(handleも追加)
・ゲームオーバーを文字から画像に差し替え
・爆発が収まるまでゲームオーバーを表示しないように調整
・ゲームオーバーになったら敵を再生成しない
・ゲームオーバー時に”s”を押下で再プレイ
(再プレイ可能にするために、各フラグやパラメーターを初期化する)
・・・上記を実装。
【今日のコード】
#include<DxLib.h>
#include<stdlib.h>
#include<time.h>
//------------------------------------
//定数定義
//------------------------------------
const int SCREEN_W = 1024;
const int SCREEN_H = 880;
const int BG_H = 1024;
const int BG_SCROLL_SPEED = 8;
const int CENTER_X = (SCREEN_W / 2);
const int CENTER_Y = (SCREEN_H / 2);
const int PLAYER_DEL_PERIOD = (30);//プレイヤーが消えている時間
const int PLAYER_MAX = (5);
const int PLAYER_W = 128; //プレイヤーの横幅
const int PLAYER_H = 141; //プレイヤーの高さ
const int PLAYER_R = (PLAYER_W / 2);//プレイヤーの半径
const int PLAYER_SPEED = 4;//プレイヤー移動速度
const int PLAYER_INTERVAL_TIME = 120;//プレイヤーが次弾発射可能になるまでのフレーム数
const int PLAYER_BULLET_SPEED = 8;//プレイヤー弾速度
const int BULLET_W = 16;//弾の横幅
const int BULLET_H = 16;//弾の縦幅
const int SHOT_R = BULLET_W / 2;//弾の半径
const int ENEMY_W = 300;
const int ENEMY_H = 346;
const int ENEMY_R = ENEMY_H / 2;
const int ENEMY_SHOT_R = BULLET_W / 2;//敵の弾の半径
const int ENEMY_BULLET_SPEED = 8;//敵弾のスピード
const int ENEMY_EMERGE_TIME = 40;//敵再出現までの時間
const int ENEMY_SHOT_INTERVAL_TIME = 20;//敵の次弾発射可能になるまでのフレーム数
const int FIRE_PERIOD = (15);//爆発アニメの1コマの時間(フレーム)
const int GAME_START_PERIOD = (60);//GAME START表示時間
const int PLAYER_REST_NUM_DX = SCREEN_W - ((PLAYER_W / 5) * PLAYER_MAX);
const int PLAYER_REST_NUM_DY = SCREEN_H - PLAYER_H;
const int GAMEOVER_W = 800;
const int GAMEOVER_H = 154;
const int GAMEOVER_TIME = 60;//ゲームオーバーフラグをtrueにするまでの時間
//------------------------------------
//変数定義
//------------------------------------
//画像のハンドル
int handle;//プレイヤー画像のハンドル番号を格納する変数
int handlePShot;//プレイヤー弾のハンドル
int handleEShot;//敵弾のハンドル
int handleEnemy;//敵画像のハンドル
int handleBg;//背景のハンドル
int handleBlast0;//爆発アニメ1コマ目のハンドル
int handleBlast1;//爆発アニメ1コマ目のハンドル
int handleBlast2;//爆発アニメ1コマ目のハンドル
int handleGameOver;//ゲームオーバー画像のハンドル
bool playerFlag; //自機の表示フラグ
bool shotFlag, shotFlag1, shotFlag2, shotFlag3;//自機の弾のフラグ
int playerX;//プレイヤーの表示座標X(座標の管理は画像の中心位置とする)
int playerY;//プレイヤーの表示座標Y(座標の管理は画像の中心位置とする)
int playerTimer = 0;
int life;//プレイヤーの保有機数
int scrollX;//背景画像の表示開始X座標
int scrollY;//背景画像の表示開始Y座標
int shotX, shotY;//プレイヤー弾1の表示X、Y座標(座標の管理は画像の中心位置とする)
int shotX1, shotY1;//プレイヤー弾1の表示X、Y座標(座標の管理は画像の中心位置とする)
int shotX2, shotY2;//プレイヤー弾2の表示X、Y座標(座標の管理は画像の中心位置とする)
int shotTimer;
bool enemyFlag, enemyStatus;//敵出現フラグ、敵状態フラグ
int enemyX, enemyY;//敵表示のX,Y座標(座標の管理は画像の中心位置とする)
int enemyTimer;//敵再出現用タイマー
int enemyVX, enemyVY; //敵移動用変数X,Y
bool enemyShotFlag = false;
int enemyShotX, enemyShotY, enemyShotTimer;//敵弾X,Y座標、再発射タイマー
int gameTimer = 0;//ゲームスタート画面が消えるまでのカウンター
int n = 0;//プレイヤーライフ表示用変数
bool fire_flag = false;//爆発アニメを表示するフラグ
int fire_x;//爆発位置のX座標
int fire_y;//爆発位置のY座標
int fire_pat_index;//何枚目の絵を表示中?
int fire_pat_timer;//アニメーションのタイマー
bool gameOverFlg;
int gameOverCounter;
// プロトタイプ宣言
bool CollisionCheck(int x1, int y1, int r1, int x2, int y2, int r2);//衝突チェック
void AnimeSet(int x, int y);//爆発アニメーションをセット
void AnimeDsp();//爆発アニメーション表示
void DrawGraphCenter(int x, int y, int handle, bool flag);
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
SetMainWindowText("BlackPiyo VS Mike");//ゲームウインドウのタイトル
ChangeWindowMode(TRUE); // ウィンドウモード(false = フルスクリーン)
SetGraphMode(SCREEN_W, SCREEN_H, 32);//ゲームウインドウのサイズと色モード設定
SetAlwaysRunFlag(TRUE);
if (DxLib_Init() == -1) {
return -1; // DXライブラリ初期化失敗の為システム終了
}
// 最前面に持ってくる処理
HWND hwnd = GetMainWindowHandle();
SetForegroundWindow(hwnd);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
//--------------------------------
//グラフィックの読み込み
//--------------------------------
//プレイヤー画像の読み込み
handle = LoadGraph("chara/blackpiyo-s.png");
if (handle == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//プレイヤー弾画像の読み込み
handlePShot = LoadGraph("chara/egg.png");
if (handlePShot == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//敵弾画像の読み込み
handleEShot = LoadGraph("chara/egg.png");
if (handleEShot == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//敵画像の読み込み
handleEnemy = LoadGraph("chara/mike.png");
if (handleEnemy == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//背景画像の読み込み
handleBg = LoadGraph("bg.png");
if (handleBg == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//爆発画像0の読み込み
handleBlast0 = LoadGraph("effect/bakuhatsu0.png");
if (handleBlast0 == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//爆発画像1の読み込み
handleBlast1 = LoadGraph("effect/bakuhatsu1.png");
if (handleBlast1 == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//爆発画像2の読み込み
handleBlast2 = LoadGraph("effect/bakuhatsu2.png");
if (handleBlast2 == -1) {
return -1; //画像読み込みに失敗したのでエラー終了
}
//ゲームオーバー画像の読み込み
handleGameOver = LoadGraph("img/GameOver.png");
if (handleGameOver == -1) {
return -1;
}
//---------------------------------------
// 変数の初期化
//---------------------------------------
//背景画像の表示開始座標
scrollX = 0;
scrollY = 0 - (BG_H - SCREEN_H);
//player
life = PLAYER_MAX;
playerX = CENTER_X;
playerY = SCREEN_H - (PLAYER_H / 2) - 1;
playerFlag = true;
playerTimer = 0;
//player弾
shotX = 0;
shotY = 0;
shotFlag = false;
shotX1 = 0;
shotY1 = 0;
shotFlag1 = false;
shotX2 = 0;
shotY2 = 0;
shotFlag2 = false;
//enemy
enemyX = CENTER_X;
enemyY = ENEMY_H / 2;
enemyVX = 0;
enemyVY = 1;
enemyFlag = true;
enemyTimer = 0;
enemyStatus = 0;
//敵弾
enemyShotX = 0;
enemyShotY = 0;
enemyShotFlag = false;
enemyShotTimer = 0;
gameTimer = 0; //ゲームスタート表示が消えるまでの時間カウンター
//爆発
// 爆発
fire_x = 0;
fire_y = 0;
fire_flag = false;
fire_pat_index = 0;
fire_pat_timer = 0;
//ゲームオーバー関連
gameOverFlg = false;
gameOverCounter = 0;
srand((unsigned)time(NULL) * 123);//乱数の初期値を時間を種にしてセット
//------------------------------------------
//ゲームループ
//-------------------------------------
while (ProcessMessage() == 0) {
//背景スクロール処理
scrollY += BG_SCROLL_SPEED;
if (scrollY > BG_H)
{
scrollY = 0;
}
if (gameOverFlg == true) {
if (CheckHitKey(KEY_INPUT_S) == 1) {
//プレイヤー関連
playerX = SCREEN_W / 2;
playerY = SCREEN_H - (PLAYER_H / 2) - 1;
playerFlag = true;
playerTimer = 0;
life = PLAYER_MAX;
//ショット関連
shotFlag = false;
shotFlag1 = false;
shotFlag2 = false;
shotFlag3 = false;
enemyShotFlag = false;
//敵
enemyFlag = true;
enemyTimer = 0;
//爆発
fire_flag = false;
fire_pat_index = 0;
fire_pat_timer = 0;
//ゲームオーバー関連
gameOverFlg = false;
gameOverCounter = 0;
;
continue;
}
}
//ゲームオーバー
if (life <= 0 && fire_flag == false) {
//保有機数がなくなり、爆発も収まっているのでゲームオーバーを表示するまでの間をカウントする
if (gameOverCounter < GAMEOVER_TIME) {
gameOverCounter++;
if (gameOverCounter >= GAMEOVER_TIME) {
gameOverFlg = true;
}
}
}
//playerを動かす処理
if (CheckHitKey(KEY_INPUT_RIGHT) == 1)
{
playerX += PLAYER_SPEED;
}
if (CheckHitKey(KEY_INPUT_LEFT) == 1)
{
playerX -= PLAYER_SPEED;
}
if (CheckHitKey(KEY_INPUT_DOWN) == 1)
{
playerY += PLAYER_SPEED;
}
if (CheckHitKey(KEY_INPUT_UP) == 1)
{
playerY -= PLAYER_SPEED;
}
//プレイヤー弾発射
if (playerFlag == true && shotTimer <= 0) {
if (CheckHitKey(KEY_INPUT_SPACE) == 1) {
if (shotFlag == false)
{
shotX = playerX;
shotY = playerY;
shotFlag = true;
shotTimer = PLAYER_INTERVAL_TIME;
}
else if (shotFlag1 == false)
{
shotX1 = playerX;
shotY1 = playerY;
shotFlag1 = true;
shotTimer = PLAYER_INTERVAL_TIME;
}
else if (shotFlag2 == false)
{
shotX2 = playerX;
shotY2 = playerY;
shotFlag2 = true;
shotTimer = PLAYER_INTERVAL_TIME;
}
}
}
//プレイヤーの字次弾発射可能時間のカウントダウン
if (shotTimer > 0)
{
shotTimer--;
}
if (shotFlag == 1)
{
shotY -= PLAYER_BULLET_SPEED;
if (shotY < 0)
{
shotFlag = 0;
}
}
if (shotFlag1 == 1)
{
shotY1 -= PLAYER_BULLET_SPEED;
if (shotY1 < 0)
{
shotFlag1 = 0;
}
}
if (shotFlag2 == 1)
{
shotY2 -= PLAYER_BULLET_SPEED;
if (shotY2 < 0)
{
shotFlag2 = 0;
}
}
//プレーヤーの移動制限
if (playerX > SCREEN_W - PLAYER_W / 2)playerX = SCREEN_W - PLAYER_W / 2;
if (playerX < PLAYER_W / 2)playerX = PLAYER_W / 2;
if (playerY > SCREEN_H - PLAYER_H / 2)playerY = SCREEN_H - PLAYER_H / 2;
if (playerY < PLAYER_H / 2)playerY = PLAYER_H / 2;
//敵弾の処理
if (enemyShotFlag == true) {
//敵弾が表示中に移動させる
enemyShotY += ENEMY_BULLET_SPEED;
if (enemyShotY >= SCREEN_H) {
//ウインドウ外に出たら非表示に
enemyShotFlag = 0;
}
}
else {
if (enemyShotTimer++ > ENEMY_SHOT_INTERVAL_TIME) {
enemyShotTimer = 0;
if (enemyFlag == true) {
enemyShotFlag = true;
enemyShotX = enemyX;
enemyShotY = enemyY;
}
}
}
//敵の移動処理
if (enemyFlag == 1) {
//敵が表示中なので移動させる
enemyX += enemyVX; // X方向の移動
enemyY += enemyVY; // Y方向の移動
if (enemyStatus) {
enemyVY = -enemyVY;
}
// 範囲外判定:敵が画面外に出たらフラグをオフにし再出現を準備
if (enemyX < - ENEMY_W || (enemyX - ENEMY_W) > SCREEN_W) {
enemyFlag = 0;
enemyTimer = ENEMY_EMERGE_TIME;
}
if (enemyY < - ENEMY_H || (enemyY - ENEMY_H ) > SCREEN_H) {
enemyFlag = 0;
enemyTimer = ENEMY_EMERGE_TIME;
}
}
else {
// 敵の再出現処理
if (life > 0) {
if (enemyTimer-- < 0) {
enemyFlag = true;
enemyX = rand() % SCREEN_W;
enemyY = -100;
enemyVX = rand() % 5 - 1; // -1~1のランダム速度
enemyVY = rand() % 5 - 2; // -2~2のランダム速度
enemyTimer = ENEMY_EMERGE_TIME;
}
}
}
//衝突判定(コリジョンチェック)
if (shotFlag == true && enemyFlag == true)
{
//プレイヤー弾1と敵ともに存在しているので衝突判定を行う
if (CollisionCheck(shotX, shotY, SHOT_R, enemyX, enemyY, ENEMY_R))
{
enemyFlag = 0;
shotFlag = 0;
AnimeSet(enemyX, enemyY);//爆発セット
enemyTimer = (rand() % 100);
enemyX = (rand() % 360);
}
}
if (shotFlag1 == 1 && enemyFlag == 1)
{
//プレイヤー弾1と敵ともに存在しているので衝突判定を行う
if (CollisionCheck(shotX1, shotY1, SHOT_R, enemyX, enemyY, ENEMY_R))
{
enemyFlag = 0;
shotFlag1 = 0;
AnimeSet(enemyX, enemyY);//爆発セット
enemyTimer = (rand() % 100);
enemyX = (rand() % 360);
}
}
if (shotFlag2 == 1 && enemyFlag == 1)
{
//プレイヤー弾1と敵ともに存在しているので衝突判定を行う
if (CollisionCheck(shotX2, shotY2, SHOT_R, enemyX, enemyY, ENEMY_R))
{
enemyFlag = 0;
shotFlag2 = 0;
AnimeSet(enemyX, enemyY);//爆発セット
enemyTimer = (rand() % 100);
enemyX = (rand() % 360);
}
}
if (playerFlag == true && enemyFlag == true) {
if (CollisionCheck(playerX, playerY, PLAYER_R, enemyX, enemyY, ENEMY_R))
//プレイヤーと敵ともに存在しているので衝突判定を行う
{
playerFlag = false; //プレイヤー消滅
enemyFlag = false; //敵消滅
AnimeSet(playerX, playerY);//爆発セット
}
//プレイヤーが一定時間消えた後、復活する
}
if (playerFlag == true && enemyShotFlag == true) {
if (CollisionCheck(playerX, playerY, PLAYER_R, enemyShotX, enemyShotY, ENEMY_SHOT_R)) {
playerFlag = false;//プレイヤー消滅
enemyFlag = false;//敵消滅
AnimeSet(playerX, playerY);//爆発セット
}
}
if ((playerFlag == false) && (life >= 0))
{
if (playerTimer++ > PLAYER_DEL_PERIOD) {
playerX = CENTER_X;//ウインドウ横中央
playerY = SCREEN_H - (PLAYER_H / 2) - 1;//ウインドウ最下部
playerFlag = TRUE;
playerTimer = 0;
life--;
}
}
if (life <= 0) playerFlag = false;
//描画処理
SetDrawScreen(DX_SCREEN_BACK); // 裏画面に描画
ClearDrawScreen();
DrawGraph(0, scrollY, handleBg, true);
DrawGraph(0, scrollY - BG_H, handleBg, true);
//残機表示
for (int ii = 0; ii < life - 1; ii++) {
int dx = PLAYER_REST_NUM_DX + ((PLAYER_W / 5) * ii);
int dy = PLAYER_REST_NUM_DY;
DrawRotaGraph(dx, dy, 0.2, 0.0, handle, true, false);
}
DrawGraphCenter(playerX, playerY, handle, playerFlag == true);
DrawGraphCenter(shotX, shotY, handlePShot, shotFlag == true);
DrawGraphCenter(shotX1, shotY1, handlePShot, shotFlag1 == true);
DrawGraphCenter(shotX2, shotY2, handlePShot, shotFlag2 == true);
DrawGraphCenter(enemyX, enemyY, handleEnemy, TRUE);
DrawGraphCenter(enemyShotX, enemyShotY, handleEShot, enemyShotFlag == true);
//爆発処理
AnimeDsp();
//ゲームオーバー表示
if (gameOverFlg == true){
int dx = (SCREEN_W - GAMEOVER_W) / 2;
int dy = (SCREEN_H - GAMEOVER_H) / 2;
DrawGraph(dx, dy, handleGameOver, true);
}
//ゲームスタート表示
if (gameTimer++ < GAME_START_PERIOD)
{
DrawString(CENTER_X - 70, CENTER_Y, "GAME START", GetColor(255, 255, 255));
}
ScreenFlip();
}
// システム終了処理
//--------------------------
// 画像データの破棄
//--------------------------
// プレイヤー画像の破棄
DeleteGraph(handle);
// 背景画像の破棄
DeleteGraph(handleBg);
// 弾画像の破棄
DeleteGraph(handlePShot);
DeleteGraph(handleEShot);
// 敵画像の破棄
DeleteGraph(handleEnemy);
// 爆発画像3パターンの破棄
DeleteGraph(handleBlast0);
DeleteGraph(handleBlast1);
DeleteGraph(handleBlast2);
//GameOver画像の破棄
DeleteGraph(handleGameOver);
DxLib_End();
return 0;
}
//画像の中心位置基準で表示
//input x, y 表示位置座標
//handle 画像ID
//flag 表示/非表示
void DrawGraphCenter(int playerX, int playerY, int handle, bool flag)
{
int width, height;
if (flag)
{
GetGraphSize(handle, &width, &height);
DrawGraph(playerX - (width / 2), playerY - (height / 2), handle, TRUE);
}
}
//衝突チェック
//input x1, y1 キャラ#1 X,Y位置
// r2 キャラ#1 半径
// x2, y2 キャラ#2 X,Y位置
// r2 キャラ#2 半径
//output flag 当たった/当たってない
bool CollisionCheck(int x1, int y1, int r1, int x2, int y2, int r2) {
int dx = x1 - x2;
int dy = y1 - y2;
int dist = dx * dx + dy * dy;
int radius = r1 + r2;
if (dist <= radius * radius) {
return true;//当たっている
}
return false;//当たっていない
}
void AnimeSet(int x, int y) {
if (!fire_flag) {
fire_flag = true;
fire_pat_timer = 0;
fire_pat_index = 0;
fire_x = x;
fire_y = y;
}
}
void AnimeDsp() {
if (fire_flag) {
if (fire_pat_timer++ > FIRE_PERIOD) {
fire_pat_timer = 0;
fire_pat_index++;
}
if (fire_pat_index == 0) {
DrawGraphCenter(fire_x, fire_y, handleBlast0, true); //1コマ目
}
else if (fire_pat_index == 1) {
DrawGraphCenter(fire_x, fire_y, handleBlast1, true);//2コマ目
}
else if (fire_pat_index == 2) {
DrawGraphCenter(fire_x, fire_y, handleBlast2, true);//3コマ目
}
else {
fire_pat_index = 0;
fire_flag = false;
}
}
}
ゲームオーバー後にプレイヤー操作もできていたので、if (life <= 0) playerFlag = false;を追加した。
コメント