🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Unity3D

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

Q&A

解決済

1回答

2678閲覧

坂道の上る時下がる時でY軸の値の補正方法が知りたい"下がる場合"

退会済みユーザー

退会済みユーザー

総合スコア0

Unity3D

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

0グッド

0クリップ

投稿2019/10/27 14:37

編集2019/10/31 10:06

提示コード//////コメントの中のコードです。坂道を上に登った時の処理はif文で完成したいのですが

質問1 "坂を下る時"の処理の実装方法が知りたいです。
質問2 坂道を上に登る時と下る時の処理を分ける分岐の実装法が知りたいまた、坂道で斜めに進む時動けなくなるのでその辺も考慮した処理の実装法が知りたい
質問4 平地から坂道の上ろうとすると引っ掛かって登れない原因が知りたい

イメージ説明
イメージ説明

using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { const float walk_speed_max = 20.0f; Rigidbody rb; Vector3 move; float input_h; float input_v; Vector3 move_x; Vector3 move_z; public GameObject gGround; ground spt_g; bool isJump; bool isDush; bool isRay; bool isGround = false; float jump_force = 200.0f; float move_speed = walk_speed_max; Animator ani; private Transform StepHit; private RaycastHit downRay; private Transform Hit; private RaycastHit ray; const float ray_range = 0.3f;//レイを飛ばす距離 // 昇れる段差 private float stepOffset = 0.3f; //坂道の角度登れる private float slopeLimit = 65f; // 昇れる段差の位置から飛ばすレイの距離 private float slopeDistance = 0.1f; private Vector3 v; // GameObject go = GameObject.Find("GameObject"); private Transform prev; void move_step() { //y軸は逆にしてるプラスが下 Debug.DrawLine(StepHit.position, StepHit.position + StepHit.right * ray_range, Color.red); Debug.DrawLine(StepHit.position, StepHit.position + StepHit.forward * ray_range, Color.blue); float s = Mathf.Sqrt((move.x * move.x) + (move.z * move.z)); if (s > 0 && isGround == true) { if (Physics.Linecast(StepHit.position, StepHit.position + StepHit.forward * ray_range, out ray,LayerMask.GetMask("Slope"))) // if (Physics.Linecast(StepHit.position, StepHit.position + StepHit.forward * ray_range, out ray)) { //Debug.Log(Vector3.Angle(transform.up, ray.normal)); if (Vector3.Angle(transform.up, ray.normal) <= slopeLimit) { v = new Vector3(0f, (Quaternion.FromToRotation(Vector3.up, ray.normal) * transform.forward * s).y, 0f) + transform.forward * s; Debug.Log("上がる"+v.y); move.y += v.y; } ////////////////////////////////////////////////////////////////////////////////////////////////////// } else if (Physics.Linecast(StepHit.position, StepHit.position + StepHit.right * ray_range, out downRay, LayerMask.GetMask("Slope"))) { Debug.Log(Vector3.Angle(transform.up, downRay.normal)); if (Vector3.Angle(transform.up, downRay.normal) <= slopeLimit) { Debug.Log("下がる"); v = new Vector3(0f, (Quaternion.FromToRotation(Vector3.up, ray.normal) * transform.forward * s).y, 0f) + transform.up * s; Debug.Log("下がる:" + v.y); move.y += -v.y; } // Debug.Log("下がるとき"); } ////////////////////////////////////////////////////////////////////////////////////////////////////// } } // Start is called before the first frame update void Start() { rb = GetComponent<Rigidbody>(); spt_g = gGround.GetComponent<ground>(); ani = GetComponent<Animator>(); isJump = false; isDush = false; StepHit = transform.Find("StepRay"); } // Update is called once per frame void Update() { //Debug.Log(transform.up); // Debug.Log(transform.right); isGround = spt_g.isGround; // Debug.Log(isGround); //input_h = Input.GetAxis("Horizontal"); //input_v = Input.GetAxis("Vertical"); if(Input.GetKey(KeyCode.LeftArrow)) { input_h = -1; }else if (Input.GetKey(KeyCode.RightArrow)) { input_h = 1; } else { input_h = 0; } if (Input.GetKey(KeyCode.UpArrow)) { input_v = 1; } else if (Input.GetKey(KeyCode.DownArrow)) { input_v = -1; } else { input_v = 0; } move_z = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized * input_v; move_x = Camera.main.transform.right * input_h; move = move_x + move_z; move.x *= move_speed; move.z *= move_speed; // Debug.Log(isRay); if (move != Vector3.zero) { transform.rotation = Quaternion.LookRotation(move.normalized); } // /*走る*/ if(Input.GetKey(KeyCode.RightControl)) { isDush = true; move_speed = 15.0f; } else { isDush = false; move_speed = walk_speed_max; } if(Input.GetKey(KeyCode.Space)) { if(isGround == true && isJump == false) { isJump = true; } } move_step(); Animation_Mng(); } /*アニメーション管理*/ void Animation_Mng() { float speed = Mathf.Sqrt((move.x * move.x) + (move.z * move.z)); ani.SetFloat("Move_Speed",speed); ani.SetBool("isDush",isDush); //ani.speed = 2; } private void FixedUpdate() { if (isGround == false) { rb.AddForce(new Vector3(0, -30.0f, 0)); rb.velocity = new Vector3(move.x, rb.velocity.y, move.z); } else { rb.velocity = new Vector3(move.x, move.y, move.z); } } private void OnCollisionEnter(Collision c) { //isGround = true; } private void OnCollisionExit(Collision c) { //isGround = false; // Debug.Log("プレイヤーcollision false"); } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

void move_step()にて、坂道にいるときy軸速度をいじろうとした形跡があるのに、コメントアウトされているように見えます。

結果、x,z方向は直接速度をいじっているにもかかわらず、y方向の移動はAddForceでしかいじっていないのでは?(違ったら申し訳ございません)
だとしたらおそらくそれが原因です。

どういうことか、何が起きているか具体的に説明します。

坂道を登ろうとしているとき、そこに坂道があるにも関わらずx,zの速度は直接いじられている、これはつまり無理やり横方向に進もうとして坂道にめり込みながら進んでいる状態です。

結果静止した瞬間にそのめり込みが解消され、上に上がったように見えます。

坂道を下ろうとしたとき、はじめy軸方向の速度は0の状態で、突然x,zの速度だけが一定の値にされます。
y方向にもAddForceされていますが、これはあくまで力を加え徐々に加速されているだけです。

よほど大きな力を加えなければ、速度の値を直接いじったときのように一瞬でその速度になったりはしません。

これによりx,zの速度一定、y軸の速度は0から加速され、坂道にぶつかり0に戻るという動作を繰り返します。

従って階段を降りるかのような段階的な動きになります。

質問者様の症状と一致しているのではないでしょうか?

解決策としては、y軸の速度もいじる、もしくはy座標を直接坂道に合わせいじるのがいいでしょう。

せっかくmove_step()にて坂道いるかの情報を入手しているのですから、これをそのまま使います。
坂道にいるとき、角度と移動方向から計算して必要なy軸の速度もしくは座標を出し、加えます。

というかコメントアウトされている処理がまんまこれなのでは?

(他にも 坂 Unity で検索すると色々出るので良ければ自分で調べてみてください)

余談ですが、今回のようなケースがあるので、RigidBodyで直接速度をいじるのは推奨されないと言われる場合があります。

全てAddForceでやれ、ってわけですね。
ただその場合それはそれで問題が発生することもありますし、余程うまくやらないともっさりした動きになったりします。

ですので物理法則を大事にしたいなら全てAddForceなどで統一、そうでなくレスポンスなどゲームらしさを大切にしたいならRigidBody.verocityやtransform.positionの変更など臨機応変に、ってところですかね。

投稿2019/10/27 17:39

編集2019/10/31 13:50
junkpar

総合スコア57

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

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

退会済みユーザー

退会済みユーザー

2019/10/31 08:22

質問ですが坂を下がるときはどうすればyの値を取得できるのでしょうか?またそれを実装したとして 坂を下がっているときと上がっているときはどうすれば判別できるのでしょうか?
退会済みユーザー

退会済みユーザー

2019/10/31 10:47

そのやり方で自分は前に進む時の法線ベクトルを取得し計算してるのですが坂を下る時で困っています。 真下にもレイを飛ばしてぶつかったときの計算をelse ifでしていますがyの値が20と出てしまいます 符号を逆にしてみましたがうまく実装できません。どうしたらいいのでしょうか?
junkpar

2019/10/31 11:58

地形の判断がしたいのですからRaycastは前方ではなく真下に飛ばすのが無難かと思われます。 playerの位置、もしくはそこから進行方向に少しずれた位置から下に向かって飛ばすべきです。 それと今思いつきましたがplayerの位置とそこから進行方向にずれた位置でRaycastを2本飛ばしてy座標を測定すればもっと直接的に傾斜を求めることができますね。
junkpar

2019/10/31 12:06

すいません僕が少々勘違いしていたようです 質問者さんの処理はもともと坂道の処理ではなく段差を登る処理だったのでは? 坂道と段差は違いますからそれで色々問題が起きているのだと思います。 解決方法は直前の僕のコメントのやり方でなんとかなると思います。
退会済みユーザー

退会済みユーザー

2019/10/31 12:28

上も下も同じやり方でできるのですねそれはわかりましたが。質問ですがレイはどうすればいいのでしょうか 2つで一つは前でもう一つは真下に飛ばすのがいいのでしょうか?
junkpar

2019/10/31 12:42

両方とも下に向かって飛ばしましょう。前に飛ばしては進行方向が下りだった時地形にヒットしません。
退会済みユーザー

退会済みユーザー

2019/10/31 12:49

真下でしょうか?両方とはどっちはどう下向きなのでしょうか?
退会済みユーザー

退会済みユーザー

2019/10/31 13:11

また坂道に居るときに横に移動すると極端に歩く速度が遅く、ゼロフュージョンなどを入れてしまうと 動かなくなるので横に動いても歩く速度が平地と同じなる実装方法を教えていただきたいです。
junkpar

2019/10/31 14:16

指定した位置から真下に向かってraycastを飛ばし、地形にヒットした時の座標を取得することで、その地点の高さを調べることができます。 これによりplayerの位置と、プレイヤーがこれから進むであろう位置のそれぞれの地形の高さを調べることで、プレイヤーのy座標をどういじるべきか設定できるはずです。 それと横移動が遅くなる原因はよくわかりませんが、以前質問者さんの質問に坂に摩擦を設定したらどうかと提案したことがあるので、ひょっとしたらそれが原因かもしれません。 摩擦は適切な値である必要がありますし、坂に摩擦を設定するなら通常の床にも設定、移動する際の力もそれに合わせるなど各地で適切な物理設定が必要です。 それを考えると摩擦を設定するのは面倒なので、あの回答は忘れてもらった方がいいかもしれません。
退会済みユーザー

退会済みユーザー

2019/10/31 14:19

わかりました。また摩擦の件ですがコリジョンをカプセルに変更したら治りました。これまでは メッシュでやってました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問