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

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

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

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

Q&A

解決済

2回答

3880閲覧

Dxlib 2Dジャンプゲームのジャンプの細かい動作を作りたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

0グッド

0クリップ

投稿2019/07/31 09:12

マリオ風アクションゲームでジャンプの細かい仕様を作りたいのですがただジャンプする以外の動作を作れませんどうすれば実装できるのでしょうか?
1,ジャンプして当たり判定に当たると落下する
2,ジャンプ中や落下中で空中に居る間はジャンプできない
3,足場のブロックがなくなると落下するこの時の空中に居るのでジャンプできない
この3つの動作を実装したいのですがどうすればいいのかわかりませんただジャンプするだけなら実装できますがジャンプボタンを押せばいくらでもジャンプできてしまいそれを防ぐと別のバグに遭遇し上手く作れません。

#include "Input.h" #include "Player.h" #include "DxLib.h" #include "Map.h" #define MOVE_SPD 5 /*コンストラクタ*/ Player::Player(const char* str, int xx, int yy) :pos{xx,yy} { LoadDivGraph(str,7,7,1,64,64,g_handle); } /*計算更新*/ void Player::Update() { input_key(); //gravity(); } /*描画更新*/ void Player::Draw_Update() { DrawFormatString(100,100,GetColor(255,255,255),"Debug"); DrawGraph(gPos_x(), gPos_y(), g_handle[0], true); } bool isJump = false;//ジャンプボタンを押したかどうか bool isJumpNow = false;//ジャンプ中かどうか /*キー入力*/ void Player::input_key() { if (keybord(KEY_INPUT_LEFT) > 0) { sPos_x(-MOVE_SPD); } if (keybord(KEY_INPUT_RIGHT) > 0) { sPos_x(+MOVE_SPD); } ////////////////////////////////////////////////////////////////////////////////// /*ジャンプ*/ if (keybord(KEY_INPUT_SPACE) > 0) { if(isJumpNow == false) { isJump = true; } Jump_up(isJump); gravity(isJump); } else { gravity(isJump); } ////////////////////////////////////////////////////////////////////////// } ///////////////////////////////////////////////////////////////////////////// void Player::Jump_up(bool jump) { if (jump == true) { n = (n - 2); if (j <= 0) { n = 0; } j = n; sPos_y(j); } } bool isCollision = false; /*重力効果*/ void Player::gravity(bool g)//ジャンプしてるかどうかと当たり判定を比較 { isCollision = Map::col(pos.x,pos.y); DrawFormatString(0, 200, GetColor(255, 255, 255), "jump: %d",jump); /*当たっていない時ジャンプボタンを押した時*/ if (isCollision == false) { sPos_y(-2); } else if (isCollision == true) { isJump = false; } if (jump == true) { DrawFormatString(0, 100, GetColor(255, 255, 255), "collsiion"); } } /////////////////////////////////////////////////////////////////////////////////

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

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

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

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

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

guest

回答2

0

何がどうバグっているのかという状況を提示されたコード断片からは読み取れませんが…

ボタンが押された際にジャンプして良いか否かの判断を「今現在ジャンプ中か」みたいなフラグで判断しようとしている(?)ように見えますが,
その「複雑さ」は必要なのでしょうか?

フラグを1個用意すると,

  • ジャンプして良いか否かは現在のフラグ状態で判断するぞ
  • ってことは,そのフラグは誰かがどこかで適切に立てたり降ろしたりしているわけだ
  • 具体的には,いつフラグは立つの? いつ降りるの? 初期値はどっちなの? 何らかのタイミングでの初期化も忘れないようにしないと…

という話が湧いて出てくることになると思いますが,ジャンプの可否にこれだけの話が必要ですか?
必要か否かは作る物次第なのだと思いますが,
【修正しようとするとバグる】というつらい状態になる原因の一つが,こういった複雑さを 管理/把握 できないことなのであれば「話をシンプルにできないかを検討する」という方針があり得るのではないかと思います.

例えばジャンプ可否の判定を

  • 「今現在,キャラクタの足元に足場とできる何かがあるか否か」

という判定にしても問題ないのならば,非常にシンプルに済みそうです.(Map::col()というのを呼ぶだけ?)

2,ジャンプ中や落下中で空中に居る間はジャンプできない
3,足場のブロックがなくなると落下するこの時の空中に居るのでジャンプできない

の,ジャンプできるできないの話はこの条件だけで網羅できるように思えます.

投稿2019/08/01 02:10

fana

総合スコア11658

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

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

fana

2019/08/02 11:09

また理由なき低評価か…
guest

0

ベストアンサー

1. ジャンプして当たり判定に当たると落下する

物理学のお話になります。

一般に運動する物体がなにかに衝突したとき、完全に跳ね返らず、いくらか速度が減衰して跳ね返ります。これを非弾性衝突といいます。何割くらい速度が減衰するかを反発係数eといい、以下のように定義されます。

e = v' / v

  • vは衝突前の速度、v'は衝突後の速度

さて、今回の場合を考えます。ジャンプする運動を水平方向(左右)と垂直方向(上下)に分解して考えます。面倒くさいの以下x, y方向とします。右方向、上方向を正とします。

まずy方向について。

ジャンプ中の運動はいわゆる鉛直投げ上げ運動で、重力加速度gがかかり、また上方向に初速度(ジャンプした瞬間の速度)v_0が与えられます。つまりある時刻tでのy方向の速度は

