Unity-黑暗之魂复刻-跳跃功能

2019-05-29 17:02:18 浏览数 (3)

trigger once signal

使用触发来实现跳跃逻辑

代码语言:javascript复制
//2.trigger once signal
    public bool jump;
    private bool lastJump = false;
代码语言:javascript复制
bool newJump = Input.GetKey(keyB);
        if(newJump != lastJump && newJump == true)
        {
            print("I jump");
            jump = true;
        }
        else
        {
            jump = false;
        }
        lastJump = newJump;

我们添加新的状态Jump 通过Trigger来触发跳跃的动画 这里会遇到Unity中存在的一个问题,当我们连续按跳跃的时候,Trigger会记录两次按键,动画就会播放两次。 通过FSMClearSignals添加到ground的状态中的Behavior中我们来修复这个问题。 我们重写OnStateEnter这个方法,当进入当前状态的时候,清空Trigger的记录。这样我们就避免了连续输入动画会播放两次的问题。

代码语言:javascript复制
 // 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 item in clearTriggerAtEnter)
        {
            animator.ResetTrigger(item);
        }
    }
再优化

为了减少在动画状态机中添加代码,我们将Behavior套接出去。 我们在Jump的动画状态中添加一个FSMOnEnter的Behavior继承自StateMachineBehaviour

代码语言:javascript复制
public string[] message;
    // 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)
    {
        animator.gameObject.SendMessage("OnJump");
    }

由于我们的代码并不在animator的gameObject上 我们的Input相关和角色Controller相关代码都在PlayerHandle中,ybot中只有Animator组件

PlayerHandle.PNG

所以我们改编代码,向父物体SendMessage

代码语言:javascript复制
animator.gameObject.SendMessageUpwards("OnJump");
在空中的时候锁死当前的平面速度向量

1.首先在Jump的State中AddBehaviour,一个进入状态一个退出状态 2.如上面代码,我们在ActorController中编写进入和退出状态触发的方法。

代码语言:javascript复制
private void OnJumpEnter()
    {
        pi.enabled = false;
        lockPlanar = true;
        //print("Jump!!!!!");
    }
    private void OnJumpExit()
    {
        pi.enabled = true;
        lockPlanar = false;
        //print("JumpEX!!!!!");
    }

我们进入状态的时候锁死玩家输入同时,让玩家当前的移动速度不再变化。

代码语言:javascript复制
if(lockPlanar == false)
        {
            planarVec = pi.Dmag * model.transform.forward * walkSpeed * ((pi.run) ? runMultiplier : 1.0f);
        }

这样角色再空中仍然会保持跳跃时的速度向量。

卡在墙上bug

由于我们让角色在空中保持了跳跃时的速度向量,会出现角色在空中的时候卡在墙上,这时摩擦力大于重力,角色不会下落,我们要改进就要给角色修改摩擦力。 制作两个physics.material,将他们的DynamicFriction和StaticFriction分别设置为1和0,当玩家在离开ground时,我们将zero的physics.material设置给player的collider.material,这样玩家在空中的摩擦力就会为零,在ground上时,我们再设置回去。

落地相关

1.给Jump添加新的Transition到fall,在jump进行状态转换的时候先判断到fall。 2.添加落地检测器,使用Physics中的OverLapCapsule进行检测。这个API适用于粗略的广泛的判断,它会返回检测到的全部碰撞体。 3.给地面设置新的Layer,将地面的Layer设置为Ground 4.我们让玩家跳跃完播放fall的动画而不是ground,在fall动画播放的时候,如果OverLapCapsule检测到地面,立刻将状态设置为ground。我们使用bool值控制在jump后是转换到ground还是fall。

代码语言:javascript复制
        point1 = transform.position   transform.up * (radius - offset);
        point2 = transform.position   transform.up * (capol.height-offset) - transform.up * radius;

        Collider[] colliders = Physics.OverlapCapsule(point1, point2, radius,LayerMask.GetMask("Ground"));
        if(colliders.Length != 0)
        {
            SendMessageUpwards("IsGround");
        }
        else
        {
            SendMessageUpwards("IsNotGround");
        }

落地的时候去调用父物体中的IsGround,IsGround将设置动画的状态。

代码语言:javascript复制
    public void IsGround()
    {
        anim.SetBool("isGround", true);
    }
    public void IsNotGround()
    {
        anim.SetBool("isGround", false);
    }

5.失速问题,在fall的时候水平速度没有了,我们在Jump状态结束的时候将玩家输入清零,这是导致问题的原因。我们将JumpOnExit砍掉,换成在ground状态进入的时候,开放锁死。 6.在我们Jump转换到fall(正在转换)的时候,IsGround的条件满足了,我们仍然会将状态先转换到fall而不是立刻中断去进行转换ground状态。解决这个问题我们在jump状态transition到fall的setting中将Interruption Source(中断)设置为CurrentState。 在官方文档中,状态转换中断(Transition Interruption)中描述,使用中断源与有序中断属性控制转换如何被中断,中断提供效果,概念的讲,好像转换是序列的之后从第一个转换到最后一个转换逐一解析。

0 人点赞