Unity 角色控制器的幾種實現方式(CharacterController驅動,剛體驅動,動畫驅動)


一.CharacterController組件驅動

這是常用的角色控制方式,但是最大的缺點就是無法被力所驅動,因此,很難做出沖撞的抵觸效果

另外這里要說明:

第一種:characterController.SimpleMove(Speed);
第二種:characterController.Move(Speed*deltaTime);
發生的問題:第一種和第二種垂直移動效果不同。
解決:官方文檔:第一種始終使用的是系統的默認垂直加速度,而第二種要自己實現。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色控制器控制角色物理效果
/// </summary>
public class PlayerControllerTest00 : MonoBehaviour
{
    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
    private Vector3 moveDirection = Vector3.zero;

    void Update()
    {
        CharacterController controller = GetComponent<CharacterController>();
        if (controller.isGrounded)
        {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetKeyDown(KeyCode.Space))
                moveDirection.y = jumpSpeed;
        }

        moveDirection.y -= gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
    }
}

這里借用了某位老兄的代碼:https://www.cnblogs.com/ChenZiRong1999/p/13395132.html

這里產生了一個疑問,如果有知道的網友,給我留個評論:

遇到一個玄學Bug,用角色控制器做了一個角色控制組件,采用兩種方式:
第一種:角色外層根用空物體然后掛上組件,動畫模型物體作為子物體。
第二種:動畫模型物體直接為根物體,並且模型沒有位移動畫。
移動代碼charactorController.SimpleMove(verticalSpeed+horizonSpeed);
發生的問題:第一種比第二種飄,也就是從一個物體邊緣走出去落下的過程中第一種很飄,貌似垂直速度不符合效果。

二.剛體驅動

這里使用膠囊碰撞體加剛體組件的方式來實現,從而可以實現沖撞效果,缺點是需要大量的時間來調整,而且代碼干涉物理效果,並且物理更新與渲染更新並不同步,因此角色的移動會相對看起來比較抖動,當然無論代碼是放在FixedUpdate()還是Update()都和很難完全消除抖動,更多的是從相機動手,讓相機的跟隨抵消不同步抖動帶來的視覺干擾。

在剛體下有幾種移動方式,具體如代碼中所示。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 剛體角色控制器控制角色
/// </summary>
public class PlayerControllerTest01 : MonoBehaviour
{
    Rigidbody rigid;

    public float moveSpeed;
    private Vector3 moveDirection = Vector3.zero;//角色的方向
    float moveScale = 0;
    private void Awake()
    {
        rigid = GetComponent<Rigidbody>();
    }

    private void Update()
    {

        //跳躍:為剛體施加一個向上的力:該力是由向上的跳躍速度和在剛體原速度方向上的一個速度合成的
        //VelocityChange是一個瞬時速度
        if (Input.GetKeyDown(KeyCode.Space)) {
            rigid.AddForce(transform.up * 20 /*+ rigid.velocity.normalized * directionalJumpFactor*/, ForceMode.VelocityChange);
        }
        
        moveScale = 0;
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S))
        {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveScale = 1;
        }

        //旋轉,使用剛體的旋轉
        Quaternion rot = Quaternion.Euler(0, Vector3.SignedAngle(Vector3.forward, moveDirection, Vector3.up), 0);//目標旋轉
        Quaternion currentRot = Quaternion.RotateTowards(rigid.rotation, rot, Time.deltaTime * 600);//中間插值旋轉
        rigid.MoveRotation(currentRot);

        //水平移動
        Vector3 v = Vector3.Project(rigid.velocity, transform.forward);
        float s = moveSpeed == 0 ? 0 : 1 - v.magnitude / moveSpeed;
        //rigid.AddForce(transform.forward * moveScale * s, ForceMode.VelocityChange);//第一種:力驅動,好處:比較真實具體移動交給物理系統;缺點:不好控制,容易滑動
        //rigid.velocity = transform.forward * 10 * moveScale + Vector3.up * rigid.velocity.y;//第二種:速度設置,好處:直接設置速度;缺點:直接干涉物理速度,抖動失真
        //if (moveScale == 1) rigid.MovePosition((rigid.position + transform.forward * moveSpeed * Time.deltaTime));//第三種:直接物理位置,好處:直接移動,缺點:目前描述不出來
    }

    private void FixedUpdate()
    {
        if (moveScale == 1) rigid.MovePosition((rigid.position + transform.forward * moveSpeed * Time.fixedDeltaTime));
    }
}

 同樣,參考某位老兄的代碼:https://blog.csdn.net/qq_38327432/article/details/91561247

二.動畫驅動

顧名思義,這里代碼只是改變動畫狀態機的狀態參數,移動動畫自身帶有位移,這樣的好處就是動畫效果和位移等效果完美契合,整個的動畫都交由動畫師來完成,缺點是整個過程的動畫參數量大,至於動畫遇到的問題,做的少,暫時不知道。代碼demo,暫時沒有資源,沒有做

 

 

寫了半天必須配張圖啊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM