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)中描述,使用中断源与有序中断属性控制转换如何被中断,中断提供效果,概念的讲,好像转换是序列的之后从第一个转换到最后一个转换逐一解析。