一个物体在Scene窗口看不见Game窗口能看见。选中它时打开Gizmos也看不见身上碰撞体的线框。也无法被射线检测到。换成其他MeshOpen Asset In Context正常显示把它Revert回预制体还是不显示。Ctrl D复制一个正常显示。把MeshFilter填入其他模型也不显示但是物体显示橙色轮廓把Scene复制一份复制的场景里正常显示。原因hierarchy左侧点了不可见。射击射线方向设置为枪的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目标的最低级共同父节点是PIK目标最多可以做P的一级子节点而没有偏移。这里枪和左手的最低级共同父节点是ChestIK目标作为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 VectorIK的位置并没有变右手的位置也没有变。那么有没有方法让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是1Body的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可能和这个有关系。事件public event UnityAction onDataChanged;在Start里添加监听触发没有执行监听方法在Model类非Mono里的一个事件一个MonoBehavior管理器在Start里添加了监听。写一个打印所有监听者的public void PrintListeners() { Debug.Log(监听者有); foreach (var eve in onDataChanged.GetInvocationList()) { Debug.Log(eve.Method.Name); } }刚后打印有监听方法触发的时候打印事件为空然后手动打印已经是空了。[ContextMenu(玩家背包数据变化的监听者有)] void Look() { player.pack.PrintListeners(); }然后在Update第一帧打印bool prtrue; private void Update() { if (pr) { pr false; Look(); } } [ContextMenu(玩家背包数据变化的监听者有)] void Look() { player.pack.PrintListeners(); }已经是空了。然后研究失去方向只能瞎试了。把event去掉变成普通委托问题还在。现在我们知道这个事件在Start和第一次Update之间被什么东西设空了。然后添加2次、多次监听打印都是空说明是被null而不是-。然后继续瞎猜把Model类的[Serializable]去掉没用。然后看了这个Model对象被写入的记录发现model除了被new过一次还被管理器写入过一次。所以是这里的问题。打印显示添加监听的时候用的是new的model然后model又被管理器赋值。那么就不能让Start不可控顺序地执行初始化了。既然Start顺序不可控还没有参数继承MonoBehavior已失去意义。就直接不继承MonoBehavior了也不用单例了而是作为总管理器的成员。这引出了一个大问题就是含有事件的类一般是数据类随意new、写入对象导致事件监听者丢失那么就两个解决方法不要在声明后面直接newnew作为从持久化数据读不到的兜底。要么把所有返回数据类的方法改成输入数据类给字段赋值的。声明时不new就要考虑数据为空的情况那么在这些情景手动调用new事件不放在数据类放在控制器类。控制器引用的model可能不同时间是不同的实例。问题是model类对数据增删改查的方法知道什么时候数据变化了model不能访问控制器事件放控制器需要增删改查也放控制器但这不合理增删改查方法应该和数据放在一起
Unity问题记录
一个物体在Scene窗口看不见Game窗口能看见。选中它时打开Gizmos也看不见身上碰撞体的线框。也无法被射线检测到。换成其他MeshOpen Asset In Context正常显示把它Revert回预制体还是不显示。Ctrl D复制一个正常显示。把MeshFilter填入其他模型也不显示但是物体显示橙色轮廓把Scene复制一份复制的场景里正常显示。原因hierarchy左侧点了不可见。射击射线方向设置为枪的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目标的最低级共同父节点是PIK目标最多可以做P的一级子节点而没有偏移。这里枪和左手的最低级共同父节点是ChestIK目标作为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 VectorIK的位置并没有变右手的位置也没有变。那么有没有方法让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是1Body的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可能和这个有关系。事件public event UnityAction onDataChanged;在Start里添加监听触发没有执行监听方法在Model类非Mono里的一个事件一个MonoBehavior管理器在Start里添加了监听。写一个打印所有监听者的public void PrintListeners() { Debug.Log(监听者有); foreach (var eve in onDataChanged.GetInvocationList()) { Debug.Log(eve.Method.Name); } }刚后打印有监听方法触发的时候打印事件为空然后手动打印已经是空了。[ContextMenu(玩家背包数据变化的监听者有)] void Look() { player.pack.PrintListeners(); }然后在Update第一帧打印bool prtrue; private void Update() { if (pr) { pr false; Look(); } } [ContextMenu(玩家背包数据变化的监听者有)] void Look() { player.pack.PrintListeners(); }已经是空了。然后研究失去方向只能瞎试了。把event去掉变成普通委托问题还在。现在我们知道这个事件在Start和第一次Update之间被什么东西设空了。然后添加2次、多次监听打印都是空说明是被null而不是-。然后继续瞎猜把Model类的[Serializable]去掉没用。然后看了这个Model对象被写入的记录发现model除了被new过一次还被管理器写入过一次。所以是这里的问题。打印显示添加监听的时候用的是new的model然后model又被管理器赋值。那么就不能让Start不可控顺序地执行初始化了。既然Start顺序不可控还没有参数继承MonoBehavior已失去意义。就直接不继承MonoBehavior了也不用单例了而是作为总管理器的成员。这引出了一个大问题就是含有事件的类一般是数据类随意new、写入对象导致事件监听者丢失那么就两个解决方法不要在声明后面直接newnew作为从持久化数据读不到的兜底。要么把所有返回数据类的方法改成输入数据类给字段赋值的。声明时不new就要考虑数据为空的情况那么在这些情景手动调用new事件不放在数据类放在控制器类。控制器引用的model可能不同时间是不同的实例。问题是model类对数据增删改查的方法知道什么时候数据变化了model不能访问控制器事件放控制器需要增删改查也放控制器但这不合理增删改查方法应该和数据放在一起