关于用Unity新系统实现第三人称移动

559 阅读2分钟

使用Player Input的Send Message模式控制输入

1、新建一个Input Actions,建立一下Action Maps以及Actions

image.png



2、如图建立分别的Actions

image.png

image.png image.png
(注意可以将Processors中的Invert Y反转Y坐标的选择勾选上,使起变成顺手的操作方式)

image.png

image.png



3、建立控制输入的C#脚本,与Player Inputs一样挂载到需要移动的物体上

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

public class InputController : MonoBehaviour
{
    private Vector2 move;
    private Vector2 point;
    private bool jump;
    private bool aim;
    private bool sprint;

    public void OnMove(InputValue value)
    {
        move = value.Get<Vector2>();
    }
    public void OnLook(InputValue value)
    {
        point = value.Get<Vector2>();
    }
    public void OnJump(InputValue value)
    {
        jump = value.Get<bool>();
    }
    public void OnAim(InputValue value)
    {
        aim = value.Get<bool>();
    }
    public void OnSprint(InputValue value)
    {
        sprint = value.Get<bool>();
    }
}

注意:如果之前建立的Actions为Move,则函数的名字需要为OnMove才能在使用Send Message中输入信息!!



建立PlayerController脚本控制角色

PlayerController_1: 将Animation转换成Int类型的变量,方便后续使用

    private Animator anim;

    private int animWS;
    private int animAD;
    private int animSprint;
    private int animAim;
    private int animGrounded;
    private int animJump;
    
    private void Awake()
    {
        anim = this.GetComponent<Animator>();
    }
    
    private void Start()
    {
        SwitchAnimName();
    }
    
    private void SwitchAnimName()
    {
        animWS = Animator.StringToHash("WS");
        animAD = Animator.StringToHash("AD");
        animSprint = Animator.StringToHash("Sprint");
        animAim = Animator.StringToHash("Aim");
        animGrounded = Animator.StringToHash("Grounded");
        animJump = Animator.StringToHash("Jump");
    }

PlayerController_2:实现跳跃功能

[Header("Player Grounded")]
public bool Ground = true;
public LayerMask GroundLayer;

    private void Update()
    {
        Jump();
        GroundedCheck();
    }

    private void Jump()
    {
        if (Grounded)
        {
            anim.SetBool(animJump, true);
        }
    }

    private void GroundedCheck()
    {
        Grounded = Physics.CheckSphere(new Vector3(this.transform.position.x, this.transform.position.y - GroundOffset, this.transform.position.z), CheckRadius, GroundLayer);
    }

PlayerController_3:实现人物移动

    private InputController input;
    private void Awake()
    {
        anim = this.GetComponent<Animator>();
        input = this.GetComponent<InputController>();
    }
    
    private void Update()
    {
        Move();
    }
    
    private void Move()
    {
        anim.SetFloat(animWS, input.move.x);
        anim.SetFloat(animAD, input.move.y);
    }

在Move中,只对动画进行了设置是因为动画中包含了移动,使用的是Unity购买的资源项目,再到Mixamo.com中找的动作资源,通过重定向进行了绑定。如果动作中不包含移动,则可以使用Character Controller组件Move()方法进行移动。

PlayerController_3:实现人物始终面对镜头前方

    [Header("Camera Rotate")]
    public GameObject CinemachineTarget;
    public float TurningSpeed = 5f;
    public bool LockCamera = false;
    public float CameraTargetYaw;
    public float CameraTargetPitch;
    public float TopClamp = 70f;
    public float BottomClamp = -30f;
    private const float threshold = 0.01f;
    
    private LateUpdate()
    {
        CameraRotation();
    }
    private void CameraRotation()
    {
        if(input.point.sqrMagnitude >= threshold && !LockCamera)
        {
            CameraTargetYaw += input.point.x * Time.deltaTime;
            CameraTargetPitch += input.point.y * Time.deltaTime;
        }
        CameraTargetYaw = ClampAngle(CameraTargetYaw, float.MinValue, float.MaxValue);

        this.transform.rotation = Quaternion.Euler(0, CameraTargetYaw * TurningSpeed, 0);
        CinemachineTarget.transform.rotation = Quaternion.Euler(CameraTargetPitch * TurningSpeed, CameraTargetYaw * TurningSpeed, 0);
    }
    
    //将角度限制到 -360 +360之间
    private static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360f) angle += 360f;
        if (angle > 360f) angle -= 360f;
        return Mathf.Clamp(angle, min, max);
    }

因为Cinemachine中Virtual Camera无法直接旋转,所以Create一个Player的子对象作为Virtual Camera的Follow对象。通过对这个对象的旋转,来旋转镜头。
实现了类似于和平精英一样的镜头移动方式,但人的上半身持枪跟着镜头移动未实现。

总结:

新的输入系统在简单的使用上,通过一定的学习,确实能优化输入系统,尤其是当有多种控制方式的时候(例如:手柄、键盘)。Send Message模式用起来感觉比直接通过脚本控制或者Invoke Unity Events模式更加方便。而使用了Maximo中的人型模型的重定向,虽然能避免写移动的逻辑以及动画制作,但是也会失去对移动逻辑的一些控制,有利有弊,可以根据自己的需求来选择是否使用Maximo中的动作模型。