実現したいこと
3Dモデルの表面(長い円錐のようないびつなモデル)をキャラクターに歩かせたい。
イメージ的にはスーパーマリオギャラクシーのような感じ。
前提
表面に垂直なベクトルをraycastで取得しquaternion.rotationで立たせ、addforceで地面と垂直なベクトルに力を加えることで重力を再現しています。
ところがキャラクターがxまたはy方向に90度以上傾くとキャラクターの角度が0度に戻りそのまま下へと落下していってしまいます。
該当のソースコード
C#
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class agent_controller : MonoBehaviour 6{ 7 [SerializeField] float m_MovingTurnSpeed = 360; 8 [SerializeField] float m_StationaryTurnSpeed = 180; 9 [SerializeField] float m_JumpPower = 12f; 10 [Range(1f, 4f)][SerializeField] float m_GravityMultiplier = 2f; 11 [SerializeField] float m_RunCycleLegOffset = 0.2f; //specific to the character in sample assets, will need to be modified to work with others 12 [SerializeField] float m_MoveSpeedMultiplier = 1f; 13 [SerializeField] float m_AnimSpeedMultiplier = 1f; 14 [SerializeField] float m_GroundCheckDistance = 0.1f; 15 16 public Rigidbody m_Rigidbody; 17 Animator m_Animator; 18 public bool m_IsGrounded; 19 float m_OrigGroundCheckDistance; 20 const float k_Half = 0.5f; 21 float m_TurnAmount; 22 float m_ForwardAmount; 23 Vector3 m_GroundNormal; 24 float m_CapsuleHeight; 25 Vector3 m_CapsuleCenter; 26 CapsuleCollider m_Capsule; 27 bool m_Crouching; 28 public Transform m_Transform; 29 30 void Start () { 31 32 } 33 34 Vector3 inputVector; 35 void Update () { 36 CheckGroundStatus(); 37 VerticalGravity(); 38 Controller(); 39 } 40 41 public float speed; 42 public Camera camera; 43 44 void Controller(){ 45 if (Input.GetKey(KeyCode.W)) 46 { 47 transform.position += transform.forward * speed * Time.deltaTime; 48 } 49 if (Input.GetKey(KeyCode.D)) 50 { 51 transform.position += transform.right * speed * Time.deltaTime; 52 } 53 if (Input.GetKey(KeyCode.A)) 54 { 55 transform.position -= transform.right * speed * Time.deltaTime; 56 } 57 if (Input.GetKey(KeyCode.S)) 58 { 59 transform.position -= transform.forward * speed * Time.deltaTime; 60 } 61 62 transform.Rotate(new Vector3(0, Input.GetAxis("Mouse X") * 5, 0)); 63 camera.transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * 1, 0, 0)); 64 } 65 66 void VerticalGravity(){ 67 //進行方向を検知 68 inputVector = m_Transform.forward; 69 //地面に平行な進行方向へのベクトル 70 Vector3 onplane = Vector3.ProjectOnPlane(inputVector, m_GroundNormal); 71 //そっちをみる 72 m_Transform.rotation = Quaternion.LookRotation(onplane, m_GroundNormal); 73 m_Rigidbody.AddForce(-1 * m_GroundNormal * 10); 74 } 75 76 void CheckGroundStatus(){ 77 RaycastHit hitInfo; 78 // helper to visualise the ground check ray in the scene view 79 Debug.DrawRay(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistance), Color.red, 100); 80 81 // 0.1f is a small offset to start the ray from inside the character 82 // it is also good to note that the transform position in the sample assets is at the base of the character 83 if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, m_GroundCheckDistance)) 84 { 85 m_GroundNormal = hitInfo.normal; 86 m_IsGrounded = true; 87 } 88 else 89 { 90 m_IsGrounded = false; 91 m_GroundNormal = Vector3.up; 92 } 93 } 94} 95
試したこと
CheckGroundStatus()をunityのサンプルから直接引用しており、その中のRaycastの第2引数が絶対的な下方向であるVector3.downを使っていたので、代わりに相対的な下方向の-transform.upにしてみましたがやはり90度を超えた段階で落下してしまいます。
お力添えしていただけると助かります。
補足情報(FW/ツールのバージョンなど)
unity 2021.3.16f
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。