DXライブラリ 画面に敵を1体しか表示できない

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
くろのま
記事: 10
登録日時: 3年前

DXライブラリ 画面に敵を1体しか表示できない

#1

投稿記事 by くろのま » 3年前

初心者です。
DXライブラリを使ってシューティングゲームを作っています。敵を決まったタイミングで表示して動かそうとしました。すると、ちゃんと表示されて動きもするんですが、次の敵が現れたら前に表示された敵は消えてしまいます。それと、敵を倒したら当たり判定が残る?ような現象も発生しています。原因が全く分からないので、教えて頂きたいです。ごちゃごちゃしててすみません。

環境は Windows10、 Visual Studio 2019です。

コード:

#include "Game.h"

#include "SceneMgr.h"

#include "DxLib.h"

#include "keyboard.h"

#include "gameclear.h"


#define SHOT 20

#define ENEMY 20

static int mImageHandle;     //画像ハンドル格納用変数

static int player;           //画像ハンドル格納(自機)

static int bullet;           //画像ハンドル格納(弾)

static int enemy;            //画像ハンドル格納(敵)

static int enemyBullet;     //画像ハンドル格納(敵の弾)

static int SHandle;        //音ハンドル格納用変数(戦闘BGM)

static int bulletSHandle;   //音ハンドル格納(弾の発射音)


int playerplase_x = 100, playerplase_y = 200;     //自機の初期位置

int enemy_h = 64, enemy_w = 64, bullet_h = 16, bullet_w = 16;  //敵と弾の幅と高さ

int enemy_x[ENEMY], enemy_y[ENEMY];      //敵の座標

int bullet_x[SHOT], bullet_y[SHOT],bulletFlag[SHOT];      //弾の座標,フラグ

int enemyB_x[ENEMY], enemyB_y[ENEMY], enemySFlag[ENEMY];  //敵の弾の座標、フラグ

int enemyFlag[ENEMY];             //敵が存在しているかのフラグ

int i,j;

int bulletBFlag;             //ショットボタンが前のフレームで押されたかどうかを保存する

int countar;

int EbulletCounter = 0;                   //敵の弾のカウンター

int Ecounter = 0;                        //敵のカウンター(仮)

int myFlag = 1;

int SoundCount;                          //戦闘BGM

int Enemycounter;                      //敵が出現する時間を管理する



//初期化

void Game_Initialize() {

    mImageHandle = LoadGraph("画像/menyu.png");    //画像のロード

   player = LoadGraph("画像/mon1/mon_006.bmp");
   bullet = LoadGraph("画像/mon1/mon_040.bmp");
   enemy = LoadGraph("画像/mon1/mon_020.bmp");
   enemyBullet = LoadGraph("画像/mon1/mon_001.bmp");
      SHandle = LoadSoundMem("BGM/BGM088-100714-kongoushinkidaia-su-wav.wav");

     bulletSHandle = LoadSoundMem("BGM/攻撃の音/射撃_ショット.wav");

}


//更新

void Game_Update() {

              if (CheckHitKey(KEY_INPUT_BACK) != 0) {    //Escキーが押されていたら

                            SceneMgr_ChangeScene(eScene_Menu);       //シーンをメニューに変更

              }

   
           if (countar == 5) {
                            SceneMgr_ChangeScene(eScene_Gameclear);

                            countar = 0;

                            SoundCount = 0;
              }


              for (j = 0; j < ENEMY; j++) {

                            if (enemySFlag[j] == 1) {

                                          if (((enemyB_x[j] > playerplase_x && enemyB_x[j] < playerplase_x + 48) ||

                                                        (playerplase_x > enemyB_x[j] && playerplase_x + 64 < enemyB_x[j])) &&

                                                        ((enemyB_y[j] > playerplase_y && enemyB_y[j] < playerplase_y + 56) ||

                                                                      (playerplase_y > enemyB_y[j] && playerplase_y < enemyB_y[j] + 24))) {

                                                        enemySFlag[j] = 0;


 

                                                        WaitTimer(1000);

                                                        SceneMgr_ChangeScene(eScene_Gameover);        //シーンをゲームオーバーに変更

                                                        SoundCount = 0;

                                                        countar = 0;

                                                        break;

                                          }

                            }

              }

}


 


 


 


 

//描画

