前言
在人物移动过程中会遇到一些高度较低障碍物时,可以选择让角色撑住障碍物跃过

一、障碍物检测
关于该检测算法我做了一些改进,大家可参考我的下一篇文章,要是搞懂了可以直接跳过本章的障碍物检测
Unity Arpg学习日志五:跑酷攀爬功能———低障碍物撑跳、翻越(检测算法的改进)
检测高度时,设置三个高度,检测到的障碍物高度低于最低和高于最高高度不能翻越
,中间值用于检测是低攀还是高攀
使用Physics.Raycast 发出射线进行三层检测,并记录碰撞信息Hit
Check()在Update里调用

protected override void Check()
{
if (PhysicsRaycast(player.position + player.up * checkHeight1, player.forward, maxCheckDistance, mask, checkHeight1))
{
if (PhysicsRaycast(player.position + player.up * checkHeight2, player.forward, maxCheckDistance, mask, checkHeight2))
{
if (PhysicsRaycast(player.position + player.up * checkHeight3, player.forward, maxCheckDistance, mask, checkHeight3))
{
//不可翻越
}
//height2和height3之间为高翻越
else
{
IsVault();
currentValutType = 2;
}
}
//height1和height2之间为低翻越
else
{
IsVault();
currentValutType = 1;
}
}
else {
//不可翻越
}
}
PhysicsRaycast()为发出射线检测,同时在scene里画出该射线
bool PhysicsRaycast(Vector3 origin,Vector3 dir,float maxDis,LayerMask mask,float checkHeight,bool openDebug=true)
{
if(openDebug) Debug.DrawLine(player.position + player.up * checkHeight, player.position + player.up * checkHeight + player.forward * maxDis, Color.red);
if (Physics.Raycast(origin, dir, out RaycastHit hit,maxDis,mask))
{
Hit=hit;
return true;
}
else return false;
}
IsVault()为二次检测,当障碍物太宽厚,或者翻越到顶点时碰到障碍物也不能进行。
设置HeadBumpHeight碰头高度,和checkWidth墙体厚度
至于如何获得障碍物的高度,我这里用了比较简单的的方法,及使用障碍物碰撞体的高度Hit.collider.bounds.size.y,这个方法是有很多缺点的,本文先使用用它
bool IsVault()
{
Debug.DrawLine(player.position + player.up * HeadBumpHeight+ player.forward * checkWidth, player.position + player.forward * checkWidth, Color.green);
Debug.DrawLine(player.position + player.up * (Hit.collider.bounds.size.y + bodyHeight), player.position + player.up * (Hit.collider.bounds.size.y + bodyHeight) +player.forward*(maxCheckDistance + 5f),Color.blue);
if (PhysicsRaycast(player.position + player.up* HeadBumpHeight + player.forward*checkWidth, -player.up, HeadBumpHeight, mask, 0,false)||
PhysicsRaycast(player.position + player.up * (Hit.collider.bounds.size.y + bodyHeight), player.forward, maxCheckDistance + 5f, mask, (Hit.collider.bounds.size.y + bodyHeight),false))
{
return false;
}
return true;
}
}
可参考我的参数


检测射线大致为

二、状态的进入和退出
当进入状态时,将刚体的isKinematic打开,这样就不会把刚体挡住,虽然我不是基于rootMotion的动画,但这里也要把它打开让动画进行校准,退出时把他们关闭
进入状态时播放动画的同时,也要计算下目标匹配的位置,matchTarget1为上升的位置,matchTarget2为下降的位置
isRun则用来判断是否正在执行该状态
protected override void Enter()
{
base.Enter();
animator.applyRootMotion = true;
rb.isKinematic = true;
if (currentValutType == 1)
{
//目标匹配
matchTarget1 = player.position + player.up * (Hit.collider.bounds.size.y + 0.3f) + player.forward * (maxCheckDistance - 0.5f);
//matchTarget2 = player.position - player.up * (Hit.collider.bounds.size.y + 0.5f) + player.forward * (maxCheckDistance - 0.8f);
animator.Play("climb_vault_low");
}
else if(currentValutType == 2)
{
matchTarget1 = player.position + player.up * (Hit.collider.bounds.size.y+0.1f) + player.forward * (maxCheckDistance - 0.5f);
matchTarget2 = player.position + player.forward * (maxCheckDistance+0.5f);
animator.Play("climb_vault_high");
}
isRun = true;
}
protected override void Exit()
{
base.Exit();
animator.applyRootMotion = true;
rb.isKinematic = true ;
isRun=false;
}
上述代码绿色的浮点数则是要根据障碍物和动画等进行的偏移
三、状态进行(目标匹配)
状态进行时根据不同高度,不同动画进行目标匹配,在lateUpdate调用。
目标匹配可以让角色某个部位(比如手或者脚)在动画执行时位移到匹配点
关于目标匹配可以参考该文章
运动匹配
void AnimMatch()
{
if (animator.GetCurrentAnimatorStateInfo(0).IsName("climb_vault_low"))
animator.MatchTarget(matchTarget1, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.1f, 0.15f);
else if (animator.GetCurrentAnimatorStateInfo(0).IsName("climb_vault_high"))
{
//动画上升
if(animator.GetCurrentAnimatorStateInfo(0).normalizedTime<0.6f)
{
animator.MatchTarget(matchTarget1, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.1f, 0.15f);
}
//动画下降
else
animator.MatchTarget(matchTarget2, Quaternion.identity, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 0), 0.5f, 0.9f);
}
else return;
if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.99f)
{
Exit();
//执行退出
//RunnerMode.Instance.ExitClimbState();
}
}

演示


1316



被折叠的 条评论
为什么被折叠?