v = v_0 - gt

と表せます。tを衝突した時間にすれば衝突した瞬間の速度が求まります。これをv_1とします。

ある時刻tでの位置yは

y = v_0 t - gt^2

と表せます。単純にtで積分しただけですね。衝突判定はこのyを見ればいいわけです。衝突した瞬間のyをy_1とします。

衝突した直後の速度は上述の反発係数を使って

v' = e v_1

ですね。

あとは下向きに初速度と重力加速度がかかっている鉛直投げ下ろし運動と同じですから

v = - e v_1 - gt

y = y_1 - e v_1 t - gt^2

のように運動します。

次にx方向について

これは単純に等速直線運動をします。

ただし衝突したときに摩擦を考えるとややこしくなります。面倒なので割愛しますが。

これに基づいてキャラクタを動かせばいいでしょう。

2. ジャンプ中や落下中で空中に居る間はジャンプできない

これは単に足場に乗っているかのフラグを持っておけばいいでしょう。・・・いや、フラグというか別にyの値使って衝突判定するだけか。

3.足場のブロックがなくなると落下するこの時の空中に居るのでジャンプできない

同上

投稿2019/08/01 01:39

編集2019/08/01 03:31
yumetodo

総合スコア5850

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

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

fana

2019/08/01 02:22

衝突した時刻tとはどうやって求めるのでしょう? あと,暗黙的に定められているy=0やt=0に関して,明記された方がわかりやすいような.
yumetodo

2019/08/01 03:28

ああ、そういえば書いていなかった。 ジャンプした瞬間の位置をy = 0, t = 0としていますね。 tはCFR(固定フレームレート)でやってるならframe数を使えばいいし、VFR(可変フレームレート)でやってるならリアル時間にすればいいです。
fana

2019/08/01 03:49

この話での衝突時間tとは,キャラクタの運動軌跡を媒介変数tを用いてC(t)と書いたときに位置C(t)が障害物の外周上となるときのtなのだと思いますが, 質問者のコードでは当たり判定処理は「ある座標(x,y)が何らかの当たる対象の内側であるか否か」しかわからない仕組みになっているように見えるので,衝突時間tを求めるのはちょっと面倒そうで,そこらへんの事を指して「どうやって求めるのでしょう?」とか言ってみた感じです. まぁ,例えばtが整数扱いの場合に「C(t+1)が障害物の内側になるときに衝突時刻をtとする」ような感じでも良いのかもですが. (これをC(t)が障害物の内側のときを衝突時刻tとしてしまうと,普通は |e|<1 だろうから,実装次第ではめり込んだりしそう)
yumetodo

2019/08/01 04:01

めり込みを言うならそもそもMap::col(pos.x,pos.y)ってだめですよね。なんで点で判定してるんでしょうという。 Map::colに時刻と運動の軌跡を表す関数を定義したlambda式を渡して判定するようにするのが責任分担から言ってもよさそう。
fana

2019/08/01 04:20

キャラクタが質点なのではないでしょうか.
yumetodo

2019/08/01 04:21

constexpr auto charactor_jump_v_0_x = /* */; template<typename GetCharactorPos, std::enable_if_t<std::is_invocable_r_v<std::pair<std::size, std::size>, GetCharactorPos, std::uintmax_t>, std::nullptr_t> = nullptr> std::optional<std::uintmax_t> Map::col(std::uintmax_t t_from, std::uintmax_t t_to, GetCharactorPos&& get_charactor_pos); void foo(std::uintmax_t frame){ std::size_t v_x = /* */; const auto when_to_clash = map.col(frame - 1, frame, [v_x](std::uintmax_t t){ return {v_x * t, charactor_jump_v_0 * t - g * t * t;}); if(when_to_clash){ //衝突したので落下モードに切り替え。なんかフラグで制御?運動の関数ごとstd::functionで持たせてそれを差し替える?ご自由に } }
yumetodo

2019/08/01 04:23

>キャラクタが質点なのではないでしょうか 点だった描画できなくないですか?大きさがないと。でということはそれを考慮しないとめり込みません?判定側で大きさ決め打ってるならわかりますがそれはそれでクソ。
fana

2019/08/01 04:28

(質点は当然冗談だけども) データと表示とは別なので,表示上の「見た目」はめり込んでてもデータ値的にはめり込んでなければOKみたいな. あえて例えるなら,弾幕STGの自機の判定と絵が全然違うみたいな.
yumetodo

2019/08/01 04:32

なるほど? (東方Projectだとキャラクターの個性を持たせるために衝突になる半径rが違う気がします、霊夢が小さい、東方紺珠伝の優曇華のBOM中はすごく大きい)
fana

2019/08/01 04:39

実際のところは謎ですが,「ただジャンプするだけならできている」とのことなので,1点の判定(であるように見えるMap::col())だけで何かがうまく成り立っている世界(なハズ).
yumetodo

2019/08/01 04:40

そもそもcolがstatic メンバ関数の時点で謎of謎なのでこれ以上突っ込むまい・・・
fana

2019/08/01 05:09

(それはそうと投下された黒魔術がムズい…勉強になるなぁ)
fana

2019/08/01 05:21 編集

(enable_if_tのあたりが上司がタバコ休憩から帰ってくるまでにはとても理解できそうにないので,とりあえずブックマークです.感謝)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問