void Game_Draw() {


              DrawGraph(0, 0, mImageHandle, FALSE);
 

              if (SoundCount == 1) {

                            PlaySoundMem(SHandle, DX_PLAYTYPE_LOOP);

              }


 

              //bulletBFlag = 0;                  //ショットボタンが前のフレームで押されていない



              if (CheckHitKey(KEY_INPUT_RIGHT) == 1) {        //右キーが押されていたら

                            playerplase_x += 5;                            //右へ移動

              }

              if (CheckHitKey(KEY_INPUT_DOWN) == 1) {        //下キーが押されていたら

                            playerplase_y += 5;                           //下へ移動

              }

              if (CheckHitKey(KEY_INPUT_LEFT) == 1) {       //左キーが押されていたら

                            playerplase_x -= 5;                           //左へ移動

              }

              if (CheckHitKey(KEY_INPUT_UP) == 1) {         //上キーが押されていたら

                            playerplase_y -= 5;                           //上へ移動

              }


 


 

              if (playerplase_x < 0)playerplase_x = 0;                    //画面からはみ出るのを阻止(左)

              if (playerplase_x > 640 - 48)playerplase_x = 640 - 48;     //はみ出し阻止(右) 48は画像の幅

              if (playerplase_y < 0)playerplase_y = 0;                   //はみ出し阻止(上)

              if (playerplase_y > 480 - 56)playerplase_y = 480 - 56;     //はみ出し阻止(下) 56は画像の高さ


 

              DrawGraph(playerplase_x, playerplase_y, player, FALSE);   //x,yの位置に自機を描画


 

              if (CheckHitKey(KEY_INPUT_SPACE)) {     //スペースキーが押されたら弾を発射


 

                            if (bulletBFlag == 0) {        //前のフレームでショットボタンが押されていなかったら弾を発射


 

                                          for (i = 0; i < SHOT; i++) {


 

                                                        if (bulletFlag[i] == 0) {
 
                                                                      bullet_x[i] = playerplase_x + 24;

                                                                      bullet_y[i] = playerplase_y + 20;

                                                                      bulletFlag[i] = 1;

                                                                      PlaySoundMem(bulletSHandle, DX_PLAYTYPE_BACK);



                                                                      break;       //弾を出したのでループから抜ける

                                                        }

                                          }

                            }

                            bulletBFlag = 1;        //前フレームでショットボタンを押されていたという情報を代入

              }

              else {                              //ショットボタンが押されていなかった場合は

                            bulletBFlag = 0;                 //押されていないを代入

              }


 

              for (i = 0; i < SHOT; i++) {

                            if (bulletFlag[i] == 1) {


 

                                          bullet_x[i] += 16;                       //弾が発射中なら弾を右へ移動、画面外に出たらフラグをにする

                                          if (bullet_x[i] > 640) {

                                                        bulletFlag[i] = 0;

                                          }

                                          DrawGraph(bullet_x[i], bullet_y[i], bullet, FALSE);    //弾が発射中の時のみ画像を描画

                            }

              }




              if (Enemycounter == 10 || Enemycounter == 90 || Enemycounter == 170) {

                            for (i = 0; i < 3; i++) {

                                          enemy_x[i] = 640;

                                          enemy_y[i] = 30;

                                          enemyFlag[i] = 1;

                                          break;

                            }

              }

           

 

              for (i = 0; i < ENEMY; i++) {

                            if (enemyFlag[i] == 1) {

                                          enemy_x[i] -= 2;

                                          if (enemy_x[i]+64 < 0) {          //画面外に出たらフラグを0にする処理

                                                        enemyFlag[i] = 0;

                                          }

                                          DrawTurnGraph(enemy_x[i], enemy_y[i], enemy, FALSE);

                                          break;                    

                            }

                           

              }


 

              EbulletCounter++;


 

              for (j = 0; j < ENEMY; j++) {                         //敵の弾の座標を格納

                            if (EbulletCounter == 120 && enemyFlag[j] == 1) {

                                          enemyB_x[j] = enemy_x[j];

                                          enemyB_y[j] = enemy_y[j] + 15;

                                          enemySFlag[j] = 1;

                                          EbulletCounter = 0;

                                          break;

                            }

              }


 

              for (j = 0; j < ENEMY; j++) {

                            if (enemySFlag[j] == 1) {                      //敵の弾のフラグが1なら

                                          enemyB_x[j] -= 6;                          //敵の弾のx座標を1フレームごとに6移動する

                                          if (enemyB_x[j] + 32 < 0) {               //敵の弾のx座標が0より小さくなったら(画面外に出たら)

                                                        enemySFlag[j] = 0;

                                          }

                                          DrawTurnGraph(enemyB_x[j],enemyB_y[j],enemyBullet,FALSE);

                                          break;

                            }

              }


 

              for (j = 0; j < SHOT; j++) {                   //自機の弾と敵の当たり判定

                            if (bulletFlag[j] == 1) {

                                          if (((bullet_x[j] > enemy_x[j] && bullet_x[j] < enemy_x[j] + enemy_w) ||

                                                        (enemy_x[j] > bullet_x[j] && enemy_x[j] < bullet_x[j] + bullet_w)) &&

                                                        ((bullet_y[j] > enemy_y[j] && bullet_y[j] < enemy_y[j] + enemy_h) ||

                                                                      (enemy_y[j] > bullet_y[j] && enemy_y[j] < bullet_y[j] + bullet_h))) {


 

                                                        bulletFlag[j] = 0;

                                                        enemyFlag[j] = 0;

                                                        countar += 1;

                                                        break;

                                          }

                            }

              }


 

              SoundCount++;

              Enemycounter++;

}


 


 

