Una implementación simple de un controlador de personajes FPS de disparos en primera persona basado en CharacterController-Unity Notes (2021.1.19)

Como me estaba preparando para el examen al final del semestre anterior, no lo he escrito en mucho tiempo. Hoy comencé a usar Unity para hacer un juego de disparos en primera persona.


Lo que logramos hoy:

  • Basado en la función de movimiento en primera persona de CharacterController, aprendí sobre la diferencia entre CharacterController.Move y CharacterController.SimpleMove. La diferencia entre Move y SimpleMove en CharacterController

  • Efecto de gravedad (no realista)

  • Efecto de salto El salto se ve afectado por el estado de movimiento actual

  • Efecto Sprint, mayor velocidad de movimiento.

  • El efecto de sentadilla se logra cambiando el CharacterController.Height, con velocidad de marcha de sentadilla independiente y velocidad de sprint de sentadilla.


ERROR y defectos:

¿Es mi escritura estándar? No lo sé, pero funciona.


vale la pena tomar nota de:

Cuando se juzga el sprint, se tiene en cuenta el movimiento, de modo que pueda evitar saltar a la altura del sprint presionando el botón de sprint cuando no se está moviendo.

Cabe señalar que la longitud del módulo de la dirección de movimiento obtenida se establece en 1 y se puede utilizar normalizar. Esto se hace para evitar una situación en la que el desplazamiento de la longitud del módulo mayor que 1 se hace mayor cuando se ingresan tanto Horizontal como Vertical, es decir, la velocidad se vuelve más rápida cuando se viaja en diagonal. Tenga en cuenta que no se puede configurar cuando la longitud del molde es menor que 0.


Código:

Basado en CharacterController

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

public class FPCharacterControllerMovement : MonoBehaviour
{
    
    
    //-----------------------------------------------------运动-----------------------------------------------------------------//
    // 走路的速度
    public float walkSpeed = 10f;
    // 奔跑的速度
    public float sprintingSpeed = 20f;
    // 重力
    public float grivaty = 9.8f;
    // 跳跃高度
    public float jumpHeight = 2f; 
    // 下蹲之后的高度
    public float crouchHeight = 1f;
    // 站立时的高度
    [HideInInspector]
    public float originHeight;
    // 下蹲时的冲刺的速度
    public float crouchWalkSpeed = 5f;
    public float crouchSprintSpeed = 5f;
    // 当前在冲刺
    [HideInInspector]
    public bool m_isSprinting;
    // 当前是否蹲下了
    [HideInInspector]
    public bool m_isCrouched;
    // 当前是否正在蹲下/起立 用于协程控制
    [HideInInspector]
    public bool m_isDoCrouching;

    // 对CharacterController的引用
    private CharacterController m_characterController;
    // 对Transform的引用
    private Transform m_characterTransform;
    // 移动的方向
    private Vector3 m_movementDirection;
    // 当前使用哪个速度(Walk or Sprint)
    private float m_currentSpeed;

    //------------------------------------------------------动画----------------------------------------------------------------//
    private Animator m_characterAnimator;
    private float m_velocity;

    private void Start() 
    {
    
    
        // 运动
        m_currentSpeed = walkSpeed;
        m_characterController = GetComponent<CharacterController>();
        m_characterTransform = transform;
        m_isCrouched = false;
        m_isDoCrouching = false;
        originHeight = m_characterController.height;

        // 动画
        m_characterAnimator = GetComponentInChildren<Animator>();
    }

