Unity项目-黑魂复刻(一)玩家控制器(玩家移动、动画实现以及优化)

玩家输入–通过转化为数字信号的方式进行输入:

设置键位和0~1之间进行平滑过渡

人物移动的数字信号转化:

     public string keyUp = "w";
     public string keyDown="s";
     public string keyLeft="a";
     public string keyRight="d";
     //通过三元运算符判定是否有按下这些键,从而进行赋值水平和垂直方向是 1或者-1
     targetDup = (Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0);
     targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);
     //当没有按时就需要把玩家停下来
     if (inputEnabled==false) {
           targetDup = 0;
           targetDright = 0;
      }
      //通过Mathf.SmoothDamp让Dup逐渐趋向与目标
      Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 0.1f);
      Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 0.1f);

人物转向:

通过输入数字信号的长度计算玩家当前的方向

//解决斜着的速度比水平垂直的速度快
 private Vector2 SquareToCircle(Vector2 input) {
        Vector2 output = Vector2.zero;

        output.x = input.x * Mathf.Sqrt(1 - (input.y * input.y) / 2.0f);
        output.y = input.y * Mathf.Sqrt(1 - (input.x * input.x) / 2.0f);
        return output;
    }
 //斜角速度和直线一样
        Vector2 temDAxis = SquareToCircle(new Vector2(Dright,Dup));
        float Dright2 = temDAxis.x;
        float Dup2 = temDAxis.y;

        Dmag = Mathf.Sqrt((Dup2 * Dup2) + (Dright2 * Dright2));
        Dvec = Dright2 * transform.right + Dup2 * transform.forward;

人物移动–通过Rigibody控制玩家的移动

需要在FixedUpdate中进行移动操作
原因:FixedUpdate 和 Update的区别 Update是在每次渲染新的一帧的时候才会调用,也就是说,这个函数的更新频率和设备的性能有关以及被渲染的物体(可以认为是三角形的数量)。在性能好的机器上可能fps 30,差的可能小些。这会导致同一个游戏在不同的机器上效果不一致,有的快有的慢。因为Update的执行间隔不一样了。 FixedUpdate是在固定的时间间隔执行,不受游戏帧率的影响。Tick:在处理Rigidbody的时候最好用FixedUpdate。 FixedUpdate的时间间隔可以在项目设置中更改,点击 Edit - Project Setting - time 找到 Fixed timestep,就可以修改了。

 //移动时需要在FixedUpdate中进行(物理) 
    private void FixedUpdate() // Time.fixedDeltaTime 1/50
    {
        //方法一,position的位置包含y轴
       // rigid.position += movingVec * Time.fixedDeltaTime;
        //方法二,速度不包含y方向
        rigid.velocity =new Vector3(movingVec.x,rigid.velocity.y,movingVec.z);
        print(rigid.velocity.y);
    }

人物动画实现以及优化

动画机设计理念:使用混合树ground将地面移动动画统一管理,通过设定parameters(参数)来控制某个动画的执行

混合树
在这里插入图片描述

动画机的运用以及模型旋转

要运用动画机,需要将动画机和输入模块串接起来。所以我们需要新的脚本,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;
    }
}

我们可以将旋转和输入的模长计算放到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)
    }

跑步

在原基础上加入奔跑。首先加入新的输入按键。并且在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,行走到跑步动画的切换就没有一个过渡了。
采用以下方案能改善问题,forward的值将通过lerp去修改。0

void Update()
    {
        // 将现在的动画参数forward值通过lerp变化得到
        anim.SetFloat("forward", Mathf.Lerp(anim.GetFloat("forward"), pi.dirMag * (pi.run ? 2.0f : 1.0f), 0.1f));
        // ...
    }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值