//終了処理

void Game_Finalize() {

              DeleteGraph(mImageHandle);   //画像の開放

              DeleteGraph(player);        //画像の開放

              DeleteGraph(bullet);        //解放(弾)

              DeleteGraph(enemy);        //解放(敵)

              DeleteGraph(enemyBullet);  //解放(敵の弾)


 

              DeleteSoundMem(SHandle);   //音の開放(戦闘BGM)

              DeleteSoundMem(bulletSHandle);   //音の開放(弾の発射音)

}


アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DXライブラリ 画面に敵を1体しか表示できない

#2

投稿記事 by みけCAT » 3年前

・敵を出現させる処理において、フラグを確認していないため、常に最初の敵を上書きしてしまう
・敵や敵の弾を動かす処理において、余計なbreak;があるため、最初の有効な敵しか処理されない
・自機の弾と敵の当たり判定において、敵のフラグを確認していない上、
 配列上で同じ位置にある敵と弾しか見ていないため、不適切な動作になる

といった問題がありそうです。
また、Game_Update関数があるのに、Game_Draw関数で大量の更新処理をしているのも、よくないと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#3

投稿記事 by くろのま » 3年前

他の箇所は指摘していただいた通りに直しましたが、配列上で同じ位置にある敵と弾しか見ていないというのがよく分かりません。詳しく教えていただけないでしょうか?

それと、今まで更新処理はシーン変更のみと思い込んでいたのですが、画面に表示させる以外の処理は全て更新処理ということですか?よくないというのは、見づらくてよくないということでしょうか。動作に影響はありますか?

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#4

投稿記事 by くろのま » 3年前

最初に出てくる敵の弾はちゃんと意図した通りに動きますが、そのあとの弾が正常に動作しません!2体目は弾を1発撃ったらそのあと撃たず、3体目は敵が画面から消える直前に撃ってきます…(;-;)どういうことでしょうか…
画面に敵を1体しか表示できないという問題は指摘していただいた場所を直したら無事解決しました。敵の当たり判定がおかしいです。弾が当たったり当たらなかったり…

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DXライブラリ 画面に敵を1体しか表示できない

#5

投稿記事 by みけCAT » 3年前

