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

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

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

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

Q&A

3回答

5184閲覧

当たり判定クラスの作り方が知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

0グッド

0クリップ

投稿2021/06/01 08:40

編集2021/06/02 04:01

現状 [ 使い方はプレイヤークラス等のこのCollisionクラス変数を作ってプレイヤーの座標の変数のアドレスを変数に設定して
player->mCollision(enemy->mCollision);とすることで当たり判定の判定を隠してシンプルに位置を修正できます。 ]

問題 「 例えばenemy をベクターにした場合コピーコンストラクタでコピーされるためエネミー座標のアドレスを格納している変数が無効なアドレスになっています。現状これをUpdate();関数で毎フレーム設定することで修正しますがあまりい修正方法とは思えません。 」

やりたいこと「 どうすれば実装を隠した状態でやつコピーコンストラクタが動いても正常に座標を修正出来るのか知りたい。 」

Github: https://github.com/Shigurechan/Dungeon_Game/tree/43ddb23595d0b3498279c1b5c2acc2028521333b

cpp

1 //背景を初期化 2 for (int y = 0; y < STAGE_SIZE_HEIGHT; y++) 3 { 4 for (int x = 0; x < STAGE_SIZE_WIDTH; x++) 5 { 6 byte b = backStageBin.at(y * STAGE_SIZE_WIDTH + x); 7 //printf("%x\n",b); 8 switch (b) 9 { 10 //wall 11 case (int)BinType::Wall: 12 { 13 //std::cout << "あああ" << std::endl; 14 backStage->push_back(MapObject(windowContext, glm::vec2(x * CELL, y * CELL), uvSize.at((int)b), MapObject::ObjectType::Wall)); 15 backStage->back().setPosition(glm::vec2(x * CELL, y * CELL)); 16 } 17 break; 18 19 20 // 21 case (int)BinType::Ground_a: 22 { 23 //std::cout << "あああ" << std::endl; 24 backStage->push_back(MapObject(windowContext, glm::vec2(x * CELL, y * CELL), uvSize.at((int)b), MapObject::ObjectType::Ground)); 25 backStage->back().setPosition(glm::vec2(x * CELL, y * CELL)); 26 27 } 28 break; 29 30 31 // 32 case (int)BinType::Ground_b: 33 { 34 //std::cout << "あああ" << std::endl; 35 backStage->push_back(MapObject(windowContext, glm::vec2(x * CELL, y * CELL), uvSize.at((int)b), MapObject::ObjectType::Ground)); 36 backStage->back().setPosition(glm::vec2(x * CELL, y * CELL)); 37 38 } 39 break; 40 } 41 } 42 } 43

cpp

1#include "Collision.hpp" 2 3//コンストラクタ 4Collision::Collision(glm::vec2 s, bool frag) 5{ 6 size = s; 7 position = NULL; 8 isTrigger = frag; 9 speed = glm::vec2(0,0); 10 11} 12 13//判定を移動 14void Collision::setPosition(glm::vec2 *pos) 15{ 16 position = pos; 17} 18 19//判定サイズを変更 20void Collision::setSize(glm::vec2 s) 21{ 22 size = s; 23} 24 25//トリガータイプを変更 26void Collision::TriggerType(bool frag) 27{ 28 isTrigger = frag; 29} 30 31 32//当たり判定 33bool Collision::Intersect(std::shared_ptr<Collision> col) 34{ 35 36 //std::cout << col.getSize().x << std::endl; 37 //std::cout <<"ああああ: "<< col->getPosition().x << std::endl; 38 39 if (((col->getPosition().x + col->getSize().x) > position->x) && (col->getPosition().x < (position->x + size.x)) && 40 ((col->getPosition().y + col->getSize().y) > position->y) && (col->getPosition().y < (position->y + size.y))) 41 { 42 std::cout << "Collision !" << std::endl; 43 44 if (col->getTriggerType() == false) 45 { 46 glm::vec2 pos = *position + glm::vec2(CELL / 2, CELL / 2); //自分 47 glm::vec2 opponent = col->getPosition() + glm::vec2(CELL / 2, CELL / 2); //相手 48 49 const float vecX = pos.x - opponent.x; //負の値なら自分が左側 50 const float vecY = pos.y - opponent.y; //正の値なら自分が下側 51 52 //めり込み量の大きい方を補正する 53 if (std::abs(vecX) < std::abs(vecY)) 54 { 55 if (vecY > 0) 56 { 57 position->y = col->getPosition().y + col->getSize().y; 58 } 59 else if (vecY < 0) 60 { 61 position->y = col->getPosition().y - size.y; 62 } 63 } 64 else 65 { 66 if (vecX > 0) 67 { 68 position->x = col->getPosition().x + col->getSize().x; 69 } 70 else if (vecX < 0) 71 { 72 position->x = col->getPosition().x - size.x; 73 } 74 } 75 76 return true; 77 } 78 else 79 { 80 return true; 81 } 82 } 83 else { 84 return false; 85 } 86} 87 88 89//座標を取得 90glm::vec2 Collision::getPosition() 91{ 92 return *position; 93} 94 95//サイズを取得 96glm::vec2 Collision::getSize() 97{ 98 return size; 99} 100 101//トリガータイプを取得 102bool Collision::getTriggerType() 103{ 104 return isTrigger; 105} 106 107//移動速度設定 108void Collision::setSpeed(glm::vec2 s) 109{ 110 speed = s; 111} 112 113//移動速度取得 114glm::vec2 Collision::getSpeed() 115{ 116 return speed; 117} 118 119 120 121//デストラクタ 122Collision::~Collision() 123{ 124 125} 126

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/06/02 04:01

