第一人称视角移动——刚体遇碰撞体产生反弹

问题介绍

在使用第一人称控制人物移动过程中,每次当代表人物的胶囊体和墙壁或场景中模型的碰撞体进行碰撞时,人物会被反弹,并且会进行旋转。
下图是出现Bug时的人物刚体设置:
在这里插入图片描述

问题分析

会出现这个问题是由于,物体的物理逻辑一般写在FixedUpdate中。根据Unity运行时序,移动物体加刚体后,在Update中碰撞体跟着物体进行了移动,那么这一次的生命周期循环里,Update之后没有物理判断了。这一帧的画面渲染出来的时候,物体碰撞体是嵌入了墙体。而在下一帧的FixedUpdate进行了物理判断,发现碰撞体是嵌入的。那么按照物理规则,物理引擎把物体给弹出来保证物理正确。这样也就导致我们看到物体发生碰撞时,人物会发生抖动。

解决问题

对于这个问题,可以从下面两个角度进行检查:
1.刚体的移动代码是否是写在FixedUpdate()函数中;
2.是否对刚体进行正确的坐标轴限定。

解决方案

(1)人物移动(绑定到人物模型上):

using System.Collections.Generic;
using UnityEngine;

public class FirstPersonMovement : MonoBehaviour
{
    
    
    public float speed = 5;

    [Header("Running")]
    public bool canRun = true;
    public bool IsRunning {
    
     get; private set; }
    public float runSpeed = 9;
    public KeyCode runningKey = KeyCode.LeftShift;

    Rigidbody rigidbody;
    /// <summary> Functions to override movement speed. Will use the last added override. </summary>
    public List<System.Func<float>> speedOverrides = new List<System.Func<float>>();

    void Awake()
    {
    
    
        // Get the rigidbody on this.
        rigidbody = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
    
    
        
        if (Manager.Instance.IsStart)
        {
    
    
            // Update IsRunning from input.
            IsRunning = canRun && Input.GetKey(runningKey);

            // Get targetMovingSpeed.
            float targetMovingSpeed = IsRunning ? runSpeed : speed;
            if (speedOverrides.Count > 0)
            {
    
    
                targetMovingSpeed = speedOverrides[speedOverrides.Count - 1]();
            }

            // Get targetVelocity from input.
            Vector2 targetVelocity = new Vector2(Input.GetAxis("Horizontal") * targetMovingSpeed, Input.GetAxis("Vertical") * targetMovingSpeed);

            // Apply movement.
            rigidbody.velocity = transform.rotation * new Vector3(targetVelocity.x, rigidbody.velocity.y, targetVelocity.y);
        }
    }
}

(2)刚体设置:
在这里插入图片描述
注意:刚体中冻结XYZ的旋转轴,并不会影响到代码中对人物进行视角控制时,人物模型的旋转
(3)视角控制(绑定到摄像机上):

using UnityEngine;

public class FirstPersonLook : MonoBehaviour
{
    
    
    [SerializeField]
    Transform character;
    public float sensitivity = 2;
    public float smoothing = 1.5f;

    //Vector2 velocity;
    //Vector2 frameVelocity;

    // 水平视角移动的敏感度
    public float sensitivityHor = 1f;
    // 垂直视角移动的敏感度
    public float sensitivityVer = 1f;
    // 视角向上移动的角度范围,该值越小范围越大
    public float upVer = -50;
    // 视角向下移动的角度范围,该值越大范围越大
    public float downVer = 50;
    // 垂直旋转角度
    private float rotVer;

    void Reset()
    {
    
    
        // Get the character from the FirstPersonMovement in parents.
        character = GetComponentInParent<FirstPersonMovement>().transform;
    }

    void Start()
    {
    
    
        // Lock the mouse cursor to the game screen.
        //Cursor.lockState = CursorLockMode.Locked;
    }

    void Update()
    {
    
    
        if(Manager.Instance.IsStart)
        {
    
    
            /*if (Input.GetMouseButton(0))
            {
                // Get smooth velocity.
                Vector2 mouseDelta = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
                Vector2 rawFrameVelocity = Vector2.Scale(mouseDelta, Vector2.one * sensitivity);
                frameVelocity = Vector2.Lerp(frameVelocity, rawFrameVelocity, 1 / smoothing);
                velocity += frameVelocity;
                velocity.y = Mathf.Clamp(velocity.y, -90, 90);

                // Rotate camera up-down and controller left-right from velocity.
                transform.localRotation = Quaternion.AngleAxis(-velocity.y, Vector3.right);
                Quaternion rotation = Quaternion.AngleAxis(velocity.x, Vector3.up);
                character.localRotation = rotation;
            }*/
            if (Input.GetMouseButton(0))
            {
    
    
                // 获取鼠标上下的移动位置
                float mouseVer = Input.GetAxis("Mouse Y");
                // 获取鼠标左右的移动位置
                float mouseHor = Input.GetAxis("Mouse X");
                // 鼠标往上移动,视角其实是往下移,所以要想达到视角也往上移的话,就要减去它
                rotVer -= mouseVer * sensitivityVer;
                // 限定上下移动的视角范围,即垂直方向不能360度旋转
                rotVer = Mathf.Clamp(rotVer, upVer, downVer);
                // 设置视角的移动值
                transform.localEulerAngles = new Vector3(rotVer, 0, 0);//控制摄像机的上下视角移动(玩家不动)
                /*Debug.Log(character.transform.localEulerAngles.y);
                Debug.Log(mouseHor);
                Debug.Log(Vector3.up);
                Debug.Log(Vector3.up * mouseHor);
                character.transform.Rotate(Vector3.up * mouseHor);//转动玩家的水平视角移动(摄像机也会动)
                Debug.Log(character.transform.localEulerAngles.y);
                Debug.Log("11111111111111111111111111111111111111111");*/
                character.transform.localEulerAngles += Vector3.up * mouseHor;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qingtian_111/article/details/129047543
今日推荐