乐趣区

关于unity:黑魂复刻游戏的玩家控制器基础移动动画实现及优化Unity随手记

明天实现的内容:
动画机设计理念
要我说,动画机真的是陈词滥调的货色了。做了好几次了,目前也就是将角色的高空动画做进去。
设计理念就是应用混合树 ground 将高空挪动动画对立治理起来。

动画机的使用及模型旋转
要使用动画机,须要将动画机和输出模块串接起来。所以咱们须要新的脚本,没错,PlayerController。同样的,棘手解决角色的旋转性能,旋转的思路为间接批改模型的 forward。

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

public class PlayerController : MonoBehaviour
{
    // 玩家的人物模型 用来获取模型身上的动画机以及其它
    public GameObject model;
    // 输出模块
    public PlayerInput pi;
    // 动画机
    private Animator anim;

    // Awake 适宜用来做 GetComponent
    void Awake()
    {anim = model.GetComponent<Animator>();
        pi = GetComponent<PlayerInput>();}

    // Update is called once per frame
    void Update()
    {
        // 将输出转换为速度 赋值给动画机相干参数
        anim.SetFloat("forward", pi.dirMag);
        // 只在有速度时可能旋转 避免原地旋转
        if(pi.dirMag > 0.1f)
            model.transform.forward = pi.dirVec;
    }
}

在咱们的计划中,旋转的只是模型,PlayerController 所在的父物体节点不会旋转

咱们能够将旋转和输出的模长计算放到 PlayerInput 中进行,能让咱们的代码看起来更丑陋。

    // 玩家的输出模长量 用于当成向前量大小作为动画管制
    public float dirMag;
    // 玩家的方向 用于旋转模型
    public Vector3 dirVec;

    // Update is called once per frame
    void Update()
    {
        // 计算输出模长
        dirMag = Mathf.Sqrt((dirUp * dirUp) + (dirRight * dirRight));
        // 计算玩家的方向
        dirVec = dirRight * transform.right + dirUp * transform.forward;
        // ...
    }

网络游戏玩家角色的位移
对于挪动,这次咱们将采纳 Rigidbody 计划。通过间接批改刚体的地位来挪动。

    // 刚体
    public Rigidbody rigidbody;
    // 行走速度
    public float walkSpeed = 2.0f;
    // 角色的位移大小
    private Vector3 movingVec;
    
    // Update is called once per frame
    void Update()
    {
        // ...
        
        // 计算挪动量 速度向量
        movingVec = pi.dirMag * model.transform.forward * walkSpeed;

    }
    
    // 解决刚体的操作
    private void FixedUpdate()
    {
        // 间接批改 position 实现位移
        rigidbody.position += movingVec * Time.fixedDeltaTime;
         批改 rb.velocity 来实现位移
        //rb.velocity = new Vector3(m_planarVec.x, rb.velocity.y, m_planarVec.z)
    }

爬坡测试
据说黑魂外面的斜楼梯实际上都是斜坡,这就是咱们采纳 Rigidbody 的起因,因为 Rigidbody 解决爬坡比较简单,绝对的 CharacterController 解决爬楼梯比较简单。


坡度比拟缓的坡咱们能够爬上去,未来会持续欠缺爬坡的能力。

跑步
在原根底上退出奔跑。首先退出新的输出按键。并且在 Update 中判断是否按下对应按键

    public string keyRun; // 跑步键
    
    // 是否正在奔跑 按压信号
    public bool run; 
    
    // Update is called once per frame
    void Update()
    {
        // 跑步信号
        run = Input.GetKey(keyRun);
        // ...
    }

依据 run 的虚实来调整 PlayerController 中的动画参数和挪动速度。

    // Update is called once per frame
    void Update()
    {
        // 将输出转换为速度 赋值给动画机相干参数
        anim.SetFloat("forward", pi.dirMag * (pi.run ? 2.0f : 1.0f));
        // 计算挪动量 速度向量
        movingVec = pi.dirMag * model.transform.forward * walkSpeed * (pi.run ? runMultiplier : 1.0f);
        // ...
    }

旋转的优化
依照之前的设计,旋转速度会很快。这里咱们应用 Slerp 给旋转一个缓动的成果。

    // Update is called once per frame
    void Update()
    {
        // 只在有速度时可能旋转 避免原地旋转
        if(pi.dirMag > 0.1f)
        {
            // 使用旋转 应用 Slerp 进行成果优化   
            model.transform.forward = 
                Vector3.Slerp(model.transform.forward, pi.dirVec, 0.3f);
        }

        // ...
    }

跑步动画的优化

    // 将输出转换为速度 赋值给动画机相干参数
    anim.SetFloat("forward", pi.dirMag * (pi.run ? 2.0f : 1.0f));

按以上代码设计,如果咱们在走路时忽然切换到跑步,因为 dirMag 是不变的,咱们只是间接将它乘以 2,会导致混合树的参数间接渐变到 2,行走到跑步动画的切换就没有一个过渡了。

    void Update()
    {
        // 将当初的动画参数 forward 值通过 lerp 变动失去
        anim.SetFloat("forward", Mathf.Lerp(anim.GetFloat("forward"), pi.dirMag * (pi.run ? 2.0f : 1.0f), 0.1f));
        // ...
    }

采纳以上计划能改善问题,forward 的值将通过 lerp 去批改。

退出移动版