首先,如果不做跳跃、不需要人物从高处坠落时做出坠落动作,就并不一定要写地面检测。人物坠落时保持在地面上的动作,可以在空中跑步,如果对效果要求不高就问题不大。
地面检测
碰撞检测方案
判定离地的代码写在OnCollisionExit(),在地面上的代码写在了OnCollisionStay(),不能写在OnCollisionEnter(),因为人物如果先接触另一块地面,再离开这一块地面,OnCollisionExit()的效果覆盖了OnCollisionEnter(),人物被判断为离地。如果写在OnCollisionStay(),离开一块地面时OnCollisionExit()执行一次,而OnCollisionStay()一直执行,人物还被判断为在地面上。坠落伤害的代码则可以放OnCollisionEnter()。
但是这样写还有严重的问题:下坡的时候先靠animator水平移动,再靠重力下落贴紧斜面,onGround会不停变成false导致人物做出坠落姿势或不能跳跃。
void OnCollisionStay(Collision collision){
if(CheckIsGround(collision.gameObject)){//地面检测在Stay里,时时都要检测
myCharacter.animator.SetBool(MyCharacter.onGroundPara,true);
}
}
void OnTriggerExit(Collider other){
if(CheckIsGround(other.gameObject)){//检测离地
myCharacter.animator.SetBool(MyCharacter.onGroundPara,false);
rigidbody.velocity=myCharacter.animator.velocity;
}
}
static int speedToHurt=9,fallHurtDamage=40,speedToDeath=15,fallDeathDamage=120;//固定跌落伤害
void OnCollisionEnter(Collision collision){
if(CheckIsGround(collision.gameObject)){
if(collision.relativeVelocity.magnitude>speedToDeath){
myCharacter.TakeDamage(fallDeathDamage,MyGameManager.fallHint);
}
else{
if(collision.relativeVelocity.magnitude>speedToHurt){//跌落伤害
myCharacter.TakeDamage(fallHurtDamage,MyGameManager.fallHint);
}
}
}
}
补救方法:在人物碰撞体下端套一个稍大的触发器碰撞体,这个碰撞体离地时才判定离地。地面检测触发器为了和碰撞体区分开,要么就挂在其他节点上。这样让做一个人物的流程更复杂了。
在判断开始坠落时要执行
rigidbody.velocity=myCharacter.animator.velocity;
在坠落中继承人物的水平速度。而在落地后这个刚体速度不用设0,刚体会由于摩擦自动停下。
速度检测方案
现实世界中人类对坠落的反应好像并不是因为脚离地,而是因为下落的加速度达到了一定值。比如在加速下落的电梯里人的脚着地,但是会感觉到在下落。rigidbody没有加速度字段,但是可以通过rigidbody.velocity.y达到一定值来判断。
float fallSpeedLastFrame;
public float fallSpeedThreshold=-3;
void Update(){
if(fallSpeedLastFrame>=fallSpeedThreshold&&myCharacter._rigidbody.velocity.y
物理效果
如果角色挂有RigidBody,可以通过rigidBody.velocity=jumpSpeed*Vector3.up实现。如果角色使用Animator的Root Motion移动,可以通过
rigidbody.velocity=new Vector3(_animator.velocity.x,jumpSpeed,_animator.velocity.z);
实现移动中跳跃,跳跃中保持起跳的速度。
动画效果
简单的跳跃只需要滞空动画。如果想做得更逼真,可以添加起跳和落地动画。我这里做滞空和落地动画。落地动画因为本身属于过渡动画,为了避免自动过渡出现不想要的效果,应该把滞空到落地、落地到站立的过渡设置尽量短。
程序判定
满足玩家输入跳跃&&人物在地面上就跳跃。定义一个bool onGround记录是否在地上,可以在脚本里或动画参数。
问题记录
跑步中跳跃有一定概率出现在空中跑步,看状态机显示进入跳跃状态后立刻退出进入了跑步状态。跳跃状态的退出条件是onGround==true,也就是说进入跳跃状态后立刻满足了退出的条件。
解决方法:稍微增加了跑步到跳跃状态过渡的时长。