void UAnimSingleNodeInstance::SetPosition(float InPosition, bool bFireNotifies)
{
	float PreviousTime = CurrentTime;
	CurrentTime = FMath::Clamp<float>(InPosition, 0.f, GetLength());

	if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
	{
		CurMontageInstance->SetPosition(CurrentTime);
	}

	// Handle notifies
	// the way AnimInstance handles notifies doesn't work for single node because this does not tick or anything
	// this will need to handle manually, emptying, it and collect it, and trigger them at once. 
	if (bFireNotifies)
	{
		UAnimSequenceBase * SequenceBase = Cast<UAnimSequenceBase> (CurrentAsset);
		if (SequenceBase)
		{
			AnimNotifies.Empty();

			TArray<const FAnimNotifyEvent*> Notifies;
			SequenceBase->GetAnimNotifiesFromDeltaPositions(PreviousTime, CurrentTime, Notifies);
			if ( Notifies.Num() > 0 )
			{
				// single node instance only has 1 asset at a time
				AddAnimNotifies(Notifies, 1.0f);
			}

			TriggerAnimNotifies(0.f);

		}
	}
}
void UAnimSingleNodeInstance::SetPosition(float InPosition, bool bFireNotifies)
{
	float PreviousTime = CurrentTime;
	CurrentTime = FMath::Clamp<float>(InPosition, 0.f, GetLength());

	if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
	{
		CurMontageInstance->SetPosition(CurrentTime);
	}

	// Handle notifies
	// the way AnimInstance handles notifies doesn't work for single node because this does not tick or anything
	// this will need to handle manually, emptying, it and collect it, and trigger them at once. 
	if (bFireNotifies)
	{
		UAnimSequenceBase * SequenceBase = Cast<UAnimSequenceBase> (CurrentAsset);
		if (SequenceBase)
		{
			AnimNotifies.Empty();

			TArray<const FAnimNotifyEvent*> Notifies;
			SequenceBase->GetAnimNotifiesFromDeltaPositions(PreviousTime, CurrentTime, Notifies);
			if ( Notifies.Num() > 0 )
			{
				// single node instance only has 1 asset at a time
				AddAnimNotifies(Notifies, 1.0f);
			}

			TriggerAnimNotifies(0.f);

			// since this is singlenode instance, if position changes, we can't keep old morphtarget curves
			// we clear it and evaluate curve here with new asset. 
			MorphTargetCurves.Empty();
			MaterialParameterCurves.Empty();
			// Evaluate Curve data now - even if time did not move, we still need to return curve if it exists
			SequenceBase->EvaluateCurveData(this, CurrentTime, 1.0);
		}
	}
}
Esempio n. 3
0
void UAnimInstance::UpdateAnimation(float DeltaSeconds)
{
#if WITH_EDITORONLY_DATA
	if (GIsEditor)
	{
		// Reset the anim graph visualization
		if (RootNode != NULL)
		{
			if (UAnimBlueprintGeneratedClass* AnimBlueprintClass = Cast<UAnimBlueprintGeneratedClass>(GetClass()))
			{
				UAnimBlueprint* AnimBP = CastChecked<UAnimBlueprint>(AnimBlueprintClass->ClassGeneratedBy);

				if (AnimBP->GetObjectBeingDebugged() == this)
				{
					AnimBlueprintClass->GetAnimBlueprintDebugData().ResetNodeVisitSites();
				}
			}
		}

		// Update the lifetimer and see if we should use the snapshot instead
		CurrentLifeTimerScrubPosition += DeltaSeconds;
		LifeTimer = FMath::Max<double>(CurrentLifeTimerScrubPosition, LifeTimer);

		if (UpdateSnapshotAndSkipRemainingUpdate())
		{
			return;
		}
	}
#endif

	AnimNotifies.Empty();
	MorphTargetCurves.Empty();

	ClearSlotNodeWeights();

	//Track material params we set last time round so we can clear them if they aren't set again.
	MaterialParamatersToClear.Empty();
	for( auto Iter = MaterialParameterCurves.CreateConstIterator(); Iter; ++Iter )
	{
		if(Iter.Value() > 0.0f)
		{
			MaterialParamatersToClear.Add(Iter.Key());
		}
	}
	MaterialParameterCurves.Empty();
	VertexAnims.Empty();

	// Reset the player tick list (but keep it presized)
	UngroupedActivePlayers.Empty(UngroupedActivePlayers.Num());
	for (int32 GroupIndex = 0; GroupIndex < SyncGroups.Num(); ++GroupIndex)
	{
		SyncGroups[GroupIndex].Reset();
	}

	NativeUpdateAnimation(DeltaSeconds);
	BlueprintUpdateAnimation(DeltaSeconds);

	// update weight before all nodes update comes in
	Montage_UpdateWeight(DeltaSeconds);

	// Update the anim graph
	if (RootNode != NULL)
	{
		IncrementContextCounter();
		FAnimationUpdateContext UpdateContext(this, DeltaSeconds);
		RootNode->Update(UpdateContext);
	}

	// curve values can be used during update state, so we need to clear the array before ticking each elements
	// where we collect new items
	EventCurves.Empty();

	// Handle all players inside sync groups
	for (int32 GroupIndex = 0; GroupIndex < SyncGroups.Num(); ++GroupIndex)
	{
		FAnimGroupInstance& SyncGroup = SyncGroups[GroupIndex];

		if (SyncGroup.ActivePlayers.Num() > 0)
		{
			const int32 GroupLeaderIndex = FMath::Max(SyncGroup.GroupLeaderIndex, 0);

			// Tick the group leader
			FAnimAssetTickContext TickContext(DeltaSeconds);
			FAnimTickRecord& GroupLeader = SyncGroup.ActivePlayers[GroupLeaderIndex];
			GroupLeader.SourceAsset->TickAssetPlayerInstance(GroupLeader, this, TickContext);

			// Update everything else to follow the leader
			if (SyncGroup.ActivePlayers.Num() > 1)
			{
				TickContext.ConvertToFollower();

				for (int32 TickIndex = 0; TickIndex < SyncGroup.ActivePlayers.Num(); ++TickIndex)
				{
					if (TickIndex != GroupLeaderIndex)
					{
						const FAnimTickRecord& AssetPlayer = SyncGroup.ActivePlayers[TickIndex];
						AssetPlayer.SourceAsset->TickAssetPlayerInstance(AssetPlayer, this, TickContext);
					}
				}
			}
		}
	}

	// Handle the remaining ungrouped animation players
	for (int32 TickIndex = 0; TickIndex < UngroupedActivePlayers.Num(); ++TickIndex)
	{
		const FAnimTickRecord& AssetPlayerToTick = UngroupedActivePlayers[TickIndex];
		FAnimAssetTickContext TickContext(DeltaSeconds);
		AssetPlayerToTick.SourceAsset->TickAssetPlayerInstance(AssetPlayerToTick, this, TickContext);
	}

	// update montage should run in game thread
	// if we do multi threading, make sure this stays in game thread
	Montage_Advance(DeltaSeconds);

	// now trigger Notifies
	TriggerAnimNotifies(DeltaSeconds);

	// Add 0.0 curves to clear parameters that we have previously set but didn't set this tick.
	//   - Make a copy of MaterialParametersToClear as it will be modified by AddCurveValue
	TArray<FName> ParamsToClearCopy = MaterialParamatersToClear;
	for (int i = 0; i < ParamsToClearCopy.Num(); ++i)
	{
		AddCurveValue(ParamsToClearCopy[i], 0.0f, ACF_DrivesMaterial);
	}


#if WITH_EDITOR && 0
	{
		// Take a snapshot if the scrub control is locked to the end, we are playing, and we are the one being debugged
		if (UAnimBlueprintGeneratedClass* AnimBlueprintClass = Cast<UAnimBlueprintGeneratedClass>(GetClass()))
		{
			if (UAnimBlueprint* Blueprint = Cast<UAnimBlueprint>(AnimBlueprintClass->ClassGeneratedBy))
			{
				if (Blueprint->GetObjectBeingDebugged() == this)
				{
					if ((CurrentLifeTimerScrubPosition == LifeTimer) && (DeltaSeconds > 0.0f))
					{
						AnimBlueprintClass->GetAnimBlueprintDebugData().TakeSnapshot(this);
					}
				}
			}
		}
	}
#endif
}