質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.34%
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

解決済

1回答

160閲覧

「ハンドルされない例外が 0x00007FF7ACE3D9ACで発生しました: 無効なパラメーターを致命的と見なす関数に無効なパラメーターが渡されました。」というエラーの解決方法がわからない

igu..

総合スコア2

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

0クリップ

投稿2025/01/17 05:32

編集2025/01/17 05:47

実現したいこと

c++を使ってvisualStudioで2Dアクションゲームを作ろうとしており、プレイヤーがコインに当たるとコインが消える、というものを作ろうとしています。vectorを使い動的配列でコインを生成しています

発生している問題・分からないこと

プレイヤーとコインの当たり判定は上手くいき接触したコインを消すためにvectorでコインを削除するためのコードを書き実行したところ、コインに接触した瞬間にエラーが起きウィンドウを閉じると、items_[i]->Update();の部分で「ハンドルされない例外が発生しました」とエラーがおきました

エラーメッセージ

error

1ハンドルされない例外が 0x00007FF7ACE3D9AC (BaseProject.exe) で発生しました: 無効なパラメーターを致命的と見なす関数に無効なパラメーターが渡されました。

該当のソースコード

#include <DxLib.h> #include "Stage.h" #include "GameScene.h" #include "Player.h" #include "Application.h" #include "ItemBase.h" #include "ItemStar.h" GameScene::GameScene(void) { cameraPos_.x = 0; cameraPos_.y = 0; } GameScene::~GameScene(void) { } void GameScene::Init(void) { stage_ = new Stage(); stage_->Init(this); player_ = new Player(); player_->Init(this,0); player2_ = new Player(); player2_->Init(this,100); //出現カウンターを0にする itemSpawnCounter_ = 0; //出現数を1にする itemSpawn_ = 1; //アイテムの初期化 size_t size = items_.size(); for (int i = 0; i < size; i++) { items_[i]->Release(); delete items_[i]; } items_.clear(); p1ItemCollision_ = false; p2ItemCollision_ = false; p1Score_ = 0; p2Score_ = 0; } void GameScene::Update(void) { MoveCamera(player_); MoveCamera(player2_); stage_->Update(); player_->Update(player_, DX_INPUT_PAD1); player2_->Update(player2_, DX_INPUT_PAD2); //アイテムの更新処理は動的配列で回す //出現しているアイテムはすべて更新する size_t size = items_.size(); for (int i = 0; i < size; i++) { items_[i]->Update(); p1ItemCollision_=IsCollisionItem(player_); p2ItemCollision_=IsCollisionItem(player2_); } if (p1ItemCollision_) { p1Score_+=1; p1ItemCollision_ = false; } if (p2ItemCollision_) { p2Score_+=1; p2ItemCollision_ = false; } //アイテムの出現カウントを増やす ++itemSpawnCounter_; //出現カウントが指定値を超えたら if (itemSpawnCounter_ > ITEM_SPAWN_INTERVAL && itemSpawn_ < 3) { itemSpawnCounter_ = 0; //アイテムを動的生成 //ポインタに何もささない上程を設定するときは //nullptrをしようする ItemBase* newItem = nullptr; //アイテムの生成 int itemTypeMaxNum = static_cast<int>(ItemBase::TYPE::MAX) - 1; //アイテムのタイプをランダムで決定する int newItemType = GetRand(itemTypeMaxNum); //enmuで使用するためにアイテムのタイプに戻す ItemBase::TYPE randType = static_cast<ItemBase::TYPE>(newItemType); switch (randType) { case ItemBase::TYPE::STAR: newItem = new ItemStar(); break; } newItem->Init(this); //出現座標 Vector2F spawnPos; //ワーニング回避のために一旦初期化 spawnPos.x = 0; spawnPos.y = 0; //出現位置設定 switch (randType) { case ItemBase::TYPE::STAR: spawnPos.x = cameraPos_.x + GetRand(Application::SCREEN_SIZE_X); spawnPos.y = cameraPos_.y + GetRand(Application::SCREEN_SIZE_Y) + 90; break; } //座標の設定 newItem->SetPos(spawnPos); //動的配列に追加 items_.push_back(newItem); itemSpawn_++; } } void GameScene::Draw(void) { stage_->Draw(); player_->Draw(); player2_->Draw(); //アイテムの描画も動的配列でまわす形に変更 //出現しているアイテムすべてを描画する size_t size = items_.size(); for (int i = 0; i < size; i++) { items_[i]->Draw(); } player_->Draw(); player2_->Draw(); DrawFormatString(50, 90, 0xffffff, "%d,%d", cameraPos_.x, cameraPos_.y); DrawBox(130, 100, Application::SCREEN_SIZE_X - 130, Application::SCREEN_SIZE_Y - 100, 0xff0000, false); DrawFormatString(0, 110, 0xffffff, "%d,%d", p1Score_, p2Score_); } void GameScene::Release(void) { stage_->Release(); delete stage_; player_->Release(); delete player_; player2_->Release(); delete player2_; } Vector2 GameScene::World2MapPos(Vector2 worldPos) { Vector2 ret; int mapX = worldPos.x / Stage::CHIP_SIZE_X; int mapY = worldPos.y / Stage::CHIP_SIZE_Y; ret.x = mapX; ret.y = mapY; return ret; } bool GameScene::IsCollisionStage(Vector2 worldPos) { // ワールド座標からマップ座標へ変換する Vector2 mapPos = World2MapPos(worldPos); // プレイヤーがいる位置のマップチップ番号を取得する int chipNo = stage_->GetChipNo(mapPos); // 障害物のチップ番号と当たっていたら真を返す if (chipNo == 8 || chipNo == 9 || chipNo == 10 || chipNo == 11 || chipNo == 12) { return true; } return false; } bool GameScene::IsCollisionItem(Player* player) { Vector2F pPos = player->GetPos(); //アイテムの更新処理は動的配列で回す //出現しているアイテムはすべて更新する size_t size = items_.size(); for (int i = 0; i < size; i++) { Vector2F iPos = items_[i]->GetPos(); Vector2 iSize = items_[i]->GetSize(); if (pPos.x - Player::COL_SIZE_X / 2 < iPos.x + iSize.x && iPos.x - iSize.x < pPos.x + Player::COL_SIZE_X / 2 && pPos.y - Player::COL_SIZE_Y / 2 < iPos.y + iSize.y && iPos.y - iSize.y < pPos.y + Player::COL_SIZE_Y / 2) { items_.erase(items_.begin() + i); i--; return true; } } return false; } Vector2 GameScene::GetCameraPos(void) { return cameraPos_; } void GameScene::MoveCamera(Player* player) { //プレイヤー座標の取得 Vector2F playerPos = player->GetPos(); //カメラの左枠処理 //カメラの左側よりプレイヤーが進んだら if (playerPos.x < cameraPos_.x + 130) { //カメラの座標をプレイヤー座標にする cameraPos_.x = playerPos.x - 130; } //カメラに移る範囲の右側座標 int cameraRightSidePosX = cameraPos_.x + Application::SCREEN_SIZE_X - 130; //カメラの右枠処理 //カメラの右側よりプレイヤーが進んだら if (cameraRightSidePosX < playerPos.x && playerPos.x < Stage::CHIP_SIZE_X * Stage::MAP_GROUND_SIZE_X - 130) { //プレイヤーのX座標-画面サイズをカメラ座標にする cameraPos_.x = playerPos.x - Application::SCREEN_SIZE_X + 130; } }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

