黑魂复刻游戏的玩家控制器(攻击的基础实现)——Unity随手记(2021.4.27)

文章目录

  • 今天实现的内容:
        • 攻击动画层
        • 配置Avatar Mask
        • 攻击信号输入
        • 攻击动画的基本代码逻辑
  • BUG以及缺陷:
        • 攻击的BUG修正
  • 值得注意的:

今天实现的内容:

攻击动画层

为了加入新的攻击动画,我们要设计一个攻击动画层。新的动画层一是为了使老动画层不至于臃肿,而是为了配置Avatar Mask。
黑魂复刻游戏的玩家控制器(攻击的基础实现)——Unity随手记(2021.4.27)_第1张图片

配置Avatar Mask

新建一个Avatar Mask,我知道这里是多个Avatar Mask。我们需要的是一个全身都被选择的Mask。将Mask放到动画层设置里面。
黑魂复刻游戏的玩家控制器(攻击的基础实现)——Unity随手记(2021.4.27)_第2张图片
在这里插入图片描述
接下来要做的就是,在攻击时调整动画层权重。这要在代码中做到。在进入代码之前,给idle添加StateMachineBehaviour脚本FSMClearSignals。我们需要清除的是attack信号来防止累积。
黑魂复刻游戏的玩家控制器(攻击的基础实现)——Unity随手记(2021.4.27)_第3张图片

攻击信号输入

和翻滚一样攻击属于一次性触发信号。由于使用键盘,所以我们采用MouseButtonDown(0)。

    // 一次性信号
    public bool attack; //攻击信号
    
    // Update is called once per frame
    void Update()
    {
     
		// ...
		
        // 攻击信号
        attack = Input.GetMouseButtonDown(0);
        attack = Input.GetKeyDown(keyAttack);
	}

攻击动画的基本代码逻辑

由于有了attack层,我们的动画机控制代码复杂了一点。我们需要使用代码修改动画层的权重。

	// 进入Attack层的动画节点attack_oneHand_A时执行的方法
    // 通过PlayerController动画机中的attack_oneHand_A节点上挂载的FSMOnEnter调用
    public void OnAttack_oneHandAEnter()
    {
     
        // 关闭输入模块
        pi.inputEnabled = false;
        // 修改攻击动画层权重为1
        m_anim.SetLayerWeight(m_anim.GetLayerIndex("Attack"), 1.0f);
    }

    // 在Attack层的动画节点attack_oneHand_A更新时执行的方法
    // 通过PlayerController动画机中的attack_oneHand_A节点上挂载的FSMOnEnter调用
    public void OnAttack_oneHandAUpdate()
    {
     
        // 计算攻击时的冲量
        m_thrustVec = model.transform.forward * m_anim.GetFloat("attackOneHandAVelocity") * m_planarVec.magnitude * 4f;
    }

    // 进入Attack层的动画节点idle时执行的方法
    // 通过PlayerController动画机中的idle节点上挂载的FSMOnEnter调用
    public void OnAttackIdleEnter()
    {
     
        // 打开输入模块
        pi.inputEnabled = true;
        // 修改攻击动画层权重为0
        m_anim.SetLayerWeight(m_anim.GetLayerIndex("Attack"), 0);
    }

方法依旧是熟悉的配方,通过FSMOnEnter的SendMessage来告诉PlayerController当前进入攻击动画了,进而重新设置层权重。m_anim.GetLayerIndex来让程序帮你找到LayerIndex。
接下来,攻击时我们的角色不能再按玩家的输入任意移动,否则会很奇怪(很明显了)。所以在攻击时要输入模块关闭,不用锁定平面移动(m_lockPlanar)。
如果角色在攻击时本身处于移动状态,我们就需要表现出惯性,角色需要向前冲一点,要实现这个效果,可以使用和jab类似的方案,也就是在攻击动画中加入一个曲线表示冲量的速度大小,只不过这次还要和m_planarVec.magnitude相乘,才能和角色的速度相关,得到的就是看起来不错的惯性效果。至于为什么移动时攻击会在关闭输入模块之后还能得到惯性效果,是因为我们的输入模块不是直接将输入值拿来就用,而是使用了Slerp。


BUG以及缺陷:

攻击的BUG修正

我们的攻击代码还不完善,你首先会发现我们在翻滚以及跳跃时依旧可以执行攻击,而且动画还会被攻击动画覆盖掉。 所以我们还要将这个问题解决了。我们的第一个解决方案是,在判断是否攻击时,不能只判断当前是否按下了攻击键,还要再检查当前是否处在ground动画状态。
但是试过之后发现,这个解决方案其实不太行,如果我们按的快,在翻滚的同时按了攻击键,还是会触发攻击。原因是因为动画转态需要时间,而这段时间内动画机认为动画还没有离开先前的状态。所以上述办法行不通了,我们需要用别的办法进行判断。我们将使用单独的一个bool变量canAttack,当我们按下jab_roll键和jump键时,将canAttack设置为false,在进入ground动画状态时,再将canAttack设置为true。这样就避免了上述问题。

	// 是否能够攻击 用于规避BUG
    private bool canAttack = true;
	
    // Update is called once per frame
    void Update()
    {
     
        // ...
        // 触发roll 会根据forward来判断具体该执行哪个动画
        if (pi.jab_roll)
        {
     
            m_anim.SetTrigger("jab_roll");
            canAttack = false;
        }
        // 触发jump 必须要先冲刺才能jump
        if (pi.jump)
        {
     
            m_anim.SetTrigger("jump");
            canAttack = false;
        }
        // 触发attack 要求当前动画必须在ground状态才能攻击
        if (pi.attack && canAttack)
        {
      
            m_anim.SetTrigger("attack");
        }

		// ...
    }

    // 进入Base层的动画节点ground时执行的方法
    // 通过PlayerController动画机中的ground节点上挂载的FSMOnEnter调用
    public void OnGroundEnter()
    {
     
        // ...
        
        // 进入ground状态以后才能够进行攻击
        canAttack = true;
    }

对于我自己的代码,在处理攻击逻辑时,我做了额外一件事,也就是防止在按下攻击键后按下jab_roll键,避免造成位移。具体方法是和之前一样的套路,就不写出来了。话说回来,之所以会有这样一步限制,是因为我的翻滚逻辑和老师的略微不同,老师的逻辑是通过在OnRollUpdate中给m_thrustVec赋值,而我的目前是直接将m_planarVec锁定,然后给他赋值作为翻滚时的平面位移量由FixedUpdate中的位移直接实现翻滚时的位移,所有会导致如果说我们在攻击时按下翻滚键会造成移动,简单来说因为我的代码在翻滚时修改了m_planarVec,而攻击的冲量受此影响。


值得注意的:

关于添加额外bool变量作为信号这种事,老师的意见是不到万不得已,不加信号没办法解决问题的时候,就不要加信号,这会导致你的代码可读性降低,如果后期加了一堆信号,会导致理解困难。在我之前的项目中,添加额外的bool变量对代码进行控制一直是我的方案,最后导致的结果确实如老师所说的那样,代码会变得很难看。看来要写出好的代码,我还有很长的路要走。


你可能感兴趣的:(Unity随手记,游戏开发)