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

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

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

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

DXライブラリ

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

Q&A

解決済

3回答

1948閲覧

Dxlib 左右だけの当たり判定を作りたいそれと別に落下時の座標修正の当たり判定を別に作りたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

DXライブラリ

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

0グッド

1クリップ

投稿2019/08/21 21:36

編集2019/08/22 05:49

Map.cppのコメント部のここですのコード部分なのですが落下時の座標を修正するコードですが左右に動いてる時も値が修正されてしまいブロックの上に上がってしまいます。これをどうしたら上から落下した時だけの落下時の時だけに修正できるのでしょうか?
y座標だけ見て前の座標を違う場合のみ実行したいのですが上手く来ません
※マリオ風アクションゲーム

Map.cpp

#include "Map.h" #include <fstream> #include "Position.h" #include "Block.h" #include <optional> #define CELL 64 #define MAP_WIDTH 20 #define MAP_HEIGHT 11 static std::ofstream ofs("Log.txt"); enum class mapChip { eBrick = 5, eQuestion = 0, eNo = -1, }; int Map::map_set[MAP_HEIGHT][MAP_WIDTH] = {//番号管理 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,0,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,0-11,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1}, }; /*マップセルのオブジェクト数を返す関数*/ int Map::getCount_mapCell(int n) { return -1; } /*コンストラクタ*/ Map::Map() { /*画像設定*/ for (int y = 0; y < 11; y++) { for (int x = 0; x < 20; x++) { if (get_mapCell(x,y) == (int)mapChip::eQuestion) { //画像ファイル名、座標、画像の横枚数、縦枚数、最初の画像 bmap_set.push_back(Block("mario_resource/Block_64px.png",Position(x * 64,y * 64),10,4, (int)mapChip::eQuestion)); } if (get_mapCell(x, y) == (int)mapChip::eBrick) { //画像ファイル名、座標、画像の横枚数、縦枚数、最初の画像 bmap_set.push_back(Block("mario_resource/Block_64px.png", Position(x * 64, y * 64), 10, 4, (int)mapChip::eBrick)); } } } } int Map::get_mapCell(int& x, int& y) { return map_set[y][x]; } /*描画 更新*/ void Map::Draw_Update() { for (int i = 0; i < bmap_set.size(); i++) { bmap_set[i].Draw_Update(); } } /*全方位の当たり判定 return セル番号を返す*/ std::optional<Position> Map::Collision::player_col(const Position *pos) { for (int y = 0; y < MAP_HEIGHT; y++) { for (int x = 0; x < MAP_WIDTH; x++) { if (get_mapCell(x, y) == (int)mapChip::eBrick || get_mapCell(x, y) == (int)mapChip::eQuestion) { if ( (pos->get_x() < (x * CELL) && pos->get_x() + CELL >= (x * CELL) || pos->get_x() > (x * CELL) && pos->get_x() <= (x * CELL) + CELL) && (pos->get_y() < (y * CELL) && pos->get_y() + CELL >= (y * CELL) || pos->get_y() > (y * CELL) && pos->get_y() <= (y * CELL) + CELL) ) { ofs<< "player_col()\n"; std::optional<Position> p = Position(x, y); return p.value();//セルを返す // return true; } } //pos->get_x() <= (x * CELL) && pos->get_x() + CELL >= (x * CELL) } } return std::nullopt; } /*計算 更新*/ void Map::Update() { /* int idx = 0; for (int i = 0; bmap_set.size(); i++) { } */ for (int i = 0; i < bmap_set.size(); i++) { bmap_set[i].Update(); } //bmap_set[0].Update(); //bmap_set[0].Debug_Log(); //Block b("mario_resource/Block_64px.png", Position(1 * 64, 1 * 64), 10, 4, 5); //b.Debug_Log(); //std::ofstream ofs("Log.txt"); // ofs << bmap_set.size(); for (int y = 0; y < 11; y++) { for (int x = 0; x < 20; x++) { if (get_mapCell(x,y) == 0) { //idx += 1; //bmap_set[y][x]->Update_changeAnime(anime_s::ewait); //bmap_set[idx].Update(); } if (get_mapCell(x, y) == 5) { //idx += 1; //画像ファイル名、座標、画像の横枚数、縦枚数、最初の画像 //bmap_set[idx].Update(); } } } } //////////////////////////////////////////////////////ここのコード //引数は今の座標と前の座標 std::optional<Position> Map::Collision::under_col(const Position *pos,const Position *prev)//下の当たり判定 { if (Map::Collision::player_col(pos) != std::nullopt) { if (pos->get_y() > prev->get_y()) { std::optional<Position> p = Map::Collision::player_col(pos); p->new_pos_x(p->get_x() * CELL); p->new_pos_y((p->get_y() * CELL) - CELL); return p.value(); // return //return true; } else { return std::nullopt; } } else { return std::nullopt; } }