IsCollisionItem関数のif文のなかに「items_.erase(items_.begin() + i);」配列の要素を削除するためのコードを書いたところ今回のエラーが発生しました、このコードをコメントアウトしたところ特にエラーが発生しなかったため原因はこの部分で間違いないと思います

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YT0014

2025/01/17 05:47 編集

erase()の中身が不明なので、推測になりますが、実体を消したとして、参照が残っていたりしてませんか?
igu..

2025/01/17 05:56

eraseの中身というのはbegin()+iのことですか? 先頭要素に接触した要素iを足しています 参照が残っているというのは具体的にどういうことでしょうか
YT0014

2025/01/17 06:12

erase()の中身というのは、erase()で行っている実際の処理コードのことです。 items_ の型も、erase()のソースも記載されていないので、igu..さん以外にはわからない状態です。 items_は、何らかの参照(ポインタ)のようなので、初期化で行っているようなReleaseやdeleteをして消していると推測しましたが、その後で、配列から参照を削除して、配列を再編しているのでしょかとお聞きしております。 参照が残っていた場合、Update()やDraw()で、配列の全要素の処理をしているので、エラーになりそうです。
fana

2025/01/17 06:24

> vectorを使い… という記述と,コードとから「推測」するなら std::vector< ItemBase* > あたりだろうとは思いますが,ちゃんと明示すべきところですね.
igu..