くろのま さんが書きました:
3年前
配列上で同じ位置にある敵と弾しか見ていないというのがよく分かりません。詳しく教えていただけないでしょうか?
複数あるもの同士の通常の当たり判定では、二重のループを用い、
存在しているものの組み合わせ全てについて判定を行います。
mixcpp-20965-1-20200821.png
通常の当たり判定
mixcpp-20965-1-20200821.png (7.61 KiB) 閲覧数: 21444 回
一方、くろのまさんのコードでは、ループを一重しか用いておらず、限られた組み合わせしか判定をしていません。
mixcpp-20965-2-20200821.png
くろのまさんの当たり判定
mixcpp-20965-2-20200821.png (4.96 KiB) 閲覧数: 21444 回
このため、判定しない組み合わせでは判定が行われず、「当たらない」ということになります。
くろのま さんが書きました:
3年前
それと、今まで更新処理はシーン変更のみと思い込んでいたのですが、画面に表示させる以外の処理は全て更新処理ということですか?
「ゲームの状態を変える処理」全般
(シーン変更、カウンタの更新、各種オブジェクトの座標の更新など)が更新処理だと思います。
例えばサウンドの再生は「画面に表示」ではないですが、更新処理よりも描画の仲間と考えられるので、
「画面に表示させる以外の処理は全て更新処理」とはいえないでしょう。
くろのま さんが書きました:
3年前
よくないというのは、見づらくてよくないということでしょうか。動作に影響はありますか?
Drawという名前がついているのにDrawでない処理をしているのは、誤解を招く原因となり、
理解のしやすさを下げるのでよくないと考えられます。
動作への直接の影響は無いと考えられますが、
意図しない処理を残してしまうバグのもととなるなど、間接的に影響する可能性があります。
くろのま さんが書きました:
3年前
最初に出てくる敵の弾はちゃんと意図した通りに動きますが、そのあとの弾が正常に動作しません!2体目は弾を1発撃ったらそのあと撃たず、3体目は敵が画面から消える直前に撃ってきます…(;-;)どういうことでしょうか…
手元で動かしてみたところ、1体目(一番左)の敵が弾を3発撃ち(うち1発は画面から隠れた状態)、
その後3体目(一番右)の敵が画面の左端のあたりで弾を1発撃つ、という挙動がみられました。
2体目(真ん中)の敵は弾を撃ちませんでした。
弾を打つ部分の処理で弾を撃つかの判定に使われているEbulletCounterの値を変えてしまうため、
break;の有無にかかわらず最初の有効な敵1体しか弾を撃たないようになっていますね。
意図した挙動はどのようなものですか?
添付ファイル
test_sozai.zip
実行用画像・補完ソースコード
(5.8 KiB) ダウンロード数: 129 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#6

投稿記事 by くろのま » 3年前

敵が画面上に現れてから60フレームごとに1発弾を撃つようにしたいです。弾を出したらカウンターを0にすればいけるかなと思ったのですが、全然できませんね…

図を使っての説明、ありがとうございました!とても分かりやすかったです。確かに自分のコードだと当たり判定が正常に動くわけがないですよね…
コードを下のように変更してみたら、とりあえず出てきた敵は倒せるようになったのですが、これであっているでしょうか?

コード:

for (i = 0; i < SHOT+j; i++) {

for (j = 0; j < SHOT; j++) {                   //自機の弾と敵の当たり判定

              if (bulletFlag[i] == 1) {

              if (enemyFlag[j] == 1) {

              if (((bullet_x[i] > enemy_x[j] && bullet_x[i] < enemy_x[j] + enemy_w) ||

                            (enemy_x[j] > bullet_x[i] && enemy_x[j] < bullet_x[i] + bullet_w)) &&

                            ((bullet_y[i] > enemy_y[j] && bullet_y[i] < enemy_y[j] + enemy_h) ||

                            (enemy_y[j] > bullet_y[i] && enemy_y[j] < bullet_y[i] + bullet_h))) {


 

                            bulletFlag[i] = 0;

                            enemyFlag[j] = 0;

                            countar += 1;

                            break;

                            }

                       }

                 }

          }

   }

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DXライブラリ 画面に敵を1体しか表示できない

#7

投稿記事 by みけCAT » 3年前

くろのま さんが書きました:
3年前
敵が画面上に現れてから60フレームごとに1発弾を撃つようにしたいです。弾を出したらカウンターを0にすればいけるかなと思ったのですが、全然できませんね…
カウンターを敵ごとに用意するといいかもしれません。
くろのま さんが書きました:
3年前
コードを下のように変更してみたら、とりあえず出てきた敵は倒せるようになったのですが、これであっているでしょうか?
間違っています。
外側のループの継続条件が i < SHOT+j となっており、
jは内側のループを抜けるときにはSHOTになっているので、iは SHOT+SHOT-1 までループしてしまいます。
一方、bulletFlagなど弾に関する配列の要素数はSHOTしか無いため、範囲外アクセスが発生します。
また、たまたまENEMYとSHOTが同じ値なので実害は出ないものの、
enemyFlagなど敵に関する配列の要素数はENEMYなので、
敵に関するループの上限にSHOTを用いるのは不適切であるといえます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#8

投稿記事 by くろのま » 3年前

これはどうですか!直しました!

コード:

