RigidBody+AddForceでの移動を作るための下地メモです。
(今回初作成なので、もっとうまいやり方はあると思います)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField]
public Rigidbody m_RigidBody;
[SerializeField]
private LayerMask m_GroundLayer;
public float m_JumpPower;
RaycastHit m_GroundHit;
//RaycastHit[] m_GroundHits;
bool m_IsGrounded = false;
float m_CheckGroundWait = 0.0f;
// Start is called before the first frame update
void Start()
{
//
}
// Update is called once per frame
void Update()
{
UpdateIsGrounded();
if( !m_IsGrounded ) return;
// FixedUpdateだと入力がうまくとれないことがあるので、ジャンプはこっちで。
Jump();
}
void FixedUpdate()
{
if( !m_IsGrounded ) return;
var hori = Input.GetAxisRaw( "Horizontal" );
var vert = Input.GetAxisRaw( "Vertical" );
var baseVector = new Vector3( hori, 0, vert );
var moveVector = Vector3.zero;
if( 0.0f < baseVector.magnitude )
{
// 足元の接触面から進行方向のベクトル取得(坂道での速度減衰対策)
moveVector = Vector3.ProjectOnPlane( baseVector, m_GroundHit.normal );
//for( int i = 0; i < m_GroundHits.Length; i++ )
//{
// moveVector += Vector3.ProjectOnPlane( baseVector, m_GroundHits[i].normal );
//}
if( moveVector.magnitude > 1 )
{
moveVector.Normalize();
}
// 移動処理
var maxVelocity = 5.0f;
var factor = ( maxVelocity * moveVector.magnitude - m_RigidBody.velocity.magnitude ) / Time.fixedDeltaTime;
m_RigidBody.AddForce( moveVector * factor * m_RigidBody.mass );
//m_RigidBody.velocity = moveVector * maxVelocity;
//m_RigidBody.MovePosition( transform.position + 0.003f * moveVector / Time.fixedDeltaTime );
}
}
private void UpdateIsGrounded()
{
// ジャンプ直後はまだ地面の接触判定が取れてしまう可能性があるので判定のウェイト
if( 0.0f < m_CheckGroundWait )
{
m_CheckGroundWait -= Time.deltaTime;
m_IsGrounded = false;
return;
}
// 接触判定。進行方向取得のため地面のオブジェクトも取得。
m_IsGrounded = Physics.SphereCast( transform.position + new Vector3( 0.0f, 0.9f, 0.0f ), 0.3f, Vector3.down, out m_GroundHit, 0.65f, m_GroundLayer );
//m_GroundHits = Physics.SphereCastAll( transform.position + new Vector3( 0.0f, 0.9f, 0.0f ), 0.3f, Vector3.down, 0.65f, m_GroundLayer );
}
void Jump()
{
if( !m_IsGrounded ) return;
if( Input.GetKeyDown( KeyCode.Space ) )
{
var hori = Input.GetAxisRaw( "Horizontal" );
var vert = Input.GetAxisRaw( "Vertical" );
var moveVector = new Vector3( hori, 0, vert );
moveVector = Vector3.ProjectOnPlane( moveVector, m_GroundHit.normal );
if( moveVector.magnitude > 1 )
{
moveVector.Normalize();
}
moveVector.y += 10.0f;
moveVector.Normalize();
m_RigidBody.AddForce( moveVector * m_JumpPower, ForceMode.Impulse );
m_CheckGroundWait = 0.5f;
}
}
}
動かすRigidBodyのmassは人体想定でとりあえず60。
ApplyRootMotionがONだとAddForceがうまく動かないのでOFFに変更。
地面の判定を取るために、地面に当たるオブジェクトにはgroundタグやgroundレイヤーを付けて判定。
地面側のPhysicMaterialはデフォルトの状態を使用。
動かすキャラ側はFrictionCombineをMultiplyにして、数値をそれぞれ3.0に。
このあたりの数値設定系はどうするのが良いのかよく分からなかったので、一旦上記の形に。
(各プロジェクト、やりたいことで変わるからベースの指標があまり無さそうな気配)
その他のメモ
・AddForceの移動は徐々にスピードが上がっていく感じなので、割と挙動的に良さげ。
ただ、他記事でもあるように、地面を滑るような挙動になるのでそのあたりがうまく嚙み合わない場合は他の移動を使ったほうが良さげ。
あと、坂に入るときに急角度の変化だと上下の移動成分が徐々に上がる形なので、少し止まる挙動になって不自然になる。
ジャンプ後も着地後から力がかかるので、動きだしが遅くなる。
・rigidbodyのvelocityを直接弄る方式での移動だと、一気にトップスピードでの移動になるので、場合によってはこちらのほうが良いかも。
こちらも滑りは発生する。
・MovePositionの方式は、IsKinematicをONにしないと正しい動作にならない。
適宜切り替えて運用できるなら・・・。
こちらは移動が瞬間移動なので滑らない。