美文网首页工作生活
Unity——#04 跳跃

Unity——#04 跳跃

作者: MisakiMel | 来源:发表于2019-07-04 06:48 被阅读0次

      单纯只考虑跳跃的实现的话,只需考虑5个问题:
    1.使用Trigger Type Signal触发型信号
    2.要解决臭名昭著的问题:在一次触发时间里累积了两次的跳跃
    3.锁死玩家输入,防止跳跃过程中的转向
    4.锁死输入同时保留速度,使其能够在跳跃过程中向前移动
    5.提供y分量的冲量,让其真正跳离地面

      OK,摩拳擦掌,跃跃欲试。

    1.使用触发型信号(Trigger Type Signal)

      在实现Run中,使用的是按压型信号(Pressing Type Signal),与其不同的是,触发型信号的取信号时间段为当玩家键入指定键的那一刻,这就很符合用来实现跳跃,按一次跳一次,而不是按住一直跳。
      首先宣告一个string变量记录触发跳跃的按键信息,然后宣告一个bool变量记录触发型信号:

    public string keyB = "space";     
    public bool jump;
    

      然后使用Input.GetKeyDown()来判断玩家是否键入了空格,是就返回true给jump变量;反之返回false。

    jump = Input.GetKeyDown (keyB);
    

      在实现Run时就有提到过Input.GetKeyDown(),它是在当用户键入指定键的那一帧时就返回true,就很符合用来实现触发型信号。
      代码部分OK,再来看看Animator视窗,添加jump动画然后让其与ground联系起来(两者之间Make Transition) :


    Animator

      然后在ground到jump的Transition里消钩Has Exit Time,这意味着当接收到跳跃的触发信号时,不用等ground的动画播放完,直接中断后播放jump的动画。


    消钩Has Exit Time
      而jump到ground的Transition默认设置就好。
      现在我们应该在Animator视窗里的Parameters那一栏(参数栏)创建一个Trigger型参数,命名为jump。
    命名为jump的Trigger型参数

      利用这Trigger型参数将ground到jump的Transition激活起来,就是说当jump信号被触发时,将打断ground的动画,转换到播放jump的动画,具体操作是在这个Transition里新增一Condition,然后选中jump参数即可:



      剩下的就是将Parameters里的jump与代码中的bool变量jump联系起来,在Animator组件的Controller的脚本文件上敲上:
            if (pi.jump) {
                anim.SetTrigger ("jump");
            }
    

      当bool变量的jump为true时,就设置Animator里的jump为触发状态。至此就应该能实现跳跃动画的播放了,当然只是播放,并不是真正的跳跃:

    Jump
    2.累积触发
      当玩家连续的键入两次跳跃键时(在一次跳跃动画播放期间),就会累积一次Trigger在里面,造成角色在跳跃完一次之后,继续跳跃第二次,即使之后没再键入跳跃键。而正常情况是,当玩家键入第一次跳跃键后,跳跃动画开始播放,在这播放期间,即使玩家键入第二次跳跃键,也不会有反馈,直到跳跃动画播放完毕,回到ground状态后,键入的跳跃键才有效果。如图就是我连续快速键入两次跳跃键的结果:

      解决这个问题需要在ground这个Blend Tree上加一个行为文件,在Inspector视窗内点击Add Behaviour,创建一命名为FSMClearSignal的脚本文件:


    Add Behaviour
      双击打卡文件,发现有好几组重载函数被注释了,下面简述一下其中几个的被调用的时机:
         // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
            //当进入这个状态时调用这个函数,进行相应操作
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
            //当在这个状态的期间时一直调用这个函数,进行相应操作
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
            //当离开这个状态时调用这个函数,进行相应操作
        }*/
    

      以后一般经常用到这三个函数,还有两个暂时用不上就不再赘述。这次呢是只用到OnStateEnter()这个函数,要做的就是当进入到ground这个状态时,清空jump这个Trigger,这样就能把在播放jump动画期间累积到多一次的Triggeri信号给清除了,具体实现如下:

        public string[] clearEnter;
        public string[] clearExit;
    
         // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
            foreach (var signal in clearEnter) {
                animator.ResetTrigger (signal);
            }
        }
    
      首先宣告一个string数组,来接收需要被清空的信号,由于是public修饰符,所以可以在Inspector视窗内直接填上要被清空的信号的数量和名字,这里要清空的只有一个就是jump信号(如图)。由于这个函数接收了一个Animator对象,所以可以利用这个对象调用其ResetTrigger()函数来清空信号,通过使用foreach来把数组里的信号依次reset掉。 Reset jump signal
      看看效果: Jump
      可以看到,现在即使我快速按3次跳跃键,它都只是完成了一次跳跃。
    3.锁死玩家输入

      在第一点的效果图中,能看到角色在跳跃过程中竟可以做到向后转身,这是什么异于常人的轻功?为了防止玩家在游戏中做出这种惊为天人的骚操作,需要在跳跃过程中锁死玩家的输入,使角色不能转向。具体实现我们应该宣告一个bool变量来控制Dmag:

    //在PlayerInput.cs文件里
        public bool InputEnabled=true;
        void Update(){
            ...
            if (!InputEnabled) {
                Dmag = 0;
            }else
            Dmag = Mathf.Sqrt (Dup2 * Dup2 + Dright2 * Dright2);
            ...
        }
    

      该bool变量默认为true,即玩家默认情况是可以输入进行移动;当InputEnabled变为false,Dmag立刻置0,这样玩家就无法操控角色了。

      在另一方面,应该在恰当时机调用这个变量使其发生bool or false的转换,而时机就是在进入跳跃的状态时锁死玩家输入,这个时间节点与OnStateEnter()函数调用时间是一致的,所以要做的就是当进入跳跃状态后,在OnStateEnter()里发送消息告知某一文件应该要锁死玩家输入啦。由于是在进入jump状态时要执行上述操作,所以包含此函数的文件应该是在jump动画下(通过Add Behaviour新建),命名为FSMCallOnEnter: FSMCallOnEnter
      双击点开,在OnStateEnter定义发射信息的操作:
    //在OnStateEnter()文件里
        public string [] onEnterMessage;
         // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
            foreach (var msg in onEnterMessage) {
                animator.gameObject.SendMessageUpwards (msg);
            }
        }
    

      由于一般处理动画的代码我都放在了同一个命名为ActorController.cs的文件里,所以关闭玩家的输入也应该放在这里,而这个文件是我添加在胶囊的组件,胶囊与模型是父子关系,而Animator组件在模型里。如果从OnStateEnter函数给出的参数Animator animator出发,在进入了跳跃状态时,发送的信息应该从animatoranimtor.gameObject,得到拥有这个Animtor组件的物体(这里是模型),到animator.gameObjectanimator.gameObject.SendMessageUpward(),最终往物体的上层(Upward)即胶囊发送信息。这样在胶囊里的全部组件都能以发送的消息作名字创建函数,一旦消息发出,这些函数就会被调用,进行相应的操作。首先我们定义发送消息的内容为"OnJumpEnter":

    OnJumpEnter
      那么就应该在ActorController.cs文件定义一个命名为OnJumpEnter()的函数:
    //在ActorController.cs文件里
        void OnJumpEnter(){
            pi.InputEnabled = false;
        }
    

      看看效果:


    Jump

      现在跳跃时我已经不能进行任何的输入了,所以不能转向,但同时引发了另外一个问题,那就是因为之前的实现锁死的代码是:

            if (!InputEnabled) {
                Dmag = 0;
            }else
            Dmag = Mathf.Sqrt (Dup2 * Dup2 + Dright2 * Dright2);
    

      Dmag = 0;在玩家不能输入的同时也使角色的速度变为0,所以出现了在跳跃时不能前进的问题。这就是第4点要讨论的内容:锁死输入同时保留速度,使其能够在跳跃过程中向前移动。
      好了,今天花在这里的时间已经够多了,休息一下,剩下的两点内容日后在谈。共勉!

    相关文章

      网友评论

        本文标题:Unity——#04 跳跃

        本文链接:https://www.haomeiwen.com/subject/hdhqhctx.html