初始设置:
动画状态机:
MoveStop->Idle的条件:
使用该节点的目的:
在动画蓝图的过渡条件中使用该节点,保证上一个状态的动作完成后进入下一个动作。需求是MoveStop动作完成后才能进入Idle状态。
Bug现象:
启动游戏后,第一次进入该状态时会直接过渡到Idle状态。
此时状态机的状态:
状态机条件:
但是之后再次进入该状态就会正常。状态只会在Move和MoveStop之间过渡。BUG只在启动游戏后第一次进入该状态时出现。
原因:
float UAnimInstance::GetRelevantAnimTimeRemainingFraction(int32 MachineIndex, int32 StateIndex) { if(FAnimNode_AssetPlayerBase* AssetPlayer = GetRelevantAssetPlayerFromState(MachineIndex, StateIndex))//AssetPlayer在这里是NULL { if(AssetPlayer->GetAnimAsset()) { float Length = AssetPlayer->GetAnimAsset()->GetMaxCurrentTime(); if(Length > 0.0f) { return (Length - AssetPlayer->GetAccumulatedTime()) / Length; } } } return 0.0f; }
断点后发现第一次进入该状态时,AssetPlayer为NULL。
FAnimNode_AssetPlayerBase* UAnimInstance::GetRelevantAssetPlayerFromState(int32 MachineIndex, int32 StateIndex) { FAnimNode_AssetPlayerBase* ResultPlayer = nullptr; if(FAnimNode_StateMachine* MachineInstance = GetStateMachineInstance(MachineIndex)) { float MaxWeight = 0.0f; const FBakedAnimationState& State = MachineInstance->GetStateInfo(StateIndex); for(const int32& PlayerIdx : State.PlayerNodeIndices) { if(FAnimNode_AssetPlayerBase* Player = GetNodeFromIndex<FAnimNode_AssetPlayerBase>(PlayerIdx)) { if(!Player->bIgnoreForRelevancyTest && Player->GetCachedBlendWeight() > MaxWeight) { MaxWeight = Player->GetCachedBlendWeight(); ResultPlayer = Player; } } } } return ResultPlayer; }
再进入GetRelevantAssetPlayerFromState查看到Player->GetCachedBlendWeight返回结果均为0.
由于状态机切换状态时先执行条件判断,再执行AnimNode的Update。所以未Update过的FAnimNode_AssetPlayerBase的BlendWeight都是0.导致返回的ResultPlayer是nullptr。
void FAnimNode_AssetPlayerBase::Update(const FAnimationUpdateContext& Context) { // Cache the current weight and update the node BlendWeight = Context.GetFinalBlendWeight(); UpdateAssetPlayer(Context); }
解决办法:
避免GetRelevantAnimTimeRemainingFraction==0。小于0.1且不等于0,过渡条件为true。
注:可能是我自己使用上的问题,若有正确使用方法请告知。