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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Unity3D

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

Unity

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

Q&A

解決済

1回答

4940閲覧

Unity-chanの登れる坂の傾斜制御について

tarozimakiyoshi

総合スコア1

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2021/05/04 17:24

編集2021/05/05 18:30

Unity-chanを標準の**「unity chan control script with rigidbody」**というスクリプトを用いて移動させたところ、80度程度の斜面でも登れてしまうことがわかりました。
45度以上の斜面は登れないようにしたいのですが、そのような設定は可能でしょうか。

※terrainで作成した地形を歩かせています。

「Charactor controller」コンポーネントだと「Slop Limit」などの斜面に関する設定項目があるのですが、
「unity chan control script with rigidbody」にはその設定項目がないためご質問させていただきました。

恐れ入りますが、ご教示の程よろしくお願いいたします。

※画像追記:崖は登れてしまう
イメージ説明
設定値
イメージ説明

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

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

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

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

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

guest

回答1

0

ベストアンサー

UnityChanControlScriptWithRgidBody(クラス名とかコード内につづり間違いがポツポツ混じっているのがちょっと気になりますね...)には登れる斜面の限界だとかは特に設けられていないようです。そういった機能が必要でしたら改造を加えてやる必要がありそうですね。

まず、下記部分に...

lang

1 // 以下キャラクターコントローラ用パラメタ 2 // 前進速度 3 public float forwardSpeed = 7.0f; 4 // 後退速度 5 public float backwardSpeed = 2.0f; 6 // 旋回速度 7 public float rotateSpeed = 2.0f; 8 // ジャンプ威力 9 public float jumpPower = 3.0f;

フィールドを追加して下記のようにしました。

lang

1 // 以下キャラクターコントローラ用パラメタ 2 // 前進速度 3 public float forwardSpeed = 7.0f; 4 // 後退速度 5 public float backwardSpeed = 2.0f; 6 // 旋回速度 7 public float rotateSpeed = 2.0f; 8 // ジャンプ威力 9 public float jumpPower = 3.0f; 10 // 斜面が登りにくくなり始める角度 11 public float slopeLowerThreshold = 45.0f; 12 // 斜面が登れなくなる角度 13 public float slopeUpperThreshold = 60.0f;

また、下記移動部分を...

lang

1 // 上下のキー入力でキャラクターを移動させる 2 transform.localPosition += velocity * Time.fixedDeltaTime;

下記のように変更し、足元の地面の傾きに応じて移動力を落としてみました。

lang

1 // velocityの倍率を表す変数 2 float velocityMultiplier = 1.0f; 3 4 // キャラクターの原点(ユニティちゃんなら足元のはず)よりも少し上から 5 // 原点の少し下までレイキャストを行い... 6 if (Physics.Raycast(new Ray(transform.position + (Vector3.up * 0.125f), Vector3.down), out RaycastHit hit, 1.0f)) 7 { 8 // 足場が検出されたら、その法線を取得 9 Vector3 normal = hit.normal; 10 11 if (Mathf.Approximately(normal.y, 0.0f)) 12 { 13 // もし足場が垂直なら、velocityMultiplierを0倍に設定 14 // 真下へのレイキャストなので、こうなるケースはないはずですが 15 // 念のためゼロ除算のケースを考慮して条件分岐を設けました 16 velocityMultiplier = 0.0f; 17 } 18 else 19 { 20 // 傾き具合を調べ、velocityMultiplierを調整 21 Vector2 normalXZ = new Vector2(normal.x, normal.z); 22 Vector2 velocityXZ = new Vector2(velocity.x, velocity.z); 23 float slopeAngle = Mathf.Rad2Deg * Mathf.Atan2(-Vector2.Dot(normalXZ, velocityXZ) / normal.y, velocityXZ.magnitude); 24 float t = Mathf.Clamp01((slopeAngle - slopeLowerThreshold) / (slopeUpperThreshold - slopeLowerThreshold)); 25 velocityMultiplier = 1.0f - (t * t * (3.0f - (t * 2.0f))); 26 } 27 } 28 29 // velocityの大きさを調整 30 velocity *= velocityMultiplier; 31 32 33 // 上下のキー入力でキャラクターを移動させる 34 transform.localPosition += velocity * Time.fixedDeltaTime;

なるべくささやかな修正で済ませたつもりですが、いかがでしょうかね?

図

#追記