Player.cpp

#include <iostream> #include <fstream> #include "Input.h" #include "Player.h" #include "DxLib.h" #include "Map.h" #include "Animation.h" #define MOVE_SPD 5 #define JUMP_FORCE 4.0624 * 3 static std::ofstream ofs("Log.txt"); /*コンストラクタ*/ Player::Player(const char* str, int xx, int yy) { //LoadDivGraph(str,7,7,1,64,64,g_handle); AnimeClip = new Animation(anime_s::ewait,str,7,7,1); pos = new Position(); prev = new Position(); AnimeClip->setAnime(anime_s::ewalk,1,3,3); AnimeClip->setAnime(anime_s::ewait, 0, 0, 1); AnimeClip->setAnime(anime_s::ejump, 5, 5, 1); } /*計算更新*/ void Player::Update() { input_key(); jump_up(); //side_move();// gravity(); AnimeClip->Update(); DrawFormatString(100, 200, GetColor(255, 255, 255), "isGround %d", isGround); DrawFormatString(100, 280, GetColor(255, 255, 255), "isJump %d", isJump); *prev = *pos; } /*描画更新*/ void Player::Draw_Update() { if ( key == -1) { //DrawTurnGraph(get_x(), get_y(), g_handle[0], true); /////// DrawTurnGraph(pos->get_x(), pos->get_y(), AnimeClip->draw_setClip(), true); } /*右→*/ if (key == 1) { /// DrawGraph(pos->get_x(), pos->get_y(), AnimeClip->draw_setClip(), true); } AnimeClip->Draw_Update(); } /*キー入力*/ void Player::input_key() { if (keybord(KEY_INPUT_LEFT) > 0)//← { key = -1; AnimeClip->Update_changeAnime(anime_s::ewalk,key); pos->set_x(-MOVE_SPD); }else if (keybord(KEY_INPUT_RIGHT) > 0)//→ { key = 1; AnimeClip->Update_changeAnime(anime_s::ewalk,key); pos->set_x(+MOVE_SPD); }else if (keybord(KEY_INPUT_UP) > 0)//上 { pos->set_y(+MOVE_SPD); }else if (keybord(KEY_INPUT_DOWN) > 0)//下 { pos->set_y(-MOVE_SPD); } else if (keybord(KEY_INPUT_SPACE) > 0)//ジャンプ { //AnimeClip->Update_changeAnime(anime_s::ejump); //if(Map::Collision::under_col(pos->refget_x(), pos->refget_y()) == false) if (isGround == true && jf == 0) { //isJump = true; isGround = false; jf = JUMP_FORCE; } AnimeClip->Update_changeAnime(anime_s::ejump); } else//何も押していない時 { AnimeClip->Update_changeAnime(anime_s::ewait); } } /************************ジャンプ ***********************/ void Player::jump_up() { pos->set_y((int)jf); //if (Fps::gframe() % 20 == 0) { jf = ((jf -0.126953125f * 3.0f)); if (jf < -0.126953125f * 3.0f * 10.0f) { jf = -0.126953125f * 3.0f * 10.0f; //pos->set_y(); } //} } /*********************************************************/ /***********************重力*******************************/ void Player::gravity() { //落下 if (Map::Collision::under_col(pos, prev) == std::nullopt && isGround == false) { //DrawFormatString(200, 200, GetColor(255, 255, 255), "x %d", pos->get_x()); pos->set_y((int)jf); jf = ((jf -0.126953125f * 3.0f)); if (jf < -0.126953125f * 3.0f * 10.0f) { jf = -0.126953125f * 3.0f * 10.0f; //pos->set_y(); } } /*地面着地*/ if (Map::Collision::under_col(pos, prev) != std::nullopt && jf < 0) { DrawFormatString(200, 280, GetColor(255, 255, 255), "y %d", pos->get_y()); std::optional<Position> p = Map::Collision::under_col(pos, prev); pos->new_pos_y(p->get_y()); ofs << "under_col true\n"; } else { DrawFormatString(200, 280, GetColor(255, 255, 255), "y %d", pos->get_y()); ofs << "under_col" <<pos->get_y()<<"\n"; } } /**********************************************************/

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

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

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

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

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

