質問するログイン新規登録
C++

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

DXライブラリ

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

Q&A

解決済

3回答

3297閲覧

2Dアクションゲーム 下からブロックを叩いた時の判定を認識するアルゴリズムを知りたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

DXライブラリ

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

0グッド

0クリップ

投稿2020/02/23 07:05

編集2020/02/25 01:03

0

0

点と線の交差判定を使った当たり判定を実装したのですが提示画像の青色で囲ったところつまり天井ブロックとぶつかった時の処理を実装したいです。
条件としてはY軸にジャンプやらしてる時でX軸に移動している時つまり左右に移動しているときに青色で囲ったところに当たるとX軸が先に修正されてしまいぶつかったブロックの端に移動してしまうというバグをを修正したいです。タイトル通り下からブロックを叩いたということを認識できればその時にY軸だけ修正するというコードの実装することがで実現できると思うのですが....
質問1「動いた方向の逆方向に修正するコードはどうすれば実装できるのか手法が知りたい」

イメージ説明

/*当たり判定処理 関数*/ void Game::Collision_Update() { /* NOTE プレイヤーの中心と当たり側の座標の中心で判定する。 */ Position *Result = NULL; float offset_x = 0; float offset_y = 0; bool NoCol_x = true; bool NoCol_y = true; /*移動方向によって異なる*/ if(p->speed->x > 0)//右 { offset_x = ( p->CELL + p->speed->x ); }else if (p->speed->x < 0)//左 { float t = (p->CELL) * - 1;//符号を逆にするマイナス offset_x = (t + p->speed->x); // ofs<<offset_x<<std::endl; }else{ offset_x = 0; } //if(action == keyState::Jump) if(p->speed->y < 0)/*ジャンプ*/ { float t = p->CELL * -1; offset_y = t + p->speed->y; ofs<<"offset_y: "<<offset_y<<std::endl; //}else if (action == keyState::Down) }else if (p->speed->y > 0) {/*落下*/ offset_y = ((p->CELL) + p->speed->y); //ofs<<offset_y <<std::endl; } /************************************************当たり判定***********************************************************************/ for (int y = 0; y < m->height; y++) { for (int x = 0;x < m->width; x++) { Mapchip *mp = m->isMapObject(x, y); if (mp != NULL) { float Fix_x_up = -1; float Fix_x_down = -1; float Fix_y_left = -1; float Fix_y_right = -1; /* X 軸 */ Position now_x_up(p->pos->x + ((p->CELL / 2) - 1), p->pos->y); Position future_x_up((p->pos->x + ((p->CELL / 2) - 1)) + offset_x, p->pos->y); Position now_x_down(p->pos->x + ((p->CELL / 2) - 1), (p->pos->y + (p->CELL - 1))); Position future_x_down((p->pos->x + ((p->CELL / 2) - 1)) + offset_x, (p->pos->y + (p->CELL - 1))); DrawFormatString(400, 400, GetColor(255, 255, 255), "Collisition",true); int r = cross_pos(&Result, now_x_up, future_x_up, Position(mp->get_X() + ( (mp->size_width / 2) - 1), mp->get_Y() + mp->size_height), Position((mp->get_X() + mp->size_width) + ((mp->size_width / 2) - 1), (mp->get_Y() + mp->size_height ) - 1 )); if( r != 0) { NoCol_x = false; DrawFormatString(400, 400, GetColor(255, 255, 255), "                         now_x_up", true); if(p->speed->x > 0){ Fix_x_up = (int)Result->x - ( (p->CELL - 1) + (p->CELL /2) ); }else if(p->speed->x < 0) { Fix_x_up = (int)Result->x + (p->CELL / 2) + 1; // Fix_x_up = Result->x + 1; } ofs << "pos_up : " << Fix_x_up << std::endl; delete(Result); Result = NULL; } /*地面に居ない時*/ if(p->isGround == false){ r = cross_pos(&Result, now_x_down, future_x_down, Position(mp->get_X() + ((mp->size_width / 2) - 1), mp->get_Y()), Position(mp->get_X() + ((mp->size_width / 2) - 1), (mp->get_Y() + mp->size_height) - 1)); if (r != 0) { NoCol_x = false; DrawFormatString(400, 500, GetColor(255, 255, 255), "now_x_down", true); if (p->speed->x > 0) { Fix_x_down = (int)Result->x - ((p->CELL - 1) + (p->CELL / 2)); //Fix_x_down = now_x_down.x; }else if (p->speed->x < 0) { Fix_x_down = (int)Result->x + (p->CELL / 2) + 1; //Fix_x_down = now_x_down.x; } ofs << "pos_down : " << Fix_x_down << std::endl; delete(Result); Result = NULL; } } /*X 補正*/ if (Fix_x_up != -1 || Fix_x_down != -1) { if (p->speed->x > 0)/*右*/ { if (Fix_x_up == -1) { p->pos->x = Fix_x_down; } else if(Fix_x_down == -1) { p->pos->x = Fix_x_up; } else { if (Fix_x_up < Fix_x_down) { p->pos->x = Fix_x_up; } else { p->pos->x = Fix_x_down; } } } else if (p->speed->x < 0)/*左*/ { if (Fix_x_up == -1) { p->pos->x = Fix_x_down; } else if (Fix_x_down == -1) { ofs << "col" << std::endl; p->pos->x = Fix_x_up; } else { if (Fix_x_up < Fix_x_down) { p->pos->x = Fix_x_down; } else { p->pos->x = Fix_x_up; } } } } /*********************************************** Y軸 *************************************************************************************/ /* Y 軸 値設定*/ ofs<<"pos: " << p->pos->x<<std::endl; Position now_y_left(p->pos->x, p->pos->y + ((p->CELL / 2) - 1)); Position future_y_left(p->pos->x, (p->pos->y + (p->CELL / 2) - 1) + offset_y); Position now_y_right(p->pos->x + (p->CELL - 1), p->pos->y + ((p->CELL / 2) - 1)); Position future_y_right(p->pos->x + (p->CELL - 1), (p->pos->y + (p->CELL / 2) - 1) + offset_y); // ofs << "left: " <<future_y_left.y << std::endl; // ofs << "right: " <<future_y_right.y << std::endl; r = cross_pos(&Result,now_y_left,future_y_left, Position(mp->get_X(), mp->get_Y() + (mp->size_height / 2) - 1), Position(mp->get_X() + ((mp->size_width) - 1), mp->get_Y() + (mp->size_height / 2) - 1)); if(r != 0) { NoCol_y = false; DrawFormatString(350, 600, GetColor(255, 255, 255), "now_y_left", true); // ofs<<"y_col left"<<std::endl; /*落下*/ if (p->speed->y > 0) { Fix_y_left = (Result->y - ((p->CELL) + ((p->CELL / 2)) - 1)); //ofs << Fix_y_left->y << std::endl; // p->speed->y = 0; /* 補正座標がおかしくなってる書き間違てた。 */ p->isGround = true; p->isJump = false; } /*ジャンプ*/ else if (p->speed->y < 0) { //p->speed->y = 0; Fix_y_left = (Result->y + (p->CELL / 2) + 1); ofs<<Fix_y_left<<std::endl; } delete(Result); Result = NULL; } r = cross_pos(&Result, now_y_right, future_y_right, Position(mp->get_X(), mp->get_Y() + (mp->size_height / 2) - 1), Position(mp->get_X() + (mp->size_width - 1), mp->get_Y() + (mp->size_height / 2) - 1)); if (r != 0) { // ofs << "y_col right" << std::endl; NoCol_y = false; DrawFormatString(350, 300, GetColor(255, 255, 255), "now_y_right", true); /*ジャンプ*/ if(p->speed->y < 0) { Fix_y_right = (Result->y + (p->CELL / 2) + 1); ofs << Fix_y_right << std::endl; // p->speed->y = 0; /*落下*/ }else if (p->speed->y > 0) { // p->speed->y = 0; Fix_y_right = (Result->y - ((p->CELL) + ((p->CELL / 2)) - 1)); p->isGround = true; p->isJump = false; // ofs << Fix_y_right->y << std::endl; } } /* Y 補正 */ if(Fix_y_left != -1 || Fix_y_right != -1) { /*落下*/ if(p->speed->y > 0){ p->speed->y = 0; //ofs<<"GGG"<<std::endl; if(Fix_y_left == -1) { p->pos->y = Fix_y_right; }else if(Fix_y_right == -1) { p->pos->y = Fix_y_left; }else{ if(Fix_y_left < Fix_y_right) { p->pos->y = Fix_y_left; }else{ p->pos->y = Fix_y_right; } } /*ジャンプ */ }else if (p->speed->y < 0) { p->speed->y = 0; if (Fix_y_left == -1) { p->pos->y = Fix_y_right; } else if (Fix_y_right == -1) { p->pos->y = Fix_y_left; } else { if (Fix_y_left < Fix_y_right) { p->pos->y = Fix_y_right; } else { p->pos->y = Fix_y_left; } } } } } } } if(NoCol_x == true) { float xx = p->speed->x; p->pos->x += xx; } if (NoCol_y == true) { float yy = p->speed->y; p->pos->y += yy; } } /****************************************************************************************************************************/

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

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

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

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

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

stdio

2020/02/24 00:39

衝突判定が出来ているかつプログラムを拝見する限り、マリオのジャンプも出来ているなら、後は発想力でなんとか出来る気がします。逆に言えばその程度の発想力もなければこの先のゲームを開発するのは辛いということです。 突き放すようで申し訳ございませんが、この程度の試練も乗り越えられないようではマリオを中途半端に作っただけで、諦めた方がいいと思います。
nskydiving

2020/02/24 02:10

>タイトル通り上からブロックを叩いたということを認識できれば 「上から」は「下から」の誤りではないでしょうか?
退会済みユーザー

退会済みユーザー

2020/02/25 01:43

はい。誤字です修正しました。
guest

回答3

0

ひとまず「下からたたいた」として考えますね。
あと、この手のやつに「正解」ってないので、より良い解決策がどこかにあるかもしれません。
コード見る限り、X軸判定を先にしていて、左右に速度があるときに補正をかけているため、このような事が起きていると考えられます。

恐らく順序を入れ替えても逆の問題が起きるだけだと思います。

ということで、スピードではなく「めり込み量」で考えてみます。XとYのどちらに押し戻せば(補正すれば)、自然に見えるのかを考えると、めり込み量が少ない方です。

ということで、めり込み量をXとYで比較して、絶対値が小さい方に押し戻します。ただしこの方法ですと、ブロックの継ぎ目でおかしなことになります。

このため複数のブロックに対しての当たり判定を見て、トータルでめり込みの少ない方に押し戻します。

と、言う感じのアルゴリズムでいかがでしょうか(即興で考えましたが…)

投稿2020/02/24 15:31

CTsuchinoko

総合スコア28

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

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

退会済みユーザー

退会済みユーザー

2020/02/24 18:20

質問ですが移動方向と逆方向に補正したいのですがどうすればいいのでしょうか?
guest

0

ベストアンサー

当たった時にy軸が上に上がっているとき(ジャンプ中とか)でp->speed->y =0 ;にしてもX軸が反応してしまうのはぴったり合っているようで実は一瞬1ドット分重なっているがためにX軸が反応してブロックの端に移動してしまってました。 自己解決です~♪

/*ジャンプ中の場合*/ p->pos->y = Result->y + (p->CELL / 2) + 1; p->speed->y = 0;

投稿2020/02/25 02:33

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

上から、あるいは下からブロックに接触したかどうかは、直前のキャラクターの移動増分がどちら方向を向いているかで分かるのでは?(あとは接触した座標も)

あとは補正を各軸ごとにやるのではなく、計算だけしておいて(各々の計算は計算結果の前の状態を利用して行う)、一括で補正すれば順序を気にする必要もなくなりそうですが。

投稿2020/02/24 23:42

tacsheaven

総合スコア13707

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

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

退会済みユーザー

退会済みユーザー

2020/02/25 01:10

X軸はキャラ上と下の真ん中でY軸もキャラの両端なのですが一体どうすればいいのでしょうか?当たった方向はp->speed を使って向きを取得することができるので問題ないのですがぶつかった座標をResultで取得してそこからどうすればいいのかわかりません。
tacsheaven

2020/02/25 01:36

そもそも当たったときにどうしたいのでしょうか? スーパーマリオブラザーズと同じような挙動だとすれば、ジャンプして当たった場合は Y 軸方向の加速度が 0 になります(めり込み補正の座標補正は別計算)。 しかし、その次の瞬間に「キャラクターの下が地面でも障害物でもない」ので、落下する(Y軸方向のプラス加速度が発生する)はずです。 そこの処理が抜けていませんか?
退会済みユーザー

退会済みユーザー

2020/02/25 02:04

えっwということはp->speed->y = 0;のような処理が必要ということでしょうか? まためり込み量の修正はResultに当たった座標が返ってくるのでその座標にキャラの大きさ分を足し引きしているのですがこれはどうなのでしょうか?
tacsheaven

2020/02/25 02:10

むろん、あたった状況によっては Y 軸方向の加速度補正は必要ないかも知れません。巨大マリオで破壊可能なブロックなら破壊してそのまま上昇を続けるでしょうし、破壊不可能だったり小さいマリオなら跳ね返されるでしょ? それらも加味して加速度を設定してやらねばなりません。その判定は衝突時に行うしかないのですよ。
退会済みユーザー

退会済みユーザー

2020/02/25 02:21 編集

ちなみになのですが線と線の交差判定を使ったこのやり方?実現できるのでしょうか? またXとYを別で考えてXが当たってないのでyを見てYを補正してp->speed->y = 0;という処理を書いてみましたがはやり当たったブロックの一番端に移動するというバグが治りません。
tacsheaven

2020/02/25 02:21

交差判定を使ったとしても、結局は「どのブロックと衝突したのか」は分かるでしょ?(衝突座標からそこにあるはずのオブジェクトを、マップデータ及びモンスターの位置情報を元に決定する) 逆にそれが分からなかったら、何と衝突したのかどうやって判断するつもりなのです?
退会済みユーザー

退会済みユーザー

2020/02/25 02:29

YだけXだけとかだったらもう完成してるのであとはそれを上手く組み合わせるだけでもう少しなんですよね。衝突座標がわかったのでそこに書き換えてその上でy軸に動いていたらその逆の方向にキャラの大きさ分補正してっていう感じの処理を書いてまして....なぜブロックの端に移動してしまうのでしょか?p-.>speed->y = 0;をしているので当たった瞬間からX軸は次のセル探索で当たってないと思うのですがw
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問