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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

5282閲覧

Unityで、時間と高さ幅と着地地点を指定してジャンプをコントロールしたい

SaharaDesert

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/02/13 06:33

編集2019/02/13 07:18

前提・実現したいこと

時間と高さ幅と着地地点を指定してオブジェクトをジャンプさせたいです。

言葉足らずだと思いますが、ご教授よろしくお願いいたします。

下記のURLを参考に作成しています。
https://teratail.com/questions/173195?nli=5c5ceb2c-ab38-4558-9e36-49d90a28000d

発生している問題・エラーメッセージ

幅ぶんの座標まで移動を終えていないので、Y軸の到着地点に来ると横に瞬間移動をする

該当のソースコード

C#

1public class jump : MonoBehaviour { 2 private float jumpTime2 = 2f;//ジャンプしている時間 3 private float width2 = 5;//幅 4 private float height2 = 6;//高さ 5 private float time2;//ジャンプ中の折り返し地点の時間 6 private float fixedGravityY2;//固定重力 7 private float initVelocityY2;//速度 8 private float initVelocityX2;//速度 9 private float elapsedTime2 = 0f; 10 private bool jumpChecker2 = false;//ジャンプしているかのチェック 11 public bool jumpStart2 = false;//ジャンプ処理の前の処理通過フラグ 12 private Vector3 JumpPos2; 13 private float initPositionX2; // 初期X座標のためのフィールドを追加 14 private float initPositionY2; // 初期Y座標のためのフィールドを追加 15 16 private float LandingPosY = 2f; 17 18 private bool LandingPointY_Flag = false; 19 20 21 22 void Update() { 23 if (Input.GetKey("a") && !jumpChecker2) { 24 //((Y軸+止まる位置)/Y軸) 25 //float hoge = ((height2 + LandingPosY) / height2); 26 float hoge = ((LandingPosY * 2) / height2); 27 28 float hoho = hoge <= 0 ? 1 : hoge; 29 //0以下のチェック 30 //double hohoho = Math.Truncate(hoge) <= 0 ? 1 : Math.Truncate(hoge); 31 Debug.Log("倍数:" + hoho); 32 33 jumpChecker2 = true; 34 time2 = jumpTime2 / 2; 35 36 //Y軸 37 fixedGravityY2 = -2 * height2 / (time2 * time2); 38 initVelocityY2 = 2 * height2 / time2; 39 initPositionY2 = transform.position.y; 40 41 //X軸 42 initVelocityX2 = (width2*hoho) / jumpTime2; // 距離widthをjumpTime秒かけて移動する場合の速度 43 initPositionX2 = transform.position.x; // ジャンプ開始時のX座標を覚えておく 44 45 46 } 47 if (jumpChecker2) 48 { 49 elapsedTime2 += Time.deltaTime; 50 Vector3 pos = target.transform.position; 51 pos.x = initPositionX2 + initVelocityX2 * elapsedTime2; // 水平方向は等速とする 52 pos.y = initVelocityY2 * elapsedTime2 + fixedGravityY2 * elapsedTime2 * elapsedTime2 / 2; 53 54 //高さの頂点に到達したかの判定 55 if (pos.y > (initPositionY2 + height2) - 0.2) 56 { 57 //高さの頂点に到達 58 LandingPointY_Flag = true; 59 60 } 61 62 //Y軸の所定の位置に到達したかの判定 63 if (LandingPointY_Flag) 64 { 65 if (pos.y < LandingPosY) 66 { 67 pos.y = LandingPosY; 68 pos.x = initPositionX2 + width2; // 初期位置からwidthだけ進んだ位置を最終的なX座標とする 69 elapsedTime2 = 0; 70 jumpChecker2 = false; 71 } 72 } 73 74 transform.position = pos; 75 } 76 77}

試したこと

移動しきれていない幅をを計算で求めてみたが駄目だった。

補足情報

参考にしたソースコード

C#

1public class jump : MonoBehaviour 2{ 3 public float jumpTime = 1f; 4 float time; 5 public float height = 2f; 6 public float width = 2f; 7 float fixedGravity; 8 float initVelocity; 9 // float fixedGravityX; // 水平方向の加速度は不要 10 float initPositionX; // 初期X座標のためのフィールドを追加 11 float initVelocityX; 12 float elapsedTime = 0f; 13 public bool jumpChecker = false; 14 15 void Update() 16 { 17 if (Input.GetKey("a") && !jumpChecker) 18 { 19 jumpChecker = true; 20 time = jumpTime / 2; 21 fixedGravity = -2 * height / (time * time); 22 initVelocity = 2 * height / time; 23 24 // fixedGravityX = -2 * width / (time * time); // 水平方向の加速度は不要 25 initVelocityX = width / jumpTime; // 距離widthをjumpTime秒かけて移動する場合の速度 26 initPositionX = transform.position.x; // ジャンプ開始時のX座標を覚えておく 27 } 28 if (jumpChecker) 29 { 30 elapsedTime += Time.deltaTime; 31 Vector3 pos = transform.position; 32 pos.x = initPositionX + initVelocityX * elapsedTime; // 水平方向は等速とする 33 pos.y = initVelocity * elapsedTime + fixedGravity * elapsedTime * elapsedTime / 2; 34 35 if (pos.y < 0) 36 { 37 pos.y = 0; 38 pos.x = initPositionX + width; // 初期位置からwidthだけ進んだ位置を最終的なX座標とする 39 elapsedTime = 0; 40 jumpChecker = false; 41 } 42 transform.position = pos; 43 } 44 } 45}

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

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

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

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

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

stdio

2019/02/13 06:48

(特に2Dの)ゲームの質問をする場合は、どのようなゲームを制作中なのかしっかりと明記してください。 それによってアドバイス等が変わってきます。 例)マリオの様な横スクロールアクション、古いゼル伝の様なゲーム上目線ダンジョン。
SaharaDesert

2019/02/13 06:53

すみません。 マリオの様な横スクロールアクションに近いジャンプです。 プレイヤーがジャンプして宙に浮いているブロックに乗る感じです。
stdio

2019/02/13 07:03

プログラムを見た感じ、横スクロールアクションだと思ったよ。 基本的にブロックの衝突判定は常時判定要るよ。 パッと見た感じだと... if (jumpChecker2)が通ってない気がするけど、気のせい?
izmktr

2019/02/13 07:07

まず、高校レベルの物理はちゃんと理解していますか? 速さv (m/s)で真上にボールを投げたとき、何mまで上がって何秒後に落ちてくるか計算できますか? 出来てないなら、一旦物理の勉強に戻らないと難しいかと思います
SaharaDesert

2019/02/13 07:07

キーを押したか判定している所で、jumpChecker2のフラグをtrueにしているので通っています。
SaharaDesert

2019/02/13 07:09

物理方確認してきます。
stdio

2019/02/13 07:14

いや、jumpChecker2を一度trueに変えてまたfalseに戻してるように見えるのですが... if (Input.GetKey("a") && !jumpChecker) の中にご注目...
stdio

2019/02/13 07:15

あ、ごめん間違えた、違うフラグか...
SaharaDesert

2019/02/13 07:17

すみません。 関係ないフラグを消し忘れていました。 修正しておきます。
stdio

2019/02/13 07:22

initVelocityY2、elapsedTime2、fixedGravityY2 ここの値の更新ができてないのでは?
SaharaDesert

2019/02/13 07:27

initVelocityY2、elapsedTime2、fixedGravityY2 の値を更新する目的は、何でですか?
stdio

2019/02/13 07:33

Velocityの値を更新せずに上はいかないから。 普通は Pos += Velocity でプレイヤーの動きを制御するものだし
SaharaDesert

2019/02/13 07:38

どう直せばいいでしょうか? 教えていただいてもいいでしょうか。
stdio

2019/02/13 08:09

//高さの頂点に到達したかの判定 if (pos.y > (initPositionY2 + height2) - 0.2) とコメント書いている下あたりなんでこんなコードになっているのか説明して下さい。 なんとなくおかしいよ。
SaharaDesert

2019/02/13 08:27

最初に上に飛ぶときに、着地地点がすぐに処理されてしまうため 頂点に到達してから着地地点で移動処理を停止させています。
guest

回答1

0

ベストアンサー

だんだんややこしくなってきましたね...
ひとまず初期位置とか水平移動は無視して、鉛直投げ上げに戻ってみてはいかがでしょうか。

原点から真上にオブジェクトを投げ上げ、ある時刻tHで最高点Hに達し、その後落下して最終時刻Tで高さhに至るとすると、縦軸に垂直位置y、横軸に時刻tをとると下図のような二次曲線が描かれるでしょう。

グラフ

この未知の二次曲線を
y = at2 + bt + c
として図中の3点の(t, y)を代入すると、まず
c = 0
と確定でき、
H = atH2 + btH、h = aT2 + bT
の2式が得られます。これらを変形して一つにまとめると
h = aT2 + TH/tH - aTtH
の関係が得られます。
次に、二次曲線の導関数
dy/dt = 2at + b
に注目します。時刻tHにおいて曲線の傾きが0になるので
2atH + b = 0
となります。このbに①を変形した
b = (H - atH2) / tH
を代入して整理すると
a = -H / tH2
となります。これを②に代入し変形すると
htH2 - 2HTtH + HT2 = 0
の二次方程式が出てきます。これの解を求めると
tH = T((H±√H(H - h)) / h)
となります。解が2つありますが、
tH <= T、h <= H
でなくてはならないので、採用する解は
tH = T((H-√H(H - h)) / h)
の方ということになります。最高点に到達する時刻を決定できましたので、これをtime2として使用すればいいでしょう。
下記のようなコードを実行してみたところ...

C#

1using UnityEngine; 2 3public class jump : MonoBehaviour 4{ 5 [SerializeField] private float jumpTime2 = 2f; // 時間 6 [SerializeField] private float width2 = 5f; // 幅 7 [SerializeField] private float height2 = 6f; // 高さ 8 [SerializeField] private float LandingPosY = 2f; // 着地高さ 9 10 private bool jumpChecker2 = false; //ジャンプしているかのチェック 11 12 private float fixedGravityY2; // 重力加速度Y 13 14 private float initVelocityX2; // 初速度X 15 private float initVelocityY2; // 初速度Y 16 17 private float initPositionX2; // 初期X座標 18 private float initPositionY2; // 初期Y座標 19 20 private float elapsedTime2 = 0f; 21 22 void Update() 23 { 24 if (Input.GetKey("a") && !jumpChecker2) 25 { 26 elapsedTime2 = 0; 27 jumpChecker2 = true; 28 29 float time2; 30 if (LandingPosY > height2 || Mathf.Approximately(LandingPosY, 0.0f)) 31 { 32 // もし着地点の方が最高到達点より高かったり、着地点がちょうど0だった場合 33 // time2を求められないため、従来通りの平地ジャンプとする 34 time2 = jumpTime2 / 2; 35 } 36 else 37 { 38 time2 = jumpTime2 * ((height2 - Mathf.Sqrt(height2 * (height2 - LandingPosY))) / LandingPosY); 39 } 40 41 // Y軸 42 fixedGravityY2 = -2 * height2 / (time2 * time2); 43 initVelocityY2 = 2 * height2 / time2; 44 initPositionY2 = transform.position.y; 45 46 // X軸 47 initVelocityX2 = width2 / jumpTime2; 48 initPositionX2 = transform.position.x; 49 } 50 51 if (jumpChecker2) 52 { 53 elapsedTime2 += Time.deltaTime; 54 55 // 経過時間がjumpTime2を越えたら... 56 if (elapsedTime2 > jumpTime2) 57 { 58 // このタイミングでelapsedTime2を最終時刻であるjumpTime2に合わせ 59 // jumpChecker2をfalseにするといいでしょう 60 elapsedTime2 = jumpTime2; 61 jumpChecker2 = false; 62 } 63 64 Vector3 pos = transform.position; 65 66 pos.x = initPositionX2 + initVelocityX2 * elapsedTime2; 67 pos.y = initPositionY2 + initVelocityY2 * elapsedTime2 + fixedGravityY2 * elapsedTime2 * elapsedTime2 / 2; 68 69 transform.position = pos; 70 71 // ジャンプ中に経過時間や座標をコンソールに出力してみると、動きの様子をとらえやすいかもしれません 72 Debug.Log($"Time:{this.elapsedTime2:F4} X:{transform.position.x:F4} Y:{transform.position.y:F4}"); 73 74 // 他にも、軌跡にオブジェクトを残して動きを可視化するのも面白いでしょう 75 Transform dot = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; 76 dot.localScale = new Vector3(0.125f, 0.125f, 0.125f); 77 dot.position = transform.position; 78 } 79 } 80}

オブジェクトは下図のような軌道で飛びました。

投射

ここまで書いておきながらなんですが、もしニュートン力学の学習目的とかではなくアクションゲームの作成を目指しているのでしたら、オブジェクトの位置を二次関数の形で求めるよりも、stdioさんがおっしゃるように「現在の速度」を使った数値積分的アプローチの方が面倒が少ないと思います。むしろ、もっとColliderやRigidbodyに頼った作りにしてしまっていいんじゃないでしょうか...?

投稿2019/02/14 13:50

Bongo

総合スコア10807

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

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

SaharaDesert

2019/02/18 00:49

返信遅くなり申し訳ありません。 返信ありがとうございます。 試してみます。
SaharaDesert

2019/02/18 01:08

出来ましたありがとうございます。 ColliderやRigidbodyに頼った作りにしてしまっていいんじゃないでしょうか...? ↳今現在ColliderやRigidbody不慣れだったため使っていませんでした、もう少し知見などを得たいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問