はじめまして。
こちらには初めて投稿させていただきます。
今、学校の課題でマリオ系の2Dのスクロールアクションゲームを作っています。
その中で、プレイヤーのキャラクターと敵キャラクターが衝突したら、敵キャラクターの生存フラグをFALSEに変更するという仕様があります。
当たり判定まではできたのですが、衝突したときに生存フラグを変更するところだけがうまくいかなくて困っています。
いろいろ試行錯誤してみたのですが、なかなかうまくいかないのでこちらで質問させていただきました。
ポインタの示しているアドレスがおかしい気がしていますが、どこがおかしいのでしょうか?
よろしくお願いいたします。
メイン
Player player;
EnemyManager enemyManager;
HitManager hitManager;
while (1) {
player.Update();
enemyManager.Update();
hitManager.CheckHitPlayerVsEnemy(player, enemyManager)
}
// 主人公
class Player {
public:
void Update() { キー操作や描画処理 }
}
// 敵キャラのクラス
class Enemy {
private:
bool isAlive;
public:
void SetIsAlive(bool alive) { isAlive = alive; }
}
// 敵キャラを扱うクラス
class EnemyManager {
private:
std::list<Enemy> enemies;
public:
void Update() { 敵キャラを生成してlistに入れたり、描画処理 }
std::list<Enemy> GetEnemies() { return enemies; }
}
// 当たり判定を行うクラス
class HitManager {
public:
void CheckHitPlayerVsEnemy(Player player, EnemyManager enemyManager);
}
void HitManager::CheckHitPlayerVsEnemy(Player player, EnemyManager enemyManager) {
std::list<Enemy> enemies = enemyManager.GetEnemies();
for (std::list<Enemy>::iterator it = enemies.begin();it != enemies.end();it++) {
Enemy* enemy = &*it;
if (主人公と敵キャラが当たっている) {
enemy.SetIsAlive(FALSE); // ここでenemyの生存フラグがFALSEになってほしいのに、変更されない
}
}
}
キャラクターの当たり判定について
Re: キャラクターの当たり判定について
見にくかったのでコード表記?にしました。
//メイン
Player player;
EnemyManager enemyManager;
HitManager hitManager;
while (1) {
player.Update();
enemyManager.Update();
hitManager.CheckHitPlayerVsEnemy(player, enemyManager)
}
// 主人公
class Player {
public:
void Update() { キー操作や描画処理 }
}
// 敵キャラのクラス
class Enemy {
private:
bool isAlive;
public:
void SetIsAlive(bool alive) { isAlive = alive; }
}
// 敵キャラを扱うクラス
class EnemyManager {
private:
std::list<Enemy> enemies;
public:
void Update() { 敵キャラを生成してlistに入れたり、描画処理 }
std::list<Enemy> GetEnemies() { return enemies; }
}
// 当たり判定を行うクラス
class HitManager {
public:
void CheckHitPlayerVsEnemy(Player player, EnemyManager enemyManager);
}
void HitManager::CheckHitPlayerVsEnemy(Player player, EnemyManager enemyManager) {
std::list<Enemy> enemies = enemyManager.GetEnemies();
for (std::list<Enemy>::iterator it = enemies.begin();it != enemies.end();it++) {
Enemy* enemy = &*it;
if (主人公と敵キャラが当たっている) {
enemy.SetIsAlive(FALSE); // ここでenemyの生存フラグがFALSEになってほしいのに、変更されない
}
}
}
Re: キャラクターの当たり判定について
オブジェクトを関数に渡して、状態を変更してもらうには、
ポインタもしくは参照を渡す必要があります。
メンバ関数の戻り値としてクラス外部にメンバー変数を公開する場合も、
受け取り先で、状態を変更す場合は、参照(or ポインタ)として返す必要があります。
最小限の修正としては、以下のようになるでしょうか。
ポインタもしくは参照を渡す必要があります。
メンバ関数の戻り値としてクラス外部にメンバー変数を公開する場合も、
受け取り先で、状態を変更す場合は、参照(or ポインタ)として返す必要があります。
最小限の修正としては、以下のようになるでしょうか。
//メイン
Player player;
EnemyManager enemyManager;
HitManager hitManager;
while (1) {
player.Update();
enemyManager.Update();
hitManager.CheckHitPlayerVsEnemy(player, enemyManager)
}
// 主人公
class Player {
public:
void Update() { キー操作や描画処理 }
}
// 敵キャラのクラス
class Enemy {
private:
bool isAlive;
public:
void SetIsAlive(bool alive) { isAlive = alive; }
}
// 敵キャラを扱うクラス
class EnemyManager {
private:
std::list<Enemy> enemies;
public:
void Update() { 敵キャラを生成してlistに入れたり、描画処理 }
/* コピーではなく参照を返す */
std::list<Enemy> &GetEnemies() { return enemies; }
}
// 当たり判定を行うクラス
class HitManager {
public:
/* コピーではなく参照を渡す */
void CheckHitPlayerVsEnemy(Player &player, EnemyManager &enemyManager);
}
/* コピーではなく参照を渡す */
void HitManager::CheckHitPlayerVsEnemy(Player &player, EnemyManager &enemyManager) {
/* コピーではなく参照を受取る */
std::list<Enemy> &enemies = enemyManager.GetEnemies();
for (std::list<Enemy>::iterator it = enemies.begin();it != enemies.end();it++) {
Enemy* enemy = &*it;
if (主人公と敵キャラが当たっている) {
enemy.SetIsAlive(FALSE); // ここでenemyの生存フラグがFALSEになってほしいのに、変更されない
}
}
}
Re: キャラクターの当たり判定について
a5uaさん
ご回答ありがとうございます。
受け渡し部分を変更したところ動くようになりました。
というのは一度試していて、「なんでポインタ返してるのにコピーになるんだ?」と思っていました。
HitManager::CheckHitPlayerVsEnemy() の引数のPlayerとEnemyManagerもポインタにするというのが抜けていたようです。
勉強になります。
>状態を変更す場合は、参照(or ポインタ)として返す必要があります。
参照 または ポインタ をということですが、「こういう場合は参照をかえしたほうが良い」「こういう場合はポインタをかえしたほうが良い」という判断がまだ明確にできていないです。
今回のようなプログラムではどちらを使っても動作は変わらないですし。
参照とポインタの使い分けの基準ってあるのでしょうか?
よろしくお願いいたします。
ご回答ありがとうございます。
受け渡し部分を変更したところ動くようになりました。
というのは一度試していて、「なんでポインタ返してるのにコピーになるんだ?」と思っていました。
HitManager::CheckHitPlayerVsEnemy() の引数のPlayerとEnemyManagerもポインタにするというのが抜けていたようです。
勉強になります。
>状態を変更す場合は、参照(or ポインタ)として返す必要があります。
参照 または ポインタ をということですが、「こういう場合は参照をかえしたほうが良い」「こういう場合はポインタをかえしたほうが良い」という判断がまだ明確にできていないです。
今回のようなプログラムではどちらを使っても動作は変わらないですし。
参照とポインタの使い分けの基準ってあるのでしょうか?
よろしくお願いいたします。
Re: キャラクターの当たり判定について
参照は以下の特徴を持っています。機能限定版のポインタとも言えます。
・間接演算子(*←これ)で参照はがしをする必要がない
・NULLにはなれない
・再代入ができない
したがって、参照自体を書き換える必要がなく、NULL(何も指していない状態)が不要ならば、参照を使えば良いです。
ほとんどの場合、参照で事足りると思うので、基本的に参照を使うようにしておき、
参照では実現できないケースのときのみ、ポインタを使うようにすれば良いと思います。
・間接演算子(*←これ)で参照はがしをする必要がない
・NULLにはなれない
・再代入ができない
したがって、参照自体を書き換える必要がなく、NULL(何も指していない状態)が不要ならば、参照を使えば良いです。
ほとんどの場合、参照で事足りると思うので、基本的に参照を使うようにしておき、
参照では実現できないケースのときのみ、ポインタを使うようにすれば良いと思います。
Re: キャラクターの当たり判定について
参照とポインタの使い分けですが、私は関数の引数として使った時の違いを基準にしています。
int型の変数を 値渡し、参照、ポインタで引数を受け取る三種類の関数を例にするとそれぞれ
と書くことになります。このとき、呼び出し側からは a を渡すか &a を渡すかの違いですが
func2は参照渡しなので a の内容を変更することができます。
よってfunc2に渡される a の値は1ですがfunc3に渡される a はfunc2で変更されている可能性があります。
この、参照渡しによる呼び出し側から気がつき辛い値の変更が嫌なので私は
参照は値を変更しない且つコピーするには大きな構造体などを扱う場合に使う(constをつける)
ポインタは値を変更する場合に使う というようにして
変数の値の変動に注意して利用するようにしています。
int型の変数を 値渡し、参照、ポインタで引数を受け取る三種類の関数を例にするとそれぞれ
void func1(int);
void func2(int&);
void func3(int*)
int main()
{
int a=1;
func1(a); // 値渡し
func2(a); // 参照渡し
func3(&a); // ポインタ渡し
…
…
…
}
func2は参照渡しなので a の内容を変更することができます。
よってfunc2に渡される a の値は1ですがfunc3に渡される a はfunc2で変更されている可能性があります。
この、参照渡しによる呼び出し側から気がつき辛い値の変更が嫌なので私は
参照は値を変更しない且つコピーするには大きな構造体などを扱う場合に使う(constをつける)
ポインタは値を変更する場合に使う というようにして
変数の値の変動に注意して利用するようにしています。