現在、龍神録プログラミングの館のプログラムを参考にさせていただきながらC++でシューティング制作の練習をしています。
ようやく敵弾の発射が出来たのですが、その挙動がなにやらおかしいです。
1体目の弾発射→2体目の弾発射→3体目の弾発射・・・と順番に発射させたいのですが、まだ画面内にあるはずの敵の弾が突然消えてしまいます。
1体目発射→2体目発射の瞬間、残っているはずの1体目の弾が消えたと同時に2体目の弾が発射される→・・・
といった形になってしまいます。
消滅させるフラグの管理がおかしいのかと思われるのですが、自分では確認してもおかしく見えないので、それ以外のミスがあるのかな・・・と困っています。
以下のコードでおかしい点があったらご指摘くださると助かります(他に必要なコードがあれば載せます)。
Enemy.cpp
#include"StdAfx.h"
#include"Enemy.h"
#include"Manager.h"
//----------------------------------------------
// コンストラクタ
//----------------------------------------------
C_Enemy::C_Enemy()
{
// 敵画像読み込み
LoadDivGraph("Resource/Picture/Enemy/enemy1.png", 9, 3, 3, 32, 32, eImage[0]);
// 弾画像読み込み
LoadDivGraph( "Resource/Picture/Enemy/b0.png", 5, 5, 1, 76, 76, bImage[0]);
LoadDivGraph( "Resource/Picture/Enemy/b1.png", 6, 6, 1, 22, 22, bImage[1]);
LoadDivGraph( "Resource/Picture/Enemy/b2.png", 10, 10, 1, 5, 120, bImage[2]);
LoadDivGraph( "Resource/Picture/Enemy/b3.png", 5, 5, 1, 19, 34, bImage[3]);
LoadDivGraph( "Resource/Picture/Enemy/b4.png", 10, 10, 1, 38, 38, bImage[4]);
LoadDivGraph( "Resource/Picture/Enemy/b5.png", 3, 3, 1, 14, 16, bImage[5]);
LoadDivGraph( "Resource/Picture/Enemy/b6.png", 3, 3, 1, 14, 18, bImage[6]);
LoadDivGraph( "Resource/Picture/Enemy/b7.png", 9, 9, 1, 16, 16, bImage[7]);
LoadDivGraph( "Resource/Picture/Enemy/b8.png", 10, 10, 1, 12, 18,bImage[8]);
LoadDivGraph( "Resource/Picture/Enemy/b9.png", 3, 3, 1, 13, 19, bImage[9]);
// 初期化
memset(enemy, 0, sizeof(T_Enemy) * ENEMY_MAX);
memset(order, 0, sizeof(T_EnemyOrder) * ENEMY_ORDER_MAX);
memset(enemyShot, 0, sizeof(T_EnemyShot) * ENEMY_SHOT_MAX);
// csv読み込み
LoadStory();
}
//----------------------------------------------
// 空いている敵番号を探す
//----------------------------------------------
int C_Enemy::EnemySearch()
{
for(int i = 0; i < ENEMY_MAX; ++i)
{
// フラグが立っていなければ
if(enemy[i].flag == 0)
{
return i; // その番号を返す
}
}
return -1; // 全部埋まっていたらエラーを返す
}
//----------------------------------------------
// 空いている弾番号を探す
//----------------------------------------------
int C_Enemy::ShotSearch(int n)
{
for(int i = 0; i < ENEMY_BULLET_MAX; ++i)
{
// フラグが立っていなかったら
if(enemyShot[n].bullet[i].flag == 0)
{
return i; // その番号を返す
}
}
return -1; // 全部埋まっていたらエラーを返す
}
//----------------------------------------------
// 登録
//----------------------------------------------
void C_Enemy::Enter()
{
int i;
for(int t = 0; t < ENEMY_ORDER_MAX; ++t)
{
// 現在の瞬間がオーダーの瞬間なら
if(order[t].cnt == stageCount)
{
// 空いている敵番号に代入
if((i = EnemySearch()) != -1)
{
enemy[i].flag = 1; // フラグ
enemy[i].cnt = 0; // カウンタ
enemy[i].muki = 1; // 向き
enemy[i].vx = 0; // 水平成分の速度
enemy[i].vy = 0; // 鉛直成分の速度
enemy[i].ang = 0; // 角度
enemy[i].pattern= order[t].pattern; // 移動パターン
enemy[i].knd = order[t].knd; // 敵の種類
enemy[i].x = order[t].x; // 座標x
enemy[i].y = order[t].y; // 座標y
enemy[i].sp = order[t].sp; // スピード
enemy[i].bltime = order[t].bltime; // 弾の発射時間
enemy[i].blknd = order[t].blknd; // 弾幕の種類
enemy[i].blknd2 = order[t].blknd2; // 弾の種類
enemy[i].col = order[t].col; // 色
enemy[i].wait = order[t].wait; // 停滞時間
enemy[i].hp = order[t].hp; // 体力
enemy[i].hp_max = enemy[i].hp; // 体力最大値
for(int j = 0; j < 6; ++j)
enemy[i].item_n[j] = order[t].item_n[j];// 落とすアイテム
}
}
}
}
//----------------------------------------------
// 弾幕データ登録
//----------------------------------------------
void C_Enemy::EnterShot(int i)
{
for(int j = 0; j < ENEMY_SHOT_MAX; ++j)
{
// フラグが立っていなければ
if(enemyShot[j].flag == 0)
{
memset(&enemyShot, 0, sizeof(T_EnemyShot)); // 初期化
enemyShot[j].flag = 1; // フラグを立てる
enemyShot[j].knd = enemy[i].blknd; // 弾の種類
enemyShot[j].num = i; // どの敵から発射されたか
enemyShot[j].cnt = 0; // カウンタ
return;
}
}
}
//----------------------------------------------
// 移動制御
//----------------------------------------------
void C_Enemy::Calc()
{
for(int i = 0; i < ENEMY_MAX; ++i)
{
// フラグが立っていたら
if(enemy[i].flag == 1)
{
// パターン数が正しければ
if( 0 <= enemy[i].pattern && enemy[i].pattern < ENEMY_PATTERN_MAX)
{
// 移動パターン
switch(enemy[i].pattern)
{
case 0: MovePattern0(i); break;
case 1: MovePattern1(i); break;
case 2: MovePattern2(i); break;
case 3: MovePattern3(i); break;
case 4: MovePattern4(i); break;
case 5: MovePattern5(i); break;
case 6: MovePattern6(i); break;
case 7: MovePattern7(i); break;
case 8: MovePattern8(i); break;
case 9: MovePattern9(i); break;
case 10: MovePattern10(i); break;
}
// 移動
enemy[i].x += cos(enemy[i].ang) * enemy[i].sp;
enemy[i].y += sin(enemy[i].ang) * enemy[i].sp;
enemy[i].x += enemy[i].vx;
enemy[i].y += enemy[i].vy;
// カウンタ
enemy[i].cnt++;
// アニメーション
enemy[i].img = enemy[i].muki * 3 + (enemy[i].cnt % 18) / 6;
// 画面外に出た
if(enemy[i].x < -50 || FIELD_MAX_X + 50 < enemy[i].x || enemy[i].y < -50 || FIELD_MAX_Y + 50 < enemy[i].y)
enemy[i].flag = 0;// 消去
// 弾幕開始時間になったら
if(enemy[i].bltime == enemy[i].cnt)
EnterShot(i);// 弾幕データ登録
}
else
printfDx("enemy[i].patternの%d値が不正です。", enemy[i].pattern);
}
}
}
//----------------------------------------------
// ショット演算
//----------------------------------------------
void C_Enemy::ShotCalc(int n)
{
// 敵が倒されたら
if(enemy[enemyShot[n].num].flag != 1)
enemyShot[n].flag = 2; // それ以上弾幕を登録しない
for(int i = 0; i < ENEMY_BULLET_MAX; ++i)
{
// 弾が登録されていたら
if(enemyShot[n].bullet[i].flag > 0)
{
// 移動計算
enemyShot[n].bullet[i].x += cos(enemyShot[n].bullet[i].angle) * enemyShot[n].bullet[i].spd;
enemyShot[n].bullet[i].y += sin(enemyShot[n].bullet[i].angle) * enemyShot[n].bullet[i].spd;
// カウンタ
enemyShot[n].bullet[i].cnt++;
// 画面外に出た
if(enemyShot[n].bullet[i].x < -50 || enemyShot[n].bullet[i].x > FIELD_MAX_X + 50 ||
enemyShot[n].bullet[i].y < -50 || enemyShot[n].bullet[i].y > FIELD_MAX_Y + 50)
{
// 最低限消えない時間を過ぎたら
if(enemyShot[n].bullet[i].till < enemyShot[n].bullet[i].cnt)
enemyShot[n].bullet[i].flag = 0; // 消去
}
}
}
// 現在表示中の弾があるか調べる
for(int i = 0; i < ENEMY_BULLET_MAX; ++i)
if(enemyShot[n].bullet[i].flag > 0)
return;// フラグが立っていれば抜ける
// フラグが立っていなければ
if(enemy[enemyShot[n].num].flag != 1)
{
// 終了
enemyShot[n].flag = 0;
enemy[enemyShot[n].num].flag = 0;
}
}
//----------------------------------------------
// 描画
//----------------------------------------------
void C_Enemy::Draw()
{
// 線形補完描画
SetDrawMode(DX_DRAWMODE_BILINEAR);
// 敵の弾幕数分ループ
for(int i = 0; i < ENEMY_SHOT_MAX; ++i)
{
// 弾幕データがオンなら
if(enemyShot[i].flag > 0)
{
// 弾の最大数分ループ
for(int j = 0; j < ENEMY_BULLET_MAX; ++j)
{
// 弾データがオンなら
if(enemyShot[i].bullet[j].flag != 0)
{
// エフェクトが1なら
if(enemyShot[i].bullet[j].eff == 1)
SetDrawBlendMode(DX_BLENDMODE_ADD, 255); // ブレンドモード開始
// 弾の描画
DrawRotaGraphF(
enemyShot[i].bullet[j].x, enemyShot[i].bullet[j].y,
1.0f, enemyShot[i].bullet[j].angle + PI / 2,
bImage[enemyShot[i].bullet[j].knd][enemyShot[i].bullet[j].col], true);
if(enemyShot[i].bullet[j].eff == 1)
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0); // ブレンドモード終了
}
}
}
}
// 描画形式を戻す
SetDrawMode(DX_DRAWMODE_NEAREST);
for(int i = 0; i < ENEMY_MAX; ++i)
{
// フラグが立っている
if(enemy[i].flag == 1)
{
// 敵描画
DrawRotaGraphF(enemy[i].x, enemy[i].y, 1.0f, 0.0f, eImage[0][enemy[i].img], TRUE);
}
}
}
//----------------------------------------------
// ショット統括
//----------------------------------------------
void C_Enemy::ShotAll()
{
for(int i = 0; i < ENEMY_SHOT_MAX; ++i)
{
// フラグが立っていて種類が間違っていなければ
if(enemyShot[i].flag != 0 && 0 <= enemyShot[i].knd && enemyShot[i].knd < ENEMY_SHOT_KND_MAX)
{
// 弾幕パターン
switch(enemyShot[i].knd)
{
case 0: ShotPatternH0(i); break;
case 1: ShotPatternH1(i); break;
case 2: ShotPatternH2(i); break;
case 3: ShotPatternH3(i); break;
case 4: ShotPatternH4(i); break;
case 5: ShotPatternH5(i); break;
case 6: ShotPatternH6(i); break;
}
ShotCalc(i); // i番目の弾演算
enemyShot[i].cnt++; // カウンタ
}
}
}
//----------------------------------------------
// 統括
//----------------------------------------------
void C_Enemy::All()
{
Enter(); // 登録
Calc(); // 演算
Draw(); // 描画
ShotAll(); // ショット統括
}