Unity——#14 一段攻击

2019-07-15  本文已影响0人  MisakiMel

  这节打算新增一段攻击动画,但一般一段攻击是不够的,完整的一套平A应该要有三段或四段攻击,在以后我打算做三段攻击,这节先看看一段攻击如何实现。



  我认为现在这一层的动画状态机已经完整了,一些角色的基本动作例如走、跑、跳、翻滚都有了,不应该再往上添加动画了。所以我想把多段攻击放在一层新的状态机上,然后实现两者同时存在且互不干扰,说起来简单但做起来就不一定了。OK, Let's do it.
  首先就要新增一层Layer,在Animator的Layer里点选+号,新增一层Layer并命名为attack:


attack
  新增之后第一件事并不是直接加动画哦,而是应该点开attack右边的小齿轮:

  里面的几个属性我来解释一下:
    public string keyC;
    public bool attack;
    void Upate(){
        ...
        attack = Input.GetKeyDown(keyC);
    }

  对于keyC我设置为j,对于该用什么按键攻击并没仔细考虑,现在先测试这个Trigger能不能正常使用要紧。



  然后在ActorController.cs里将这个bool变量的attack与Trigger attack联系起来:

    void Update(){
        ...
        if (pi.attack) {
            anim.SetTrigger ("attack");
        }
    }

  现在先来看看效果哦:


  噢上帝这效果简直不堪入目,一堆bug,我们来看看现在究竟都出些啥问题:
1.完全没有了走路的动画,整个模型就在滑行
2.按空格没有任何反馈,既不能跳又不能翻滚
3.攻击随意转向
  遇到这么多问题哦肯定会慌张,感觉无从下手,都是像我这些小白常有的心态。先别急,回想一下是不是哪个环节出了问题,我沉思了一下,发现:

  可能就是这两个玩意搞得我一地鸡毛,重载嘛,全身嘛,然后在attack这个Layer的idle动画直接覆盖Base Layer的所有动画了,所以Base Layer的所有动画突然都不奏效了。那这肯定不是我想要的,怎么解决?我现在需要一个动态调节attack这个Layer的权重值的方法,只要权重值为0那么这两个玩意就不会奏效了,在我没有键入j键时,attack的权重值为0,此时就能正常播放Base Layer里的所有动画;在我键入j后,进入到attack的Layer里,此时将不能播放Base Layer里的动画,不过在攻击时不能跑跳滚也是合理的。这个该怎么实现呢?
  此时我们应该了解关于状态机的一个特点,这有助于我们去实现这个动态调节的方法。就是即使某层的的权重值为0,但它在状态机里依旧会运行,只是不会表现在角色的动画里,这个是我键入一次j的效果:

  那么我们就想,能不能这样做:当我们键入j,在进入到attack1hA的动画时,把attack这个Layer的权重值拉满,然后在attack1hA播放完毕,回到idle时,把权重值拉回0,感觉可行是不是?还能顺便把输入给锁死了。事不宜迟,马上动身!
  先在attack1hA和idle身上add Behaviour,就是FSMCallOnEnter,老招了,现在应该驾轻就熟了:


  至于怎么调节权重值,Animator给了一个方法就是Animator.SetLayerWeight(),它就只有一个Signature,那就是:
public void SetLayerWeight(int layerIndex, float weight);
  参数不难理解:
Parameters Mean
layerIndex The layer index.
weight The new layer weight.

  要注意的是,它接的是Layer的索引值,并不是Layer的名字,对于Animator的Layers,它是按索引值区分的,而这个索引值类似于数组那般,从0开始。



  像这样Base Layer的索引值就是0,attack的索引值就是1,以此类推。
  而这个函数的官方描述呢也是通俗易懂:

Description
Sets the weight of the layer at the given index.

  前面提到,Animator.SetLayerWeight()的第一个参数要求的是Layer的索引值,那么直接喂给它数字1是不好的,万一以后attack的位置改变了,这种写死的行为就会带来灾难。所以还是把这个写活好,用Layer的名字就最好,毕竟名字会改的情况不多,那么如何通过Layer的名字获得它当前的索引值呢,那就要用到Animator的另外一个函数Animator.GetLayerIndex(),这个函数也不难理解:
public int GetLayerIndex(string layerName);给它layerName,就返还指定layerName的索引值。
  至此两个要用到的函数就绪,可以动手:

    void OnAttackIdleEnter()
    {
        pi.InputEnabled = true;
        anim.SetLayerWeight (anim.GetLayerIndex ("attack"), 0);
    }

    void OnAttack1hAEnter()
    {
        pi.InputEnabled = false;
        anim.SetLayerWeight (anim.GetLayerIndex ("attack"),1.0f);   
    }

  现在我想要做就实现了,可以看看效果:



  现在恢复正常了,可以走路了,而且平A时也不能转向了,但动作有点生硬,原因就是没给到它一个向前的冲量,而且现在attack这个Layer的权重值缺少了平滑处理,不是0就是1,导致两个Layer之间的切换太过突兀:



  可以看到这个蓝条,不是满就是空的,要对其进行平滑处理,做到慢慢拉满的效果。
  除了这些问题,其实还有一些很严重的问题,那就是现在我能进行跳劈加翻滚这种逆天操作,而且还有在奔跑时键入攻击键之后键入跳跃键,会在平A完接一个翻滚。这其实都是jump和attack两个Trigger的冲突问题,这么多问题,这节应该是讲不完了,只能留到下节在逐一击破。共勉!
上一篇 下一篇

猜你喜欢

热点阅读