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

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

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

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

Unity3D

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

Q&A

解決済

1回答

1461閲覧

Standard Assetesのジャンプを用いた空中移動の実装

tails_

総合スコア1

C#

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

Unity3D

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

0グッド

0クリップ

投稿2021/06/06 12:26

前提・実現したいこと

現在、unityのStandard Assetes内のThirdPersonCharacterを用いてキャラクターを操作できるようなプログラムを作っています。
これに手を加えて、空中でも移動キーの入力に応じて移動する方向・速度を変えられるようなプログラムにしたいと考えています。

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

配布されている状態ではジャンプしている状態で移動キーを入力しても、キャラクターの向いている方向だけは変更できるものの、
ジャンプした時点で跳んだ方向・距離は固定されて着地までそれらに対する操作を受け付けなくなります。

該当のソースコード

以下はThirdPersonCharacterの内容です。

C#

1using UnityEngine; 2 3namespace UnityStandardAssets.Characters.ThirdPerson 4{ 5 [RequireComponent(typeof(Rigidbody))] 6 [RequireComponent(typeof(CapsuleCollider))] 7 [RequireComponent(typeof(Animator))] 8 public class ThirdPersonCharacter : MonoBehaviour 9 { 10 [SerializeField] float m_MovingTurnSpeed = 360; 11 [SerializeField] float m_StationaryTurnSpeed = 180; 12 [SerializeField] float m_JumpPower = 12f; 13 [Range(1f, 4f)][SerializeField] float m_GravityMultiplier = 2f; 14 [SerializeField] float m_RunCycleLegOffset = 0.2f; //specific to the character in sample assets, will need to be modified to work with others 15 [SerializeField] float m_MoveSpeedMultiplier = 1f; 16 [SerializeField] float m_AnimSpeedMultiplier = 1f; 17 [SerializeField] float m_GroundCheckDistance = 0.1f; 18 19 Rigidbody m_Rigidbody; 20 Animator m_Animator; 21 bool m_IsGrounded; 22 float m_OrigGroundCheckDistance; 23 const float k_Half = 0.5f; 24 float m_TurnAmount; 25 float m_ForwardAmount; 26 Vector3 m_GroundNormal; 27 float m_CapsuleHeight; 28 Vector3 m_CapsuleCenter; 29 CapsuleCollider m_Capsule; 30 bool m_Crouching; 31 32 33 void Start() 34 { 35 36 m_Animator = GetComponent<Animator>(); 37 m_Rigidbody = GetComponent<Rigidbody>(); 38 m_Capsule = GetComponent<CapsuleCollider>(); 39 m_CapsuleHeight = m_Capsule.height; 40 m_CapsuleCenter = m_Capsule.center; 41 42 m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ; 43 m_OrigGroundCheckDistance = m_GroundCheckDistance; 44 } 45 46 47 public void Move(Vector3 move, bool crouch, bool jump) 48 { 49 50 // convert the world relative moveInput vector into a local-relative 51 // turn amount and forward amount required to head in the desired 52 // direction. 53 if (move.magnitude > 1f) move.Normalize(); 54 move = transform.InverseTransformDirection(move); 55 CheckGroundStatus(); 56 move = Vector3.ProjectOnPlane(move, m_GroundNormal); 57 m_TurnAmount = Mathf.Atan2(move.x, move.z); 58 m_ForwardAmount = move.z; 59 60 ApplyExtraTurnRotation(); 61 62 // control and velocity handling is different when grounded and airborne: 63 if (m_IsGrounded) 64 { 65 HandleGroundedMovement(crouch, jump); 66 } 67 else 68 { 69 HandleAirborneMovement(); 70 } 71 72 ScaleCapsuleForCrouching(crouch); 73 PreventStandingInLowHeadroom(); 74 75 // send input and other state parameters to the animator 76 UpdateAnimator(move); 77 78 } 79 80 81 void ScaleCapsuleForCrouching(bool crouch) 82 { 83 if (m_IsGrounded && crouch) 84 { 85 if (m_Crouching) return; 86 m_Capsule.height = m_Capsule.height / 2f; 87 m_Capsule.center = m_Capsule.center / 2f; 88 m_Crouching = true; 89 } 90 else 91 { 92 Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up); 93 float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half; 94 if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore)) 95 { 96 m_Crouching = true; 97 return; 98 } 99 m_Capsule.height = m_CapsuleHeight; 100 m_Capsule.center = m_CapsuleCenter; 101 m_Crouching = false; 102 } 103 } 104 105 void PreventStandingInLowHeadroom() 106 { 107 // prevent standing up in crouch-only zones 108 if (!m_Crouching) 109 { 110 Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up); 111 float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half; 112 if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength, Physics.AllLayers, QueryTriggerInteraction.Ignore)) 113 { 114 m_Crouching = true; 115 } 116 } 117 } 118 119 120 void UpdateAnimator(Vector3 move) 121 { 122 // update the animator parameters 123 m_Animator.SetFloat("Forward", m_ForwardAmount, 0.1f, Time.deltaTime); 124 m_Animator.SetFloat("Turn", m_TurnAmount, 0.1f, Time.deltaTime); 125 m_Animator.SetBool("Crouch", m_Crouching); 126 m_Animator.SetBool("OnGround", m_IsGrounded); 127 if (!m_IsGrounded) 128 { 129 m_Animator.SetFloat("Jump", m_Rigidbody.velocity.y); 130 } 131 132 // calculate which leg is behind, so as to leave that leg trailing in the jump animation 133 // (This code is reliant on the specific run cycle offset in our animations, 134 // and assumes one leg passes the other at the normalized clip times of 0.0 and 0.5) 135 float runCycle = 136 Mathf.Repeat( 137 m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime + m_RunCycleLegOffset, 1); 138 float jumpLeg = (runCycle < k_Half ? 1 : -1) * m_ForwardAmount; 139 if (m_IsGrounded) 140 { 141 m_Animator.SetFloat("JumpLeg", jumpLeg); 142 } 143 144 // the anim speed multiplier allows the overall speed of walking/running to be tweaked in the inspector, 145 // which affects the movement speed because of the root motion. 146 if (m_IsGrounded && move.magnitude > 0) 147 { 148 m_Animator.speed = m_AnimSpeedMultiplier; 149 } 150 else 151 { 152 // don't use that while airborne 153 m_Animator.speed = 1; 154 } 155 } 156 157 158 void HandleAirborneMovement() 159 { 160 // apply extra gravity from multiplier: 161 Vector3 extraGravityForce = (Physics.gravity * m_GravityMultiplier) - Physics.gravity; 162 m_Rigidbody.AddForce(extraGravityForce); 163 164 165 m_GroundCheckDistance = m_Rigidbody.velocity.y < 0 ? m_OrigGroundCheckDistance : 0.05f; 166 } 167 168 169 void HandleGroundedMovement(bool crouch, bool jump) 170 { 171 // check whether conditions are right to allow a jump: 172 if (jump && !crouch && m_Animator.GetCurrentAnimatorStateInfo(0).IsName("Grounded")) 173 { 174 // jump! 175 m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z); 176 m_IsGrounded = false; 177 m_Animator.applyRootMotion = false; 178 m_GroundCheckDistance = 0.1f; 179 } 180 } 181 182 void ApplyExtraTurnRotation() 183 { 184 // help the character turn faster (this is in addition to root rotation in the animation) 185 float turnSpeed = Mathf.Lerp(m_StationaryTurnSpeed, m_MovingTurnSpeed, m_ForwardAmount); 186 transform.Rotate(0, m_TurnAmount * turnSpeed * Time.deltaTime, 0); 187 } 188 189 190 public void OnAnimatorMove() 191 { 192 // we implement this function to override the default root motion. 193 // this allows us to modify the positional speed before it's applied. 194 if (m_IsGrounded && Time.deltaTime > 0) 195 { 196 Vector3 v = (m_Animator.deltaPosition * m_MoveSpeedMultiplier) / Time.deltaTime; 197 198 // we preserve the existing y part of the current velocity. 199 v.y = m_Rigidbody.velocity.y; 200 m_Rigidbody.velocity = v; 201 } 202 } 203 204 205 void CheckGroundStatus() 206 { 207 RaycastHit hitInfo; 208#if UNITY_EDITOR 209 // helper to visualise the ground check ray in the scene view 210 Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistance)); 211#endif 212 // 0.1f is a small offset to start the ray from inside the character 213 // it is also good to note that the transform position in the sample assets is at the base of the character 214 if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, m_GroundCheckDistance)) 215 { 216 m_GroundNormal = hitInfo.normal; 217 m_IsGrounded = true; 218 m_Animator.applyRootMotion = true; 219 } 220 else 221 { 222 m_IsGrounded = false; 223 m_GroundNormal = Vector3.up; 224 m_Animator.applyRootMotion = false; 225 } 226 } 227 } 228}

試したこと

ネット上の情報は隅々まで調べましたが、有効な情報は得られませんでした。
また、プログラムの一部をコメントアウトする方法を様々な位置で試してみましたが、いずれも上手く動きませんでした。

補足情報(FW/ツールのバージョンなど)

Unity バージョン:2020.3.4f1

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

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

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

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

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

guest

回答1

0

ベストアンサー

ThirdPersonCharacterの制御はRigidbodyAnimatorのルートモーション、Transformの直接操作のハイブリッドになっているようでややこしいですね...
HandleAirborneMovementなるメソッドが空中にいる時の挙動を担当しているようですが、それを下記のように変更してみるとどうでしょうか?

lang

1 void HandleAirborneMovement() 2 { 3 // apply extra gravity from multiplier: 4 Vector3 extraGravityForce = (Physics.gravity * m_GravityMultiplier) - Physics.gravity; 5 m_Rigidbody.AddForce(extraGravityForce); 6 7 m_GroundCheckDistance = m_Rigidbody.velocity.y < 0 ? m_OrigGroundCheckDistance : 0.01f; 8 9 float speed = 4.77573647112f * this.m_MoveSpeedMultiplier * this.m_Animator.GetFloat("Forward"); 10 Vector3 forward = transform.forward; 11 m_Rigidbody.velocity = new Vector3(forward.x * speed, m_Rigidbody.velocity.y, forward.z * speed); 12 }

Rigidbodyの速度をキャラクターの前方に向けて調整してやればそれらしい動きになるんじゃないかと考えました。
4.77573647112fというマジックナンバーが登場していますが、これはキャラクターが全力疾走した時のルートモーションによる移動速度の推定値です。もしStandard Assetsに収録されているアニメーションではなく独自のアニメーションをセットしている場合は、それに合わせてこの値を調整してやることで、地上を走っている時と空中移動している時の移動速度の違和感を軽減できるかと思います。
平坦な地面で適当に走り回らせての実験しかしておりませんので、何か見落としがあるかもしれません。変な挙動を見つけましたらコメントいただければ、可能であれば対処してみようと思います。

投稿2021/06/07 11:21

Bongo

総合スコア10807

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

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

tails_

2021/06/14 10:40

コメントが遅れてしまって大変申し訳ございません。プログラムに追記して動作させてみましたが、概ね「こう動いてほしい」と想定したとおりの挙動を取ってくれました。本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問