guest

回答3

0

ベストアンサー

あなたのコードに今々適用できる話ではない(=回答とはならない)かもしれませんが……

  • 落下中にブロックに当たったら→ブロックの上に上げる
  • 落下中じゃないときにブロックに当たったら→……

みたいな考え方が物事を複雑にしている(バグる原因)と思います.

どんな向きに運動していようが,接地していようがいまいが「衝突した場所の法線方向に対して座標を補正する」で一律的に扱えば不要な混乱が生じないのではないでしょうか.

投稿2019/08/22 11:11

fana

総合スコア11654

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

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

fana

2019/08/22 11:11

あと,「埋まったから」→「辻褄が合うように座標を補正する(押し出す)」という考え方よりも, 「そもそも埋めない」=「どこまで移動できるかを求めてそこまで移動する」という方向で考えた方が楽なんじゃないかなぁ,とか.
退会済みユーザー

退会済みユーザー

2019/08/22 11:14

正直なところ考え方と解決法がわかりません一日中悩みましたがどうすればいいのでしょうか? 実装が思いつきません。
fana

2019/08/22 11:29

まずは一度,絵を描くなりして,本当にやるべきことのイメージをしっかり掴むことが必要なのではないかと想像します. □ ← コレが自由な方向に移動するとしましょう. 例えば,この□が右下方向に距離5だけ移動しようとする場面を考えます. その移動経路がブロックに衝突してしまうパターンを色々考えてみてください. (A)□の底辺が□よりも下にあるブロックに「着地」する形で衝突するのかもしれませんし, (B)□の右上隅あたりがブロックの左下らへんに当たるのかもしれません. (C)... 右下に行こうとする□の運動は,あなたのコードの世界では「落下中」に相当するのかもしれませんが,(B)の場合,当たったブロックの上に□が乗り上げるのが果たして正しいでしょうか?
fana

2019/08/22 11:36

Map::Collision::player_colを見た感じだと,ある1点の座標がブロックのどれかの内部にあるかどうかに関して判定を行っているように見えます. 「座標がブロックの内側に入った」とだけ判定できたとして,その後の対応を正しく行えるものでしょうか? ↑のコメントの例で,□の右下の角があるブロックの内側に入り込んだとわかった場合,どうしますか? ブロックの上辺側から入り込んだならば,□はそのブロックの上に着地するのでしょうが, ブロックの左辺側から入り込んだ場合でも同じでしょうか? 回答で「法線」とか書いているのはそういう意味です. あなたが意図する挙動を表現するのには,今の実装では絶対的に情報なり処理なりが足りていないのではありませんか?
退会済みユーザー

退会済みユーザー

2019/08/22 11:40

どんな数学を使えばいいかわかりますか?
退会済みユーザー

退会済みユーザー

2019/08/22 11:42

ブロックのどこに合ったったらという上下右左で個別の判定を作るにはどうすればいいのでしょうか?
fana

2019/08/22 11:52

> どんな数学 何やらふわっとした表現ですが… 他の方の回答にあるリンク先の話程度の数学,じゃないですかね. リンク先の話をざっと見ると衝突時刻tを求めるような話みたいですよ. tが算出できるならば,その時点でどこがどう当たったかはわかるでしょうし, 私の最初のコメントで言うところの「そもそも埋めない」話ができますね.(残りの(1-t)分の移動量を好きに処理してしまえばいい.衝突面の接方向成分だけを残すとか)
fana

2019/08/22 11:57

> 「そもそも埋めない」… (時間1の間に)右下方向に距離5だけ移動しようとする場合,経過時間t=0.6の時点で初めて何かに衝突するとわかったならば,そこまでは動いていい(この時刻で何かに「接する」)のだから,あとは残りの時間0.4の分の処理をどうするかって話ね.
退会済みユーザー

退会済みユーザー

2019/08/22 11:57

参考リングがちょっと何言ってるかわからないので質問したのですが...どう実装したらいいかわからないのですw色々で噛み合わないとうか...
fana