文章を修正しました。
退会済みユーザー

退会済みユーザー

2021/06/02 04:14

> 現状 [] > 問題 「」 > やりたいこと「」 上記のように括弧書きするぐらいなら、改行で区切るかMarkdownを使って書いてください
guest

回答3

0

回答へのコメントも見た感じでは「ヒットした位置も知りたいからpositionをポインタ型変数にしている」といったように解釈しました。
ただ、それだけであればCollisionクラスにhitPositionといった変数を別で生やすなりすればいいわけで、わざわざpositionを危険の多いポインタ型変数にする理由がないです。

軽くエスパーしてみますが、もしかして
MapObject::setPosition
で、受け取ったglm::vec2型の引数に&をつけてCollision::setPositionにわたしているのでは?
この場合引数の値は意図しているほど長生きしないので、参照するタイミング次第では不正なアクセスとなり得ます。

投稿2021/06/01 11:36

編集2021/06/01 11:42
S.Percentage

総合スコア283

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

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

S.Percentage

2021/06/02 04:42

回答したあとに質問がガッツリ修正されているのでコメントで追記しますが、positionの操作もCollisionモジュールの責務とするのは範囲が広すぎるのでやめたほうが良いかと思います。 positionはMapObject(やPlayer?)が管理し、Collisionの結果によってMapObject自身がpositionの修正を適用するかどうかを判断するようにしたほうが自然です。 なんでもかんでも隠蔽するのが正義というわけではないので、モジュールがやるべきことをもう一度考え直して設計し直すのをおすすめします。
fana

2021/06/02 06:00

見た感じ,Collisionというクラス自体に存在意義がなさそうなので, 衝突判定(と補正結果値の算出)に必要なデータを2つ受け取って,結果を返すだけの「関数」に挿げ替えるので事足りるように思いますね. 例えば,当たり判定が AABB であれば, AABBデータを2つ受け取って, 衝突の有無と,衝突した場合の位置補正のためのオフセット量 を返す,みたいな.
guest

0

話が全体的に意味不明なのですが,

Collision型のメンバpositionがポインタ型であることが問題を引き起こすという話なのであれば,
size やら speed とかと同じように,ふつーに glm::vec2 型にすれば根本的な問題を消滅せしむることができるんじゃないすか? とか思うのですが,どうですか?

position だけをポインタ型にする必要性があるようにも見えないのですが.

投稿2021/06/01 09:05

fana

総合スコア11729

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

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

退会済みユーザー

退会済みユーザー

2021/06/01 09:11

そうなのですがそうすると。どこで当たったものの座標を更新するのかわからなくなるのでポインタを使わざるおえないのです。
fana

2021/06/01 09:35

全くおっしゃっている意味がわからないです. そもそも その Collision なる型が なんのために,いつ時点で必要になって,どこまで生存してなきゃならないのか? とか,諸々の話は全てあなたしか知らないので,妥当な解決方法とかも判断つきませんし. 例えば, Collision::Intersect() という処理が Collision 型の主たる存在意義なのだとしたら, Collision::Intersect() を実施するときだけ存在していれば十分かもしれない. であれば,「必要なときに作って Intersect() を実行して,そこで破棄される」形で使うならば,「コピーコンストラクタがどうの」という問題自体が起きないかもしれない.
guest

0

Collision::positionをポインタでなく、実体を保持するようにすればよいのではないでしょうか。

backStage->back().setPosition(glm::vec2(x * CELL, y * CELL));

このsetPosition()がCollisionのメンバ関数ならスタック変数を渡しているのでスコープから抜けたときに
消滅してしまうのでCollisionのpositionは不定値になってしまいます。

投稿2021/06/01 08:58

tatamyiwathy

総合スコア1039

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

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

fana

2021/06/01 09:10

> このsetPosition()がCollisionのメンバ関数なら ひとつ前の行を見れば,これは MapObject::setPosition() の呼び出しだと見えます. そこから何がどう巡って Collision::setPosition() に行き着くのか(あるいは行き着かないのか)は全く提示されていません.
fana

2021/06/01 09:14

これはエスパーぎみな想像ですが > コピーコンストラクタが起きることで とか書かれているので,MapObject::setPosition() は,引数に指定された値をメンバにコピーする形にでもなっていて,そのメンバのアドレスを Collision::setPosition() に渡している とかじゃないでしょうか.
tatamyiwathy

2021/06/01 09:22

なるほど。確かにその構造だとCollision::positionをポインタにする気持ちもわからなくなないですねー
fana

2021/06/01 09:24

> 確かにその構造だとCollision::positionをポインタにする気持ちもわからなくなないですねー (そこは同意できないっす)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問