自機の弾と敵との当たり判定処理

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

自機の弾と敵との当たり判定処理

#1

投稿記事 by ヨッシー » 2年前

c/c++とDxライブラリで2次元シューティングゲームを作ろうとしているものです。投稿は今回で3回目となり、前回は「メニュー画面の実装について」というトピックで質問させていただきました。

今回はタイトルにもあるように、「自機ショットと敵との当たり判定処理」を行いたいと思い、インターネットなどを参考にしながらプログラムを書いていたのですが、その過程でわからないところがありましたので質問させていただきます。
ソースコードです。

コード:

isHitCheck.h

#pragma once
#include "PlayerBullet01.h"
#include "PlayerBullet02.h"
#include "EnemyManager.h"

class HitCheck
{
 public:
	 HitCheck();
	 PlayerBulletCollection01* playerbullet01;
	 PlayerBulletCollection02* playerbullet02;
	 EnemyManager* enemy;
	 bool CircleCollision(double pc, double ec, double cx1, double cx2, double cy1, double cy2);
	 void CollisionAll();
	
};

isHitCheck.cpp

#include "isHitCheck.h"
#include "Define.h"

HitCheck::HitCheck()
{

}

bool HitCheck::CircleCollision(double pc, double ec, double cx1, double cx2, double cy1, double cy2)
{
	//仮引数は左から弾の半径、敵の半径、弾のx座標、敵のx座標、弾のy座標、敵のy座標
	double hlength = pc + ec;
	double xlength = cx1 - cx2;
	double ylength = cy1 - cy2;

	if(hlength * hlength >= xlength * xlength + ylength * ylength) {
		return true;
	}
	else {
		return false;
	}
}

void HitCheck::CollisionAll()
{
	float px, py, ex, ey; //判定処理をしたい弾と敵の座標
	//操作キャラの弾と敵との当たり判定
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < Define::PBULLET_NUM / 4; ++j) {
			if (playerbullet01->GetShotPosition(i, j, &px, &py)) {
				for (auto enemy : _list) {
					if (!enemy->GetdeadFlag()) {
						enemy->GetPosition(&ex, &ey);
						//当たり判定
						if (CircleCollision(Define::PSHOT_COLLISION, Define::ENEMY_COLLISION, px, ex, py, ey)) {
							//当たっていれば、deadflagを立てる
							enemy->SetDeadFlag();
							//当たった弾のフラグを戻す
							playerbullet01->SetShotFlag(i, j, false);
						}
					}
				}
			}
		}
	}
}
とりあえず上のような感じで作成してみたのですが、void CheckHit::CollisionAll()関数にあるfor(auto enemy : _list)の部分でエラーがでてしまい、デバッグが出来ない状態です。

enemyは他クラスにてstd::listで管理しております。それをHitCheckクラスにfor文を使ってすべての要素にアクセスしたかったのですが、エラーが吐かれてしまいました。
構文上のミスではないと思うのですが、、他クラスのstd::listにアクセスする方法があるのでしたら教えていただきたいです。

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

Re: 自機の弾と敵との当たり判定処理

#2

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

ヨッシー さんが書きました:
2年前
void CheckHit::CollisionAll()関数にあるfor(auto enemy : _list)の部分でエラーがでてしまい、デバッグが出来ない状態です。
該当部分で使われている変数? _list の宣言が提示されたコードの中にありません。
どのようなエラーが出ますか?
ヨッシー さんが書きました:
2年前
他クラスのstd::listにアクセスする方法があるのでしたら教えていただきたいです。
「他クラス」でstd::listにアクセスする方法を作って(アクセサの関数を作るとか、publicにするとか)、
それを利用し、「他クラス」の名前(staticの場合)またはインスタンス(staticでない場合)を指定して
アクセスするようにするといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ヨッシー
記事: 13
登録日時: 2年前

Re: 自機の弾と敵との当たり判定処理

#3

投稿記事 by ヨッシー » 2年前

進捗報告を少し、friend関数で当たり判定のクラスとstd::listを管理している二つのクラスを関連付けしてあげることで無事参照することが出来ました。

いざデバッグしてみると、コンパイルエラーこそ出なかったものの、画面が固まってしまいました。これは当たり判定の処理を加えた直後に起こったことなので何が原因かは明らかですが、その対処法がいまいちわからないという状況です。