    private void Update()
    {
    
    
        
        //触地判断
        if (m_characterController.isGrounded) 
        {
    
    
            //------------------------------------------运动--------------------------------------------------------//
            // 获得输入
            float temp_Horizontal = Input.GetAxis("Horizontal");
            float temp_Vertical = Input.GetAxis("Vertical");

            // 将方向从对象的自身坐标系转换为世界坐标系
            m_movementDirection = m_characterTransform.TransformDirection(
                new Vector3(temp_Horizontal, 0, temp_Vertical));
            
            // 这是为了防止Horizontal和Vertical都有输入时
            // 出现movementDirection模长大于1的情况
            // 保证速度的恒定
            if(m_movementDirection.sqrMagnitude > 1)
            {
    
    
                m_movementDirection = m_movementDirection.normalized;
            }

            // SimpleMove是带有重力效果的 目前不使用
            //characterController.SimpleMove(temp_MovementDirection * Time.deltaTime * speed); 

            // 是否按着冲刺键并且拥有运动
            // 运动不考虑y轴的跳跃
            if (Input.GetKey(KeyCode.LeftShift) && 
                m_movementDirection.x != 0 &&
                m_movementDirection.z != 0)
            {
    
    
                // 如果条件符合 m_isSprinting设置为true 状态为冲刺
                m_isSprinting = true; 
            }
            else
            {
    
    
                m_isSprinting = false;
            }

            // 是否按下跳跃键
            if (Input.GetButtonDown("Jump"))
            {
    
    
                m_movementDirection.y = jumpHeight;
            }

            // 是否按下下蹲键
            if (Input.GetKeyDown(KeyCode.C))
            {
    
    
                // 正在下蹲或者起立时 不能更新状态 防止BUG
                if(!m_isDoCrouching)
                {
    
    
                    //当前是否已经蹲下了
                    float temp_currentHeight =
                        (m_isCrouched) ? originHeight : crouchHeight;
                    // 正在下蹲/起立
                    m_isDoCrouching = true;
                    // 因为下蹲(起立)是一个过程 所以用协程
                    StartCoroutine(DoCrouch(temp_currentHeight));
                    // 将下蹲状态设置为反状态
                    m_isCrouched = !m_isCrouched;
                }
            }

            // 是否是下蹲状态
            if(m_isCrouched)
            {
    
    
                m_currentSpeed = (m_isSprinting) ? crouchSprintSpeed : crouchWalkSpeed;
            }
            else
            {
    
    
                m_currentSpeed = (m_isSprinting) ? sprintingSpeed : walkSpeed;
            }
            //------------------------------------------------------------------------------------------------------//

            //------------------------------------------动画--------------------------------------------------------//

            Vector3 temp_velocity = m_characterController.velocity;
            temp_velocity.y = 0; //过滤掉跳跃带来的影响
            m_velocity = temp_velocity.magnitude; 
            m_characterAnimator.SetFloat("Velocity", m_velocity, 0.1f, Time.deltaTime);
            //------------------------------------------------------------------------------------------------------//
        }

        // 重力效果
        m_movementDirection.y -= grivaty * Time.deltaTime;

        // 实际的移动
        // 这样写有一些问题
        // 比如重力受移动速度的影响
        m_characterController.Move(m_movementDirection * Time.deltaTime * m_currentSpeed);
    }

    // 下蹲/站立的协程
    private IEnumerator DoCrouch(float target)
    {
    
    
        while(Mathf.Abs(m_characterController.height - target) > 0.0001f)
        {
    
    
            float temp_currentHeight = 0;
            yield return null;
            m_characterController.height = Mathf.SmoothDamp(
                m_characterController.height,
                target, 
                ref temp_currentHeight, 
                Time.deltaTime * 3f);
        }
        m_isDoCrouching = false; //对吗?目前看来没问题
    }
}

Basado en Rigidbody

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

public class FPMovement_Rigidbody : MonoBehaviour
{
    
    
    public float speed;
    public float gravity;
    public float jumpHeight;

    private Rigidbody m_rigidbody;
    private bool m_isGrounded;
    private bool isJumping;

    void Start()
    {
    
    
        m_rigidbody = this.GetComponent<Rigidbody>();
    }

    private void Update()
    {
    
    
        // 只有在地面上时才能起跳
        if(m_isGrounded)
        {
    
    
            // 跳跃逻辑判断
            if (Input.GetButtonDown("Jump"))
            {
    
    
                Debug.Log("Jump!");
                isJumping = true;
            }
        }
        else
        {
    
    
            // 在空中时,要将isJumping设置为false
            isJumping = false;
        }
    }

    void FixedUpdate()
    {
    
    
        // 玩家只有触地时才能移动和跳跃
        if (m_isGrounded)
        {
    
    
            float horizontal = Input.GetAxis("Horizontal");
            float vertical = Input.GetAxis("Vertical");

            Vector3 currentDirection = new Vector3(horizontal, 0, vertical); //这个坐标系是局部的,需要转换到世界坐标后再使用
            currentDirection = this.transform.TransformDirection(currentDirection.normalized); //normalized是为了保证速度大小的一致
            currentDirection *= speed;

            Vector3 currentVelocity = m_rigidbody.velocity; //获取当前的速度
            Vector3 velocityChange = currentDirection - currentVelocity; //用户输入的速度减去当前速度来获取实际需要的速度
            velocityChange.y = 0;  //暂时不计算这个值

            m_rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);

            // 跳跃
            if(isJumping)
            {
    
    
                m_rigidbody.velocity = new Vector3(velocityChange.x, CalculateJumpHeightSpeed(), velocityChange.z);
            }
        }

        // 重力
        m_rigidbody.AddForce(Vector3.down * gravity);
    }

    // 计算要达到跳跃高度需要的y轴速度
    private float CalculateJumpHeightSpeed()
    {
    
    
        return Mathf.Sqrt(2 * gravity * jumpHeight);
    }

    // 这只是一个相当简单的方法
    private void OnCollisionEnter(Collision collision)
    {
    
    
        m_isGrounded = true;
    }

    //private void OnCollisionStay(Collision collision)
    //{
    
    
    //    m_isGrounded = true;
    //}

    private void OnCollisionExit(Collision collision)
    {
    
    
        m_isGrounded = false;
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_37856544/article/details/112813129
Recomendado
Clasificación