射击射线方向设置为枪的z轴正方向,使用Debug.DrawRay(),画出的射线在两种情况之间不停变化。
此时人物的Chest用了Aim Constraint组件,把这个组件关掉,这个现象的就消失了,射线很平稳。
推测原因:AimConstraint组件在不停改变Chest的旋转,Debug.DrawRay()如果在Update里执行,好像在一帧里Update()和AimConstraint执行的顺序是不一定的,有些帧Update()执行时AimConstraint组件还没有改变Chest的旋转,Chest的朝向还和没有AimConstraint一样,它的子物体机瞄相机forward方向发出的射线也是原来的方向。
把人物仰起来,进一步证实了这个猜想:两条射线一条是仰起的,一条还是平的。
解决方法:在LateUpdate()里调用计算射击射线的起点和方向的代码,可保证计算射线起点和方向时AimConstraint已经对Chest的旋转做过改变。好像在一帧里LateUpdate()总是在AimConstraint之后执行。
Aim Constraint约束的物体旋转不对
想让人物头的z轴朝向小球,结果变成了这样
原因:Aim Constraint里的Constraint Settings设置了Rotation Offset的Y为90.
使用IK调整手的位置,但是手的位置不在IK的位置,有偏差
左手IK是枪的子节点。坐标轴标识的是左手IK的位置,明显在左手下方。
又在人物的Chest下建了个子节点作为左手IK目标,发现手能被完美拉到IK目标的位置。
又做了几个实验,不改变IK目标的位置,只改变父节点,左手的位置确实会变化:
做Neck的子节点:手在IK目标处
做Head的子节点:手在IK目标下方
做Right wrist的子节点:手在IK目标上方
大概规律:假设被约束物体和IK目标的最低级共同父节点是P,IK目标最多可以做P的一级子节点而没有偏移。这里枪和左手的最低级共同父节点是Chest,IK目标作为Chest及其一级子节点Right shoulder、Neck的子节点时,没有偏移,从Right shoulder的一级节点Right arm开始往下,Neck的一级节点Head开始往下,IK目标做这些节点的子节点时,会出现偏移。
但是这不合理,设置IK的方法接收的只是一个Vector3和一个Quaternion,这几个方法根本不知道给它们位置和旋转数据的节点是谁的父节点。
后来发现还是因为AimConstraint组件。我给Head加了AimConstraint组件,由前面的经验知道,在某些帧执行Update()的时候AimConstraint是不生效的。这里可能IK用的是AimConstraint生效前的IK位置,窗口里显示的是AimConstraint生效后的位置。把Head的AimConstraint关掉,确实IK位置和右手一致了。
可以得出结论:OnAnimatorIK()执行的时候AimConstraint还没有生效,但是手动把IK拖成Head的子节点时AimConstraint是生效了的,且Scene里显示的是AimConstraint生效后的位置。或者说,如果IK目标是一个带有AimConstraint的物体的子物体,那么用来约束时用的是没有启用AimConstaint时IK的位置。
下面的实验可以进一步证明这一点:把IK作为Head的子物体,通过改变AimConstraint的参数使头部转动(可以改Sources物体的位置,也可以改Aim Vector、Up Vector),IK的位置并没有变,右手的位置也没有变。
那么有没有方法让OnAnimatorIK()使用AimConstaint生效后的IK位置?或许可以在LateUpdate()里把IK的位置和旋转存在变量里,再传给OnAnimatorIK(),我试了,IK是能跟头一起运动了,但是有滞后。而且手的位置和IK偏差很大。
据此可以得到经验:调IK之前务必先关掉AimConstraint,这样无论是Scene窗口里看到的IK位置,还是OnAnimatorIK()里用到的,才和实际的数据一样。
我在Chest上也挂了AimConstraint,那么如果把IK改成Spine的子节点,则引擎先在AimConstraint没生效时把手约束到IK的位置,再加上AimConstraint的效果。结果就是腰的仰角越大,手和IK偏差越大,实验结果确实是这样:
而把左手IK挂在枪上产生的偏差很容易想到是因为引擎在双手IK没生效时确定好双手IK的位置,然后使双手IK生效,这时左手IK因为右手被约束偏移而产生了偏移,而左手还是被约束到IK生效之前的位置,导致二者位置不一致。这一点可以关闭右手IK,看左手和左手IK是否一致来确定。
关闭右手IK后左手IK和左手:位置一致
开启右手IK,左手IK的位置产生一个偏移,左手位置不变:
更一般的结论:使用多个改变动画的组件协作时(如IK、AimConstraint、AnimationRigging、AvatarMask),出现未预期的效果很可能是因为几个组件没有按预想的顺序叠加,可能是各自生效后叠加,或者叠加顺序不对。此时可以把所有组件撤掉一个个加上,看从哪一步出问题。所以应该少用改变动画的组件,尽量修改动画本身。
执行Destroy()没有生效
原因:ParticleSystem是组件,Destroy()组件是从物体上移除该组件。
解决方法:改成Destroy(bloodshed.gameObject);
丘丘人每换一次弹匣,弹匣会变小一些
换弹匣就是把弹匣挂到左手上,装弹匣的时候再挂回枪上。这个枪素材的scale不是1,我知道和这个有关系。其他人物换弹匣没这个问题。
我发现
1.父物体scale变化时,子物体在监视器里的scale不变,但是子物体的实际大小变了
2.物体的父物体改变后,引擎会自动修改它的scale,使它的实际大小不变,这应该能保证换弹后弹匣大小不变
3.这个问题和我把Mag弹匣作为Body枪身的子物体有关,作为根节点AK47的子物体是没问题的,而且根节点的Scale是1,Body的Scale不是1.
今天用胡桃换了很多次弹匣,发现弹匣也是会变小的,只是每次变小的不明显,要换很多次才能看出来。而且每换一次弹匣的Scale都不一样。
结论就是:一个物体的父物体会变化的时候,尽量把它挂在Scale是1的物体下。如果不是1就在blender里ctrl a应用缩放。
敌人没有按动画事件设置的频率射击
使用动画事件控制敌人开始射击和停止射击的时机,人物没有按设计的频率射击。很长时间不射击,也有时候不停射击。
这里打印pullTrigger,是True。但是敌人检查器的pullTrigger字段是False。
然后我想到我刚给死亡动画加了停止射击的关键帧,且Any State会过渡到死亡状态。把死亡动画的停止射击移除,果然问题消失了。但是它又没有转换到死亡状态,为什么会播放死亡动画的关键帧?
人物死亡使用布娃娃效果,敌人打死NPC没有关闭animator,我打死NPC正常开启布娃娃
开启布娃娃里用协程关闭了animator,研究发现在yield return之前打印都正常,后面打印没有效果。只有NPC打死NPC有这个问题,NPC打死我、我打死NPC都正常。用[ContextMenu()]执行死亡方法也有问题。
这段代码是我抄的。为什么要用协程关动画呢?我试了试直接关动画,布娃娃正常开启了。
后来这个问题不出现了。不了了之了。
敌人被打死后我靠近又突然开枪
开始运行后人物自己向前移动
原因:不小心在人物Hips上加了非触发器碰撞体,和人物碰撞体碰撞。
开始运行后第一次换弹回到初始的位置和旋转
把Animator Override Controller替换换弹动画的代码删掉,问题就消失了。
然后注意到此时人物用的是Animator Controller不是Animator Override Controller。说明运行时新建Animator Override Controller再替换动画会导致人物回到初始Transform。应该直接给人物用Animator Override Controller。
M21开瞄准镜后瞄准相机只能左右旋转,改变人物仰角瞄准相机的仰角不变,关镜、到Scene窗口再回去仰角会更新
好像在瞄准镜状态下人物的仰角没有每帧更新。
另一个狙击枪VSS没这个问题。初始拿VSS,换成M21会有问题。改成初始拿M21,换成VSS,两个枪都没问题了。
针对看一眼Scene窗口就更新的情况,我把Game和Scene窗口同时显示,然后就™没问题了。好像animator.SetBoneLocalRotation()有人看着它就更新,不看着就不更新。
把瞄准相机后移到某个程度,问题就消失了。
然后我去找animator更新的设置,把Culling Mode改成Always Animate,问题解决。
->
VSS没出问题可能因为它比较短,animator还认为我在看它,所以保持更新。我把VSS的瞄准相机往前放,放到这个位置,也出现同样的问题:
出问题的距离比M21远得多,然后我发现VSS模型的缩放是100,可能和这个有关系。