なるほど、ほぼ垂直に切り立った崖に突っ込んだ場合は...

  • 崖のふもとにいる時は、レイキャスト時に足元の平坦な地面が検出され、傾いていないので移動力が制限されない。つまり条件的にご質問者さんが最初に試した時の80°の斜面と同じになって、崖のわずかな傾きによって少しずつ登れてしまう。
  • 少しずつ崖を登っていって平坦部分から浮かんでいき、レイキャストがヒットしなくなると宙に浮いているのと同じ状況になる。空中にいる時に移動入力があった場合には移動力を制限しないようにしたため、やはり引き続き崖を登れてしまう。

といった状態になってしまったようですね。
代案として、まずスクリプト内に下記のようにimpulseSumおよびOnCollisionStayを追加し...

lang

1 // 他のコライダーとの衝突によって受けた力積を 2 // OnCollisionStay内で足し合わせていくようにしました 3 Vector3 impulseSum; 4 5 void OnCollisionStay(Collision other) 6 { 7 impulseSum += other.impulse; 8 }

さらに最初の回答で提示しました移動部分を下記のように変更し、足の下へのレイキャストで法線を得る代わりに、衝突で受ける力積を法線と見なして傾き判定を行うというのはどうでしょうか。

lang

1 // velocityの倍率を表す変数 2 float velocityMultiplier = 1.0f; 3 4 // レイキャストに代わって、力積の総和の大きさで接地しているか 5 // (あるいは壁に触れているか)を判定し... 6 float impulseSumMagnitude = impulseSum.magnitude; 7 if (impulseSumMagnitude > 0.01f) 8 { 9 // 力積の方向を法線と見なすことにしました 10 Vector3 normal = impulseSum / impulseSumMagnitude; 11 12 if (Mathf.Approximately(normal.y, 0.0f)) 13 { 14 // もし足場が垂直なら、velocityMultiplierを0倍に設定 15 velocityMultiplier = 0.0f; 16 } 17 else 18 { 19 // 傾き具合を調べ、velocityMultiplierを調整 20 Vector2 normalXZ = new Vector2(normal.x, normal.z); 21 Vector2 velocityXZ = new Vector2(velocity.x, velocity.z); 22 float slopeAngle = Mathf.Rad2Deg * Mathf.Atan2(-Vector2.Dot(normalXZ, velocityXZ) / normal.y, velocityXZ.magnitude); 23 float t = Mathf.Clamp01((slopeAngle - slopeLowerThreshold) / (slopeUpperThreshold - slopeLowerThreshold)); 24 velocityMultiplier = 1.0f - (t * t * (3.0f - (t * 2.0f))); 25 } 26 } 27 28 // 判定の後は、impulseSumをゼロにリセットしておきます 29 impulseSum = Vector3.zero; 30 31 // velocityの大きさを調整 32 velocity *= velocityMultiplier; 33 34 // 上下のキー入力でキャラクターを移動させる 35 transform.localPosition += velocity * Time.fixedDeltaTime;

図2

投稿2021/05/05 05:35

編集2021/05/05 21:49
Bongo

総合スコア10811

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

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

tarozimakiyoshi

2021/05/05 17:07

詳細なご説明、そしてプログラムまで書いていただき本当にありがとうございます。 動画を拝見した限り、まさに理想の動きになりそうですので、 こちら、さっそく試してみたいと思います。 しかし、公式のunity chanのスクリプトに綴りミスがあるとは笑、気づいておりませんでした。
tarozimakiyoshi

2021/05/05 18:28

いただいたスクリプトを試したところ、基本的には斜面を登らないよう制御することができました! 誠にありがとうございます。 ただ、崖はなぜか登れてしまうようでして、こちらは斜面とはまた原因が別になるものでしょうか…? 崖というのは、terrainの「set height」で地形を作成する際にできるような、見た目としてはほぼ90度の地形になります。 ※元の質問に画像を追記いたしました。
Bongo

2021/05/05 21:50

おっしゃるとおり、切り立った崖を作って試してみたところ少しずつ登れてしまいました... 代替案を追記しましたが、あれならどうでしょうかね?
tarozimakiyoshi

2021/05/06 09:35

ありがとうございます! 再度試したところ、崖が登れることはなくなりました。 意外と難しい制御だということがわかりましたのでもしかするとほかにも抜け穴のような地形が出てくるのかも知れませんが、現状ですと理想通りの動きです。大変助かりました。 こちらで解決とさせていただきます。詳細にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問