ソースコードです。

コード:

isHitCheck.h

#pragma once
#include "PlayerBullet01.h"
#include "PlayerBullet02.h"
#include "EnemyManager.h"

class HitCheck
{
	friend class EnemyManager;
 public:
	 HitCheck();
	 PlayerBulletCollection01* playerbullet01;
	 PlayerBulletCollection02* playerbullet02;
	 EnemyManager* enemy;
	 bool CircleCollision(double pc, double ec, double cx1, double cx2, double cy1, double cy2);
	 void CollisionAll();
	
};

isHitCheck.cpp

#include "isHitCheck.h"
#include "Define.h"

HitCheck::HitCheck()
{

}

bool HitCheck::CircleCollision(double pc, double ec, double cx1, double cx2, double cy1, double cy2)
{
	//仮引数は左から弾の半径、敵の半径、弾のx座標、敵のx座標、弾のy座標、敵のy座標
	double hlength = pc + ec;
	double xlength = cx1 - cx2;
	double ylength = cy1 - cy2;

	if(hlength * hlength >= xlength * xlength + ylength * ylength) {
		return true;
	}
	else {
		return false;
	}
}

void HitCheck::CollisionAll()
{
	float px, py, ex, ey; //判定処理をしたい弾と敵の座標
	//操作キャラの弾と敵との当たり判定
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < Define::PBULLET_NUM / 4; ++j) {
			if (playerbullet01->GetShotPosition(i, j, &px, &py)) {
				for (auto enemy : enemy->_list) {
					if (!enemy->GetDeadFlag()) {
						enemy->GetPosition(&ex, &ey);
						//当たり判定
						if (CircleCollision(Define::PSHOT_COLLISION, Define::ENEMY_COLLISION, px, ex, py, ey)) {
							//当たっていれば、deadflagを立てる
							enemy->SetDeadFlag();
							//当たった弾のフラグを戻す
							playerbullet01->SetShotFlag(i, j, false);
						}
					}
				}
			}
		}
	}
}
内容はほとんど前回と変わっていません。処理が固まってしまう原因として、for(auto enemy : enemy->_list)が無限ループになっているのではとも思いましたが、同じように記述した別のクラスではエラーが発生してないので、違うようです。

また、エネミー関連のソースコードも添付しておきます。ちょっと量が多いですが、、

コード:

AbstractEnemy.h

#pragma once

#include "Task.h"

class AbstractEnemy : public Task
{
public:
	AbstractEnemy(float x, float y);
	virtual ~AbstractEnemy() = default;
	void initialize();
	bool update() override;
	void SetDeadFlag() { deadflag = true;  }
	bool GetDeadFlag() { return deadflag; }
	bool GetPosition(float* x, float* y);

protected:
	virtual void setSize() = 0;

	float _x, _y; //座標
	float _speed; //速さ
	float _angle; //角度

	int _counter; //カウンタ
	int _width; //幅
	int _height; //高さ
	bool deadflag; //死亡フラグ
};

AbstractEnemy.cpp

#include "AbstractEnemy.h"
#include <DxLib.h>
#include "Image.h"
#include "Define.h"

AbstractEnemy::AbstractEnemy(float x, float y) :
	_x(x),
	_y(y),
	_speed(0),
	_angle(0),
	_counter(0),
	_width(0),
	_height(0)
{
}

void AbstractEnemy::initialize()
{
	setSize();
	deadflag = false;
}

bool AbstractEnemy::update()
{
	_counter++;
	_x += cos(_angle) * _speed;
	_y += sin(_angle) * _speed;
	return true;
}

bool AbstractEnemy::GetPosition(float* x, float* y)
{
	if (!deadflag) {
		*x = _x;
		*y = _y;
		return true;
	}
	else {
		return false;
	}
}

EnemyManager.h

#pragma once

#include "Task.h"
#include <memory>
#include <list>
#include "Enemy.h"
#include "isHitCheck.h"

class EnemyManager : public Task
{
	friend class HitCheck;
public:
	EnemyManager();
	virtual ~EnemyManager() = default;
	bool update() override;
	void draw() const override;
protected:
	std::list<std::shared_ptr<Enemy>> _list;
};

EnemyManager.cpp

#include "Enemymanager.h"
#include "Define.h"

using namespace std;