2019/08/22 12:04

それは困りましたね. リンク先のような話がわからない状態でゲームを作るのはとても厳しいのではないでしょうか……
退会済みユーザー

退会済みユーザー

2019/08/22 12:07

四角同士の判定でシューティングの当たり判定のような物だったら自分のちからで作れるのですけどこのゲームの場合座標の補正をする時に別の物など動いてしまい困っています。
fana

2019/08/23 02:24

処理効率が悪くて結果精度が悪いけども,とりあえず難しいことを考えなくて済む方法としては, 「距離5だけ移動する」というのを一気に処理せずに,細かく刻む(距離1ずつ5回にわける,距離0.5ずつ10回にわける)みたいな方法があります. 例えば0.5ずつ動かしてみると6回目まではブロックにめり込まず,7回目の時点でめり込むならば,(7回目の移動は捨てて)6回目の結果位置を移動結果としてしまう. 方法としては雑で,結果は「過剰に押し出した」結果となりますが,(見た目に1pixelのずれが生じないならOKみたいな世界なら)刻み量が十分小さければ問題のない誤差量だとして許容してもよいでしょう.
guest

0

1、左右だけの当たり判定を作りたい

点と直線の衝突判定が必要になりますね。回転を考慮に入れていないなら比較だけで可能ですよ。

2、落下時の座標修正の当たり判定を別に作りたい

衝突判定で必要なのは当たったかの他にどれだけ埋まっているかを知る必要があります。
こちらで詳しく解説されています。

投稿2019/08/22 09:12

stdio

総合スコア3307

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

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

退会済みユーザー

退会済みユーザー

2019/08/22 10:48

こちらのURLがどんな内容かわからないのですがこの場合はつまりどうすればいいのか教えてくれますでしょか?
退会済みユーザー

退会済みユーザー

2019/08/22 10:57

落下時の座標補正ですが当たったらその一つ上のマス目に上がればいいのはわかるのですが左右の補正と一緒にやってしますと真横に移動したときにそのブロックの上に上がってしまうですがそのあたりはどうすればいいのでしょうか?
stdio

2019/08/23 00:37

リンク先のURLはAABBという回転を考慮に入れていない四角形の事です。 > つまりどうすればいいのか教えてくれますでしょか? 厳しい意見ですが、少しは自分で考える、調べるということをしましょう。 > 真横に移動したときにそのブロックの上に上がってしまう それは単なる貴方のミスですね。衝突判定のコードは本来一つでいいはずです。 std::optional<Position> Map::Collision::player_col(const Position *pos)の戻り値をどの方向から衝突したかを返すようにすれば、上に行くなんてことはなくなると思います。
退会済みユーザー

退会済みユーザー

2019/08/23 12:08

初歩的な質問ですが当たった方向がどの方向から当たったかを見るにはどのようなことをすればいいのでしょうか?当たった場合は作れますが方向というのが困っています
episteme

2019/08/23 12:14 編集

俺を原点とした相手ベクトルの向きだろね
退会済みユーザー

退会済みユーザー

2019/08/23 13:28

距離の求めた方などはhttp://www.sousakuba.com/Programming/gs_vector.html ありますが プログラミングで向きを検出するにはどうすればいいのでしょうか?
episteme

2019/08/23 13:38

位置ベクトル(x,y)がわかってるなら atan2(x,y) で角度が(radian単位で)求まる。
退会済みユーザー

退会済みユーザー

2019/08/23 14:18

ぶつかったらその角度へ追い返してやればめり込みを回避できると考えたのですがその場合外に追い返す場合のx,yの数値ですがそれはどうすれば求められるのでしょうか?あとこの実装法正しいのでしょうか?
episteme

2019/08/23 14:21 編集

だからー 俺からみた相手ベクトルだってば。数学やりなおせ。
退会済みユーザー

退会済みユーザー

2019/08/23 15:23

俺から見た相手ベクトルとはどのような意味でしょうか? 当たったらプレイヤの角度をatan2で確認して それが度でいう270 <= で<=315以内だったらyを上に上げる処理を作りましたがうまくきません。
episteme

2019/08/23 20:43

俺を原点とし、原点から対象に向かうベクトル。
退会済みユーザー

退会済みユーザー

2019/08/23 22:46