2025/01/17 06:30

申し訳ないです、説明不足でした
guest

回答1

0

ベストアンサー

IsCollisionItem() の呼び出し元は以下のようになっており,ループ中に items_ の要素数が減るなら問題を起こすでしょう.

C++

1size_t size = items_.size(); //この時点での items_.size() の回数だけ以下のループが回るわけだが 2for (int i = 0; i < size; i++) 3{ 4 //そしたら,このループ内で items_ の要素数が減ったりしたらまずいよね 5 items_[i]->Update(); 6 p1ItemCollision_=IsCollisionItem(player_); 7 p2ItemCollision_=IsCollisionItem(player2_); 8}

例えば,上記のループに入る時点では要素数が2個だったとして,初回のループにて IsCollisionItem() 内で要素が1つ削除されてしまったならば,どうなるでしょう?
ループは2回目で items_[1] にアクセスするわけですが,その時点では items_ のサイズは1個なので……

投稿2025/01/17 06:08

編集2025/01/17 06:12
fana

総合スコア12010

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

igu..

2025/01/17 06:16

確かにそうですね、update内に入っていたのでsizeも更新されるかなと思っていました、この場合だとどこで削除するのがよいでしょうか
fana

2025/01/17 06:19

そもそも,このようにループ内で IsCollisionItem() を呼び出す必要性というのがあるのか否か? --- //全てのアイテムの Update() を実施 for( auto *pItem : Items_ ){ pItem->Udate(); } //IsCollisionItem()の実施 p1ItemCollision_=IsCollisionItem(player_); p2ItemCollision_=IsCollisionItem(player2_); --- っていうのだとダメなんですかね?
igu..

2025/01/17 06:24

そうですね..なぜループ内に置いていたのか自分でもわかんないです、実際にループの外に置いたらエラーが発生しませんでした、エラーの原因はループ中にsizeが減っていたのが理由ですかね?
fana

2025/01/17 06:32

> update内に入っていたのでsizeも更新されるかなと思っていました 「ので」の左側と右側の繋がりがこちらにはさっぱりわからない感じだし(あと,コードの雰囲気とかからも若干) 基本的なところが危うそうな雰囲気にも感じますが,大丈夫なんでしょうか? ・元のコードだと物事がどのように進んでいってどうなっていたのか? ・書き換えたコードだと何故問題が起きないのか? というあたりをご自身で把握できないようだと,ちょっとこのまま進めるのはきついんじゃないかな,とか思ったり. (余計なお世話でしょうが)
fana

2025/01/17 06:42 編集

ループ開始時点で要素数がN個だったとしても,ループ内で要素数が変化し得るのであれば 全要素を走査する手段が「N回ループする」ではダメだよね. …っていうのが,回答の内容. しかし,回答内で述べていない(別の)話としては 【ループ内で不特定の要素が削除されてしまうのであれば,ループにて「次にどの要素について処理をすれば良いのか」という問題があるよね】ってのもある. ループカウンタ i は処理対象アイテムを示すindexとして使われているわけだけど, 例えば i の値が 2 であるときに Items_[0] と Items_[4] が削除された場合,次に処理すべき要素を示すように i の値を適切に更新してやる必要があるけど,それっていくつにすれば良いのだろうか? (そもそも今のループの形だと「何番目の要素が削除されたのか」という情報をループ側では知ることができないから,適切に更新できるとは思えないが)
fana

2025/01/17 06:47

さらに余計な(本題とは関係ない)話: 要素を new で作ってるなら,erase() する前に delete が必要なのでは.
igu..

2025/01/17 06:50

アドバイスありがとうございます、まだ学生なのでという言い訳はあまりしたくないのですが、まだまだ勉強中でコードの書き方も知識も全然なのですが、これからもっと数をこなして経験を積みたいと考えています、今回作成しているのは友達に見せて遊んでもらうだけに作っているのですが、途中で投げ出したくないので最後まで作ろうと思います、回答ありがとうございました
fana

2025/01/17 07:03

> コードの書き方 これに関しては 「自分が把握できるコードを書く,自分がやりやすいコードを書く」ようにすると良いんじゃないかな. 今回ので言えば, 衝突するものを探すこと と 要素を削除すること とが1つのメソッド内に同居しているのことが 厄介/複雑/etc だったりするならば,そこはもっと小分けにしてみても良いだろうし. vectorを使う事がプログラミング難易度を上げているならば使わなくったって良いのだし.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.34%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問