上一篇文章中我们我们提到了一个关于空中姿态的问题,我们在本章节完善它。
首先我们不妨思考一下,什么时候切换成空中姿态,什么时候切回来,是跳起的时候吗?
这个我们很容易就能想到,不可能只有跳起的时候拥有空中姿态,人物双脚离地就应该切换成空中姿态,那样势必是需要一个关于人物是否双脚离地的判断的。
这里,我们使用了一个unity提供的API,Physics.OverlapCapsule(双交球)这个API可以帮助我们检测小姐姐落地与否。
我们首先将地图中看到的cube和plane设置一个层级
地面或者站立平台
接着开始写我们的PlayerTestView的码子
float radius;
public void init() {
rig = GetComponent<Rigidbody>();
pad = new PlayerAnimaId();
player = transform;
playerAnimatorInit();
capsuleCollider = GetComponent<CapsuleCollider>();
radius = capsuleCollider.radius - 0.05f;//获取player身上碰撞器的半径,稍微缩短半径
}
public void colliderTesting() {//判断是否接触地面
Vector3 point0 = player.position + (player.up * (radius - 0.1f));//将下方的相交球往下拉一点,使其在CapsuleCollider的下方。
Vector3 point1 = player.position + player.up * capsuleCollider.height - player.up * radius;
Collider[] groundCollider = Physics.OverlapCapsule(point0, point1, radius, LayerMask.GetMask("IsGround")); //如果接触地面
if (groundCollider.Length > 0) {
isGround(true);
} else {
moveDirection.y = 0;
isGround(false);
}
}
public void isGround(bool c) {
//这里面应该写点什么?
}
接着在PlayerTestMediator的码子里的fixupdate添加上我们的检测。
public override void OnRegister() {//绑定成功之后会调用这个API
Debug.Log("OnRegister");
playerView.init();
UpdateManges.add_playerEventList_(keyController);
UpdateManges.add_playerEventList_(playerAction);
UpdateManges.add_playerEventList_Fix(accurateDetection);//新添加的函数,需要精确检测的都应该放在这里,比如落地检测,实时重力之类。
}
public override void OnRemove() {//接触绑定之后调用这个API
Debug.Log("OnRemove");
UpdateManges.sub_playerEventList_(keyController);
UpdateManges.sub_playerEventList_(playerAction);
UpdateManges.sub_playerEventList_(accurateDetection);
}
void accurateDetection() {
playerView.colliderTesting();
}
处理完这这里,我们就要回过头去想PlayerTestView 中的isGround应该写点什么。就现在而言那就是空中的姿态,那我们就去这里找一个动作把,经过一番查找,我们找到了一个叫做,Fall的动作。如图。
我们把动作切换成humanoid,然后放入道我们的动画控制器内部。
接着我们思考一下,那些状态可以切换道这里。经过一番思考。
跳->可以
走->可以
跑->可以
静止->可以。
于是我们就这样做。
配置1
配置2 配置3
做完着这些配置,我们有需要去写一点代码实现了。
PlayerTestView_Anim:
struct PlayerAnimaId {
public int Idle;//禁止状态行为切换控制。
public int baseAniam;
public int jump;
public int isGround;//新增
};
private void playerAnimatorInit() {
animator = GetComponent<Animator>();
pad.baseAniam = Animator.StringToHash("walk");
pad.jump = Animator.StringToHash("Jump");
pad.isGround = Animator.StringToHash("IsGround");//新增
pad.Idle = Animator.StringToHash("Idle");
}
private void animator_PlayaisGround(bool isGround) {
animator.SetBool(pad.isGround, isGround);
}
PlayerTestView:
bool lockOperation ;//用于锁死玩家操作。
public void isGround(bool c) {
lockOperation = !c;
animator_PlayaisGround(c);
}
public void baseWalkRun(float right, float forward, bool run) {
if (LockOperation)
return;
animaBlendAction(right, forward, run);
}
public void playerMove() {
if (!lockOperation) {//如果出于半空中,玩家所控制的位移信息全部跳过,不做任何处理。
rig.velocity = new Vector3(moveDirection.x, moveDirection.y+ rig.velocity.y, moveDirection.z);
}
}
在PlayerTestMediator进行更改。
void playerAction() {//加入update不断跟新
playerView.baseWalkRun(right, up, run);
playerView.startJump(jump);
playerView.playerMove();
}
一切做完,我们来看看效果。
效果
看着还行,但是这里有个问题,如果小姐姐在空中的时候我们再一次按一下跳跃,小姐姐落地之后还会跳一次,这是为什么?
我们的逻辑应该是正确的,这里就要提到一个unity动画机的一个信号冗余问题。我这里这么做。
创建一个FSMClearSignals 脚本,让挂在jump这个跳跃动作上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FSMClearSignals : StateMachineBehaviour {
public string[] clearAtenter;
public string[] clearAtexit;
public override void OnStateEnter(Animator animator, AnimatorStateInfo animatorStateInfo, int layerIndex) {
foreach (var signal in clearAtenter) {
animator.ResetTrigger(signal);//清除信号
}
}
public override void OnStateExit(Animator animator, AnimatorStateInfo animatorStateInfo, int layerIndex) {
foreach (var signal in clearAtexit) {
animator.ResetTrigger(signal);//清除信号
}
}
}
配置
做到这里,小姐姐终于有模有样了,但是在我们制作的时候,我们发现了一个问题,有些线条(比如Physics.OverlapCapsule 无法显示)。所有我们下一节将制作一个辅助线控制器,用于那些我们看不见的线条。
上一节
下一节
网友评论