Unity3D开发日志一:#1 3DRPG中的人物移动和相机跟随

 一、人物移动

        在大多数的游戏当中,不仅有玩家本身需要移动,游戏内的许多NPC也需要移动,因此我们可以将“人物移动”的代码拆分成“人物”代码和“移动”代码,这样一来,便可以方便我们后期的维护,并不需要分别为玩家和NPC都写下移动的代码。

1.关于角色移动

[RequireComponent(typeof(Rigidbody))]
public class CharacterMovement: MonoBehaviour
{
    private Rigidbody _rigidbody;

    public Vector3 CurrentInput { get; private set; }
    public float MaxWalkSpeed = 5;
    private void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }


    private void FixedUpdate()
    {
        _rigidbody.MovePosition(_rigidbody.position + CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime);
    }

    public void SetMovementInput(Vector3 input)
    {
        CurrentInput = Vector3.ClampMagnitude(input, 1);
    }
}

       MovePosition意为“新的位置”,可为挂载Rigidbody组件的物体而用,是一个路程单位,而路程=速度*时间,因此可以写为“新的位置=当前的位置+移动速度*时间”,即

_rigidbody.MovePosition(_rigidbody.position + CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime);

        用以确保CurrentInput为模长为1的向量:

 CurrentInput = Vector3.ClampMagnitude(input, 1);

        可以通过以下写法做到一个属性对外只读,对类自身而言可以对其值进行修改

public Vector3 CurrentInput { get; private set; }

        使用RequireComponent可以让挂载此C#的物体自带组件

2.关于玩家角色

public class PlayerCharacter: MonoBehaviour
{
    private CharacterMovement _characterMovement;

    [SerializeField]
    private Photographer _photographer;

    [SerializeField] private Transform _followingTarget;

    private void Awake()
    {
        _characterMovement = GetComponent<CharacterMovement>();

        _photographer.InitCamera(_followingTarget);
    }

    void Update()
    {
        UpdateMovementInput();
    }

    private void UpdateMovementInput()
    {
        Quaternion rot = Quaternion.Euler(0, _photographer.Yaw, 0);

        _characterMovement.SetMovementInput(rot * Vector3.forward * Input.GetAxis("Vertical") +
                                            rot * Vector3.right * Input.GetAxis("Horizontal"));
    }
}

        [SerializeField]----将私有类型和保护类型可视化到面板上

二、相机跟随

        在写下相机跟随的代码前,我们需要先为摄像机创建一个坐标轴

        在大多数第三人称游戏中,摄像机并不会完完全全地跟随玩家角色,大多数游戏里当玩家向前移动时,操控者都可以移动视角达到看玩家的正面,以达到向前移动时仍可以观察四周

        在Unity中Project Settings自带的方法中,就存在自带的一个坐标轴:

                MouseX,MouseY给出是一个“距离”,即鼠标所移动的距离

                而Horizontal(水平的)与Vertical(竖直的)给出的则是一个比率

                即当其数值为0的时候,则静止;数值为1的时候,则移动;0.5则为半速移动

        因此,显然Horizontal相比于MouseX更适合做摄像机移动的坐标轴,我们便可

        复制Horizontal,改名为“CameraRateX”,并设定为第4坐标系

        复制Vertical,改名为“CameraRateY”,并设定为第5坐标系,将此作为摄像机坐标轴

public class Photographer : MonoBehaviour
{
    public float Pitch { get; private set; }
    public float Yaw { get; private set; }

    public float mouseSensitivity = 5;

    public float cameraRotatingSpeed = 80;
    public float cameraYSpeed = 5;
    private Transform _target;
    private Transform _camera;
    [SerializeField] private AnimationCurve _armLengthCurve;

    private void Awake()
    {
        _camera = transform.GetChild(0);
    }

    public void InitCamera(Transform target)
    {
        _target = target;
        transform.position = target.position;
    }

    void Update()
    {
        UpdateRotation();
        UpdatePosition();
        UpdateArmLength();
    }


    private void UpdateRotation()
    {
        Yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
        Yaw += Input.GetAxis("CameraRateX") * cameraRotatingSpeed * Time.deltaTime;
        Pitch += Input.GetAxis("Mouse Y") * mouseSensitivity;
        Pitch += Input.GetAxis("CameraRateY") * cameraRotatingSpeed * Time.deltaTime;
        Pitch = Mathf.Clamp(Pitch, -90, 90);

        transform.rotation = Quaternion.Euler(Pitch, Yaw, 0);
    }

    private void UpdatePosition()
    {
        Vector3 position = _target.position;
        float newY = Mathf.Lerp(transform.position.y, position.y, Time.deltaTime * cameraYSpeed);
        transform.position = new Vector3(position.x, newY, position.z);
    }

    private void UpdateArmLength()
    {
        _camera.localPosition = new Vector3(0, 0, _armLengthCurve.Evaluate(Pitch) * -1);
    }
}

       其中Pitch为绕X轴旋转,Yaw为绕竖直方向的Y轴旋转

 Yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
 Yaw += Input.GetAxis("CameraRateX") * cameraRotatingSpeed * Time.deltaTime;
 Pitch += Input.GetAxis("Mouse Y") * mouseSensitivity;
 Pitch += Input.GetAxis("CameraRateY") * cameraRotatingSpeed * Time.deltaTime;

        mouseSensitivity为鼠标灵敏度

        其中“+=”:用于指定响应事件时要调用的方法,这类方法称为事件处理程序,叫注册/订阅事件,用在操作类名后

        

        在大多数第三人称游戏中,往上拖动视角可以看向天空,但若一直往上拉,则会导致像太空类游戏一样视角倒转,因此需要规定摄像机可旋转的最大范围

Pitch = Mathf.Clamp(Pitch, -90, 90);

        

        在大多数第三人称游戏中,当把视角往下拉,摄像机则会越来越靠近人物,这是为了防止摄像机看到地下,因此,我们需要一个添加一条曲线并设定摄像机臂长方法

        此外,我们可以创建一个空物体放置在玩家的头部,以确保相机一直跟随着玩家的头部

[SerializeField] private AnimationCurve _armLengthCurve;
private void UpdateArmLength()
    {
        _camera.localPosition = new Vector3(0, 0, _armLengthCurve.Evaluate(Pitch) * -1);
    }

        将曲线的两点设为(-90,0.8)和(90,10)

        关于在摄像机旋转所用到的欧拉角相关知识,参考:

Unity之C#学习笔记(4):Unity中旋转的表示——四元数 Quaternion(上)_quaternion xyzw_Altair_Alpha_的博客-CSDN博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值