问题描述:
在做unity攀爬之类的动画时会用到MatchTarget函数,但是我在用这个函数的时候,发现距离越远,
MatchTarget匹配的最终位置和给定的位置不一样。
试了好久觉得应该是动画过渡的问题。解决办法就是把startNormalizedTime设置比0大一点,比如0.2,targetNormalizedTime 设置比1小一点,比如0.8,就是匹配时间不要设为0到1
- startNormalizedTime 开始匹配的时间,注意是单位化时间(动画开始位置是0,结束位置是1)。如果开始时间已经超过了当前动画的播放时间,会匹配下一次符合的时间。比如:startNormalizedTime传入0.2,但是当前已经播放到0.3,会匹配下一次循环的0.2的位置。
- targetNormalizedTime 最终匹配到的单位化时间。如果值大于1,可以设置特定循环数后的位置。比如2.3代表第2次循环的30%位置。
当startNormalizedTime 设置为0,targetNormalizedTime 设置为1时,出现下面的情况:
将人物左脚匹配到红色球的位置,但是每匹配一次动画片段都不会完全到目标的位置。
于是
我把matchtarget的参数修改了一下
animator.MatchTarget(redSpherePosition,Quaternion.identity, AvatarTarget.LeftFoot,
new MatchTargetWeightMask(Vector3.One, 0),0.2f,0.8f);
然后就每次都能到目标位置了。
==========================================================
问题描述:
一个动画结束后转入另一个动画发生了位移
一个骑马的动画,分为上马,骑马
动画描述: 上马,人物左脚先踩到马上,高于地面(角色模型原点)0.5米
骑马,人物会坐在马上,左脚高于地面0.5米
然后,出现了一个问题,当unity使用matchtarget上马时(将重力和碰撞取消再用该函数,我这里是直接关闭CharacterController组件),将左脚对齐0.5米,并结束动画,此时角色已经上升了0.5米(上马动画有y轴位移)。如果应用了rootmotion的话。
当进入骑马动画时,由于骑马动画相对于原点有0.5米高,所以角色又会上升0.5米(左脚就到了1米),从而浮空。
解决办法:将上马的y baketopose,使上马时原点高度为0,取消y轴的位移
不是什么matchtarget的问题,matchtarget放在update中一直执行和在update中只执行一次效果感觉是一样的,所以用一个bool值判断以免matchtarget重复执行
//以下判断放在Update或者OnStateUpdate中
if(isReady && !animator.IsInTransition(0))
{
//MatchTarget(...)
isReady=false;//在动画一开始(OnStateEnter)将这个值设为true
}
==========================================================
问题描述:
使用Animator.MatchTarget前无法调整transform.position或者transform.rotation
如果在update中使用Animator.MatchTarget()、没有打开OnAinmatorMove()、勾选了Animator组件的ApplyRootMotion的时候 是可以匹配的。但是如果想在update中调整transform.position或者transform.rotation的时候,发现一点效果的没有。例如写transform.position=Vector.zero; 然后运行,角色也不会到原点去。
在上面的上马动画中,我的上马动画最后并没有刚好旋转到90度,骑到马上是歪的。所以我想在上马动画播放之前把角色的位置旋转稍微调一下
transform.position = redSpherePosition+Vector3.down*0.5f;
//使角色上马前的位置在设定的红球下方0.5米处,没有用,哪怕是
//transform.position=Vector3.zero都没用
transform.rotation = Quaternion.LookRotation(-hit.Normal) * Quaternion.Euler(0, -25, 0);
//先让角色正向面对马,然后绕y轴调整-25度,然而并无什么用,哪怕是转任意方向都没有用
animator.MatchTarget(rideableHorse_LeftFoot, Quaternion.identity, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 0), 0.2f, 0.8f);
//播放
大致原因:
查了一下,原因大概是说RootMotion动画根运动在update之后执行然后覆盖了手动设置的transform.position或者transform.rotation。角色的控制权就不能通过脚本来改变了。
所以就必须打开OnAinmatorMove()方法 (对应状态机中的OnStateMove()方法) 使角色的控制权交给脚本。可是此时发现角色又不能被动画根运动驱动了。(上马只播放动画,不旋转,也不发生位移)
可以在OnAinmatorMove中写
transform.position+=animator.deltaPosition;
transform.rotation*=animator.deltaRotation;
也可以直接在需要根运动改变角色位移的时候使用 ApplyBuiltinRootMotion ():
public void ApplyBuiltinRootMotion ();
描述
应用默认的根运动。
应用默认的根运动。请在 MonoBehaviour.OnAnimatorMove 或 StateMachineBehaviour.OnStateMove 中对您不想手动处理根运动的帧使用该方法。
还有 ApplyBuiltinRootMotion这个似乎要在OnAinmatorMove中每一帧都调用,如果用了if()开关只调用一次的话,就只会应用一帧的根运动。
override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.ApplyBuiltinRootMotion();
//要一直使用,不能放在if里面,不然就只有一帧会调用这个函数,只有一帧会应用根运动
if (isReady && !animator.IsInTransition(layerIndex))
{
transform.position = redSpherePosition + Vector3.down * 0.5f;
transform.rotation = Quaternion.LookRotation(hit.normal) * Quaternion.Euler(0, -25, 0);//调整-25度,使结束上马动画进入骑马动画时正对前
characterController.enabled = false;
animator.MatchTarget(redSpherePosition, Quaternion.identity, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 0), 0.2f, 0.8f);
//一个开关,是否准备好开始匹配目标
isReady = false;
}
}
==========================================================
Target matching只能对Base Layer(index 0,第一个权重改不了删除不了的层)生效
本来想用动画层给动画分一下类的。。
==========================================================
遇到其他关于这个函数的问题再更新