俺というのはプレイヤーですよね?
fana

2019/08/24 00:41

衝突相手たる「ブロック」は矩形なのだろうから,原始な方法としては,ある点の移動元座標と移動先座標を結ぶ線分と,ブロックの4辺との交差判定でも行えばいい.これで「点」がブロックのどの辺に当たったかがわかるっしょ.
fana

2019/08/24 00:45

(実際は交差判定4回とかしなくても,移動ベクトルの縦横比とブロック内に入り込んだ点の座標から,どっち側に当たったかは即座に判定できるだろうけど)
退会済みユーザー

退会済みユーザー

2019/08/24 11:45

ちょっとながいコメントになりますが自分はブロックに当たったである座標を今居る座標から移動する量を足した値を移動先と仮定してその場所がブロックに当たっていたらという形で処理を書きました 差分をだしてその外側に追い返すという処理なのですがこれはいいのでしょか?また真横のブロックにあたってしまったら上に押し返すよう動作してしましあと少しのところでつまづいてます if ( (pos->get_x() <= (x * CELL) && (pos->get_x() + CELL + add_x) >= (x * CELL) || pos->get_x() >= (x * CELL) && pos->get_x() <= (x * CELL) + CELL) && (pos->get_y() <= (y * CELL) && (pos->get_y() + CELL + add_y) >= (y * CELL) || pos->get_y() >= (y * CELL) && pos->get_y() <= (y * CELL) + CELL ) ) { if (pos->get_x() <= (x * CELL) && (pos->get_x() + CELL + add_x) >= (x * CELL) || pos->get_y() <= (y * CELL) && (pos->get_y() + CELL + add_y) >= (y * CELL) ) { if (add_x > 0) { //corr_x = (pos->get_x() + CELL + add_x) - (x * CELL); } corr_y = (pos->get_y() + CELL + add_y) - (y * CELL); //if (corr_x < 0) { corr_x = 0; } if (corr_y < 0) { corr_y = 0; } px += corr_x; py -= corr_y + 3; ofs <<"corr_x: "<< corr_x << "\n"; } std::optional<Position> p = Position(px,py);
退会済みユーザー

退会済みユーザー

2019/08/24 11:45

補足ですがadd_x,add_yとは移動量です
guest

0

キャラやブロックの大きさを16ドットとします
BX=8にブロックがある場合、X=128~143の範囲がブロックです
ですから、キャラの左上座標でみると、キャラが右に移動する場合はX=112で止まるし、
左に移動する場合ははX=144で止まります

ですから、X=113~143にキャラが居る場合、移動方向を見てX=112か144に押し出す必要があります

BX,BYはブロックで見たときの座標、X,Yは画面の座標

プログラムをざっと見た感じ、当たり判定で全ブロックのループが入っているのがおかしいです
下に落ちるかどうかは足場となっている最大2ブロックをチェックするだけでいいはずです

投稿2019/08/22 01:55

izmktr

総合スコア2856

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

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

退会済みユーザー

退会済みユーザー

2019/08/22 06:07

質問ですが足場となっているブロックつまり下だけのブロックを判定するにはどうすればいいんでしょうか?
izmktr

2019/08/22 10:14

プレイヤーが(16,0)にいるとき、(BX,BY)=(1,1)のブロックの上にのっていることになります。 プレイヤーが(16,1)にいるとき、(BX,BY)=(1,1)のブロックの上にめり込んでいるので、(16,0)に補正しないといけません。 プレイヤーが(17,0)にいるとき(BX,BY)=(1,1),(2,1)の2つのブロックの上に乗っていることになります。
退会済みユーザー

退会済みユーザー

2019/08/22 10:35

それをどう判定すればいいのでしょうか? キャラクタの下に当たり判定を作りまたが真横にあるブロックに上がってしまい困っています。
izmktr

2019/08/22 11:41

補正は15ドット以内になります。 もし、それ以上の補正が入るようであれば何かが間違っています。 1フレームで16ドット以上移動する場合は16ドット以上の補正が必要になりますが、 その場合は2回に分けて移動させ、1回の移動を15ドット以下で処理します
退会済みユーザー

退会済みユーザー

2019/08/22 11:49

左右の判定はどう作ればいいのですか?
izmktr

2019/08/22 16:32

真下の判定ができていればXY軸を入れ替えるだけでいけませんか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問