EnemyManager::EnemyManager()
{
	_list.emplace_back(make_shared<Enemy>(Define::CENTER_X, 100));
}

bool EnemyManager::update()
{
	for (auto enemy : _list) {
		enemy->update();
	}
	return true;
}

void EnemyManager::draw() const
{
	for (const auto enemy : _list) {
		enemy->draw();
	}
}

Enemy.h

#pragma once
#include "AbstractEnemy.h"

class Enemy final : public AbstractEnemy
{
public:
	Enemy(float x, float y);
	~Enemy() = default;
	void draw() const override;
protected:
	void setSize() override;
};

Enemy.cpp

#include "Enemy.h"
#include <DxLib.h>
#include "Image.h"
#include "Define.h"

Enemy::Enemy(float x, float y) : AbstractEnemy(x, y)
{
	deadflag = false;
	_speed = 2.0f;
	_angle = Define::PI / 2 - Define::PI / 5;
}

void Enemy::draw() const
{
	const int handle = Image::getIns()->getEnemyNormal()[4];
	if(!deadflag)
	    DrawRotaGraphF(_x, _y, 1.0, 0.0, handle, TRUE);
}

void Enemy::setSize()
{
	int handle = Image::getIns()->getEnemyNormal()[4];
	GetGraphSize(handle, &_width, &_height);
}
こちらでももう少し色々探ってみますが、もし明らかな欠陥やアドバイスなどありましたらご指摘いただけると幸いです。

ヨッシー
記事: 13
登録日時: 2年前

Re: 自機の弾と敵との当たり判定処理

#4

投稿記事 by ヨッシー » 2年前

質問なのですが、std::listに抽象クラスを用いることは可能でしょうか。現在はEnemyクラスをstd::listで管理していますが、Enemyクラスは抽象クラスであるAbstractEnemyを継承したものとなっています。

試しにstd::list<std::shared_ptr<AbstractEnemy*>> _listという風に変更してみると、

コード:

#include "Enemymanager.h"
#include "Define.h"

using namespace std;

EnemyManager::EnemyManager()
{
	_list.emplace_back(make_shared<AbstractEnemy*>(Define::CENTER_X, 100));
	for (auto enemy : _list) {
		enemy->initialize();
	}
}

bool EnemyManager::update()
{
	for (auto enemy : _list) {
		enemy->update();
	}
	return true;
}

void EnemyManager::draw() const
{
	for (const auto enemy : _list) {
		enemy->draw();
	}
}
このソースコードのfor文内のenemyに「式にはpointer-to-class型を使用する必要がありますが、型AbstractEnemy**が使用されています」と出てしまいました。その後enemyをenemy*に変えてみたりしましたがうまくいきませんでした。
重ねて言いますがstd::listに抽象クラスを用いる方法があれば教えてください。

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

Re: 自機の弾と敵との当たり判定処理

#5

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

ヨッシー さんが書きました:
2年前
質問なのですが、std::listに抽象クラスを用いることは可能でしょうか。
使えるようですね。

コード:

#include <iostream>
#include <list>
#include <memory>

struct AbstractClass {
	virtual ~AbstractClass(){}
	virtual void printName() const = 0;
};

struct ConcleteClass1 : public AbstractClass {
	void printName() const override {
		std::cout << "ConcleteClass1\n";
	}
};

struct ConcleteClass2 : public AbstractClass {
	void printName() const override {
		std::cout << "ConcleteClass2\n";
	}
};

int main(void) {
	std::list<std::shared_ptr<AbstractClass> > l;
	l.push_back(std::make_shared<ConcleteClass1>());
	l.push_back(std::make_shared<ConcleteClass2>());
	for (auto p : l) {
		p->printName();
	}
	return 0;
}
実行結果

コード:

ConcleteClass1
ConcleteClass2
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ヨッシー
記事: 13
登録日時: 2年前

Re: 自機の弾と敵との当たり判定処理

#6

投稿記事 by ヨッシー » 2年前

返信が遅くなってしまいすみません。
処理が止まってしまう原因を探ってみたところ、弾クラスやエネミークラスのインスタンス生成関連で問題があったようです。
原因が分かったので自己解決することが出来ました。ご相談に乗っていただきありがとうございました。
また何か出てきたら別のトピックで相談しようと思います。それでは。

返信

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