for (i = 0; i < SHOT; i++) {

for (j = 0; j < ENEMY; j++) {                   //自機の弾と敵の当たり判定

              if (bulletFlag[i] == 1) {

              if (enemyFlag[j] == 1) {

                            if (((bullet_x[i] > enemy_x[j] && bullet_x[i] < enemy_x[j] + enemy_w) ||

                                (enemy_x[j] > bullet_x[i] && enemy_x[j] < bullet_x[i] + bullet_w)) &&

                                ((bullet_y[i] > enemy_y[j] && bullet_y[i] < enemy_y[j] + enemy_h) ||

                                 (enemy_y[j] > bullet_y[i] && enemy_y[j] < bullet_y[i] + bullet_h))) {


 

                                          bulletFlag[i] = 0;

                                          enemyFlag[j] = 0;

                                          countar += 1;

                                          break;

                                                        }

                                          }

                            }

              }

}




敵の弾はこれであっていますか?自分が動かしたいようには動いています。

コード:

if (Enemycounter == 10 || Enemycounter == 160 || Enemycounter == 310) {

           for (i = 0; i < 3; i++) {                                    //敵のカウンターの条件を満たしたら

                      if (enemyFlag[i] == 0) {            敵の弾の座標を格納する

                                 enemy_x[i] = 640;

                                 enemy_y[i] = 30;

                                 enemyFlag[i] = 1;

                                 break;

                      }

           }

}

          


 

for (i = 0; i < ENEMY; i++) {

           if (enemyFlag[i] == 1) {

                      enemy_x[i] -= 2;

                      EbulletCounter[i]++;

                      if (enemy_x[i]+64 < 0) {          //画面外に出たらフラグを0にする処理

                                 enemyFlag[i] = 0;

                      }

                      DrawTurnGraph(enemy_x[i], enemy_y[i], enemy, FALSE);

           }

                     

}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DXライブラリ 画面に敵を1体しか表示できない

#9

投稿記事 by みけCAT » 3年前

くろのま さんが書きました:
3年前
これはどうですか!直しました!
ブロックと最初と最後でインデントの深さが違う以外は、問題なさそうだと思います。
くろのま さんが書きました:
3年前
敵の弾はこれであっていますか?自分が動かしたいようには動いています。
ここには敵本体の処理しか書かれていないようなので、「敵の弾」としては論外ですね。
書かれている処理については、
敵を出現させる時のループの上限がENEMYではなくマジックナンバーの3になっているのが気になりますが、
今のところ出現させる敵は3体のみで、かつENEMYは3以上なので、異常動作の原因にはならないでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#10

投稿記事 by くろのま » 3年前

すみません、間違えてました…
これです↓

コード:

for (j = 0; j < ENEMY; j++) {                         //敵の弾の座標を格納

              if (EbulletCounter[j] == 60) {

                            if (enemySFlag[j] == 0) {


 

                                          enemyB_x[j] = enemy_x[j];

                                          enemyB_y[j] = enemy_y[j] + 15;

                                          enemySFlag[j] = 1;


 

                                          break;

                            }

              }

}


 

for (j = 0; j < ENEMY; j++) {

              if (enemySFlag[j] == 1) {                      //敵の弾のフラグが1なら

                            enemyB_x[j] -= 6;                          //敵の弾のx座標を1フレームごとに6移動する

                            EbulletCounter[j] = 0;

                                   if (enemyB_x[j] + 32 < 0) {               //敵の弾のx座標が0より小さくなったら(画面外に出たら)

                                          enemySFlag[j] = 0;

                                    }

                                          DrawTurnGraph(enemyB_x[j],enemyB_y[j],enemyBullet,FALSE);

              }

}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DXライブラリ 画面に敵を1体しか表示できない

#11

投稿記事 by みけCAT » 3年前

弾の移動処理においてEbulletCounter[j] = 0;を実行しているが、
ここでのjは敵ではなく敵の弾の位置なので、関係ない敵のデータを書き換えてしまうことに繋がり、不適切です。
EbulletCounter[j] = 0;は弾を出す処理の方で行うべきでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

くろのま
記事: 10
登録日時: 3年前

Re: DXライブラリ 画面に敵を1体しか表示できない

#12

投稿記事 by くろのま » 3年前

直してみたら、敵1体につき弾を1発しか撃ってくれなくなってしまいましたが、バグもなく正常に動作しているのでこのままにしておこうと思います。
みけCATさん、質問に丁寧に答えてくださりありがとうございました!

返信

“C言語何でも質問掲示板” へ戻る