今回の目標
・HitCheck()関数で当たり判定を関数化:済
・爆発をアニメーションで表現 ← ここから
・敵が弾を撃ったら逃げる行動に変化
・弾と敵を配列で複数化
爆発画像のhandleを定義
int handleBlast0 = LoadGraph("effect/bakuhatsu0.png");
int handleBlast1 = LoadGraph("effect/bakuhatsu1.png");
int handleBlast2 = LoadGraph("effect/bakuhatsu2.png");
爆発画像のセット・表示切替関数の追加
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;
}
}
※”!”(論理否定:NOT)について
C言語では ! は論理否定(NOT)を表します。例えば、!true は false になり、!false は true になります。
また、具体的な使用例として:
#include <stdio.h>
int main() {
int a = 0;
if (!a) {
printf("a は 0 なので、この条件は真(true)です。\n");
}
return 0;
}
このコードでは a が 0 の場合、!a は true になり、if (!a) の条件が成立します。
他に気になることがあれば、遠慮なく聞いてくださいね!
(by Copilot)
なお、AnimeDsp()は、毎フレーム実行する必要があるため、描画処理部分に記述する。
上記を踏まえて
【今日のコード①】
#include<stdlib.h>
#include<time.h>
#include<DxLib.h>
#define SCREEN_W 480
#define SCREEN_H 880
#define CENTER_X (SCREEN_W / 2)
#define CENTER_Y (SCREEN_H / 2)
#define DISTANCE_R (250*250) //距離の二乗
#define PLAYER_DEL_PERIOD (30)
#define PLAYER_MAX (1)
#define GAME_START_PERIOD (60)//GAME START表示時間
#define PLAYER_W 128 //プレイヤーの横幅
#define PLAYER_H 141 //プレイヤーの高さ
#define PLAYER_R (PLAYER_W/2)//プレイヤーの半径
#define SHOT_R (5)//弾の半径
#define ENEMY_R (250)
#define ENEMY_SHOT_R (5)
#define FIRE_PERIOD (15)//爆発アニメの1コマの時間(フレーム)
bool playerFlag = true; //自機の表示フラグ
int playerX = CENTER_X;
int playerY = CENTER_Y;
int scrollY = 0;
int shotX = 0, shotY = 0, shotFlag = 0;
int shotX2 = 0, shotY2 = 0, shotFlag2 = 0;
int shotX3 = 0, shotY3 = 0, shotFlag3 = 0;// shotFlag…0:表示しない 1:表示
int shotTimer = 0;
int enemyFlag = 1, enemyX = 0, enemyY = 100, enemyTimer = 0, enemyVX = 0, enemyVY = 1; //enemy画像の幅の半分をずらして、真ん中付近に表示
int playerTimer = 0;
int playerLife;
int gameTimer = 0;
int n = 0;
bool fire_flag = false;//爆発アニメを表示するフラグ
int fire_x;
int fire_y;
int fire_pat_index = 0;//何枚目の絵を表示中?
int fire_pat_timer = 0;//アニメーションのタイマー
int handle;
int handleShot;
int handleEnemy;
int handleBg;
int handleBlast0;
int handleBlast1;
int handleBlast2;
// プロトタイプ宣言
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) {
ChangeWindowMode(TRUE); // ウィンドウモード
SetGraphMode(SCREEN_W, SCREEN_H, 32);
DxLib_Init(); // DXライブラリ初期化
SetMainWindowText("BlackPiyo VS Mike");
handleShot = LoadGraph("chara/egg.png");
handleEnemy = LoadGraph("chara/mike.png");
handleBg = LoadGraph("bg.png");
handle = LoadGraph("chara/blackpiyo-s.png");
handleBlast0 = LoadGraph("effect/bakuhatsu0.png");
handleBlast1 = LoadGraph("effect/bakuhatsu1.png");
handleBlast2 = LoadGraph("effect/bakuhatsu2.png");
srand((unsigned)time(NULL) * 123);
playerLife = PLAYER_MAX;
while (ProcessMessage() == 0) {
SetDrawScreen(DX_SCREEN_BACK); // 裏画面に描画
ClearDrawScreen();
//playerを動かす処理
if (CheckHitKey(KEY_INPUT_RIGHT))
{
playerX += 2;
}
if (CheckHitKey(KEY_INPUT_LEFT))
{
playerX -= 2;
}
if (CheckHitKey(KEY_INPUT_DOWN))
{
playerY += 2;
}
if (CheckHitKey(KEY_INPUT_UP))
{
playerY -= 2;
}
if (CheckHitKey(KEY_INPUT_SPACE) && (shotTimer == 0))
{
if (shotFlag == 0)
{
shotX = playerX;
shotY = playerY;
shotFlag = 1;
shotTimer = 20;
}
else if (shotFlag2 == 0)
{
shotX2 = playerX;
shotY2 = playerY;
shotFlag2 = 1;
shotTimer = 20;
}
else if (shotFlag3 == 0)
{
shotX3 = playerX;
shotY3 = playerY;
shotFlag3 = 1;
shotTimer = 20;
}
}
//プレーヤーの移動制限
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 (shotTimer > 0)
{
shotTimer--;
}
int dx = 0;
if (shotFlag == 1 && enemyFlag == 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 (shotFlag2 == 1 && enemyFlag == 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 (shotFlag3 == 1 && enemyFlag == 1)
{
if (CollisionCheck(shotX3, shotY3, SHOT_R, enemyX, enemyY, ENEMY_R))
{
enemyFlag = 0;
shotFlag3 = 0;
AnimeSet(enemyX, enemyY);//爆発セット
enemyTimer = (rand() % 100);
enemyX = (rand() % 360);
}
}
scrollY += 8;
if (scrollY > SCREEN_H)
{
scrollY = 0;
}
if (shotFlag == 1)
{
shotY -= 4;
if (shotY < 0)
{
shotFlag = 0;
}
}
if (shotFlag2 == 1)
{
shotY2 -= 4;
if (shotY2 < 0)
{
shotFlag2 = 0;
}
}
if (shotFlag3 == 1)
{
shotY3 -= 4;
if (shotY3 < 0)
{
shotFlag3 = 0;
}
}
//敵の移動処理
if (enemyFlag == 1) {
enemyX += enemyVX; // X方向の移動
enemyY += enemyVY; // Y方向の移動
if (CollisionCheck(playerX,playerY,PLAYER_R,enemyX,enemyY,ENEMY_R))
{
playerFlag = FALSE; //プレイヤー消滅
enemyFlag = FALSE; //敵消滅
AnimeSet(playerX, playerY);//爆発セット
}
//プレイヤーが一定時間消えた後、復活する
if ((playerFlag == false) && (playerLife >= 0) )
{
if (playerTimer++ > PLAYER_DEL_PERIOD) {
playerFlag = TRUE;
playerTimer = 0;
playerLife--;
}
}
// 範囲外判定:敵が画面外に出たらフラグをオフにし再出現を準備
if (enemyX < -300 || enemyX -300 > SCREEN_W) {
enemyFlag = 0;
enemyTimer = 40;
}
if (enemyY < -300 || enemyY -300 > SCREEN_H) {
enemyFlag = 0;
enemyTimer = 40;
}
}
else {
// 敵の再出現処理
if (enemyTimer-- < 0) {
enemyFlag = 1;
enemyX = rand() % SCREEN_W;
enemyY = -300;
enemyVX = rand() % 5 - 1; // -1~1のランダム速度
enemyVY = rand() % 5 - 2; // -2~2のランダム速度
enemyTimer = 50;
}
}
DrawGraph(0, scrollY, handleBg, TRUE);
DrawGraph(0, scrollY - SCREEN_H, handleBg, TRUE);
DrawGraphCenter(playerX, playerY, handle, playerFlag);
DrawGraphCenter(shotX, shotY, handleShot, shotFlag == 1);
DrawGraphCenter(shotX2, shotY2, handleShot, shotFlag2 == 1);
DrawGraphCenter(shotX3, shotY3, handleShot, shotFlag3 == 1);
DrawGraphCenter(enemyX, enemyY, handleEnemy, TRUE);
//残機表示
DrawFormatString(0, 0, GetColor(255, 255, 255), "残機:%d", playerLife+n);
//爆発処理
AnimeDsp();
//ゲームオーバー表示
if (playerLife == -1)
{
if(n==0)n++;
DrawString(70, 240, "GAME OVER", GetColor(255, 255, 255));
}
//ゲームスタート表示
if (gameTimer++ < GAME_START_PERIOD)
{
DrawString(120, CENTER_Y, "GAME START", GetColor(255, 255, 255));
}
ScreenFlip();
}
DxLib_End();
}
//画像の中心位置基準で表示
//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;
}
}
}
とりあえず爆発するところまではできた。
コメント