Created
January 13, 2019 14:51
-
-
Save Firefly74940/89cb14fa3c9396451070d2e22232d53a to your computer and use it in GitHub Desktop.
Random Sequence Player NoLoop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. | |
#include "DPGPluginPrivatePCH.h" | |
#include "AnimNode_WRandomPlayer.h" | |
#include "AnimationRuntime.h" | |
#include "Animation/AnimInstanceProxy.h" | |
FAnimNode_WRandomPlayer::FAnimNode_WRandomPlayer() | |
: CurrentEntry(INDEX_NONE) | |
, CurrentDataIndex(0) | |
{ | |
} | |
void FAnimNode_WRandomPlayer::Initialize_AnyThread(const FAnimationInitializeContext& Context) | |
{ | |
FAnimNode_Base::Initialize_AnyThread(Context); | |
EvaluateGraphExposedInputs.Execute(Context); | |
const int32 NumEntries = Entries.Num(); | |
if(NumEntries == 0) | |
{ | |
// early out here, no need to do anything at all if we're not playing anything | |
return; | |
} | |
NormalizedPlayChances.Empty(NormalizedPlayChances.Num()); | |
NormalizedPlayChances.AddUninitialized(NumEntries); | |
// Initialize normalized play chance for each entry and validate entry data | |
float SumChances = 0.0f; | |
for(FWRandomPlayerSequenceEntry& Entry : Entries) | |
{ | |
SumChances += Entry.ChanceToPlay; | |
} | |
for(int32 Idx = 0 ; Idx < NumEntries ; ++Idx) | |
{ | |
NormalizedPlayChances[Idx] = Entries[Idx].ChanceToPlay / SumChances; | |
} | |
// Initialize random stream and pick first entry | |
RandomStream.Initialize(FPlatformTime::Cycles()); | |
CurrentEntry = GetNextEntryIndex(); | |
PlayData.Empty(2); | |
PlayData.AddDefaulted(2); | |
FWRandomAnimPlayData& CurrentData = PlayData[CurrentDataIndex]; | |
// Init play data | |
CurrentData.PlayRate = RandomStream.FRandRange(Entries[CurrentEntry].MinPlayRate, Entries[CurrentEntry].MaxPlayRate); | |
} | |
void FAnimNode_WRandomPlayer::Update_AnyThread(const FAnimationUpdateContext& Context) | |
{ | |
EvaluateGraphExposedInputs.Execute(Context); | |
if(Entries.Num() == 0) | |
{ | |
// We don't have any entries, play data will be invalid - early out | |
return; | |
} | |
FWRandomAnimPlayData* CurrentData = &PlayData[CurrentDataIndex]; | |
if(UAnimSequence* CurrentSequence = Entries[CurrentEntry].Sequence) | |
{ | |
if(FAnimInstanceProxy* AnimProxy = Context.AnimInstanceProxy) | |
{ | |
FAnimGroupInstance* SyncGroup; | |
FAnimTickRecord& TickRecord = AnimProxy->CreateUninitializedTickRecord(INDEX_NONE, SyncGroup); | |
AnimProxy->MakeSequenceTickRecord(TickRecord, Entries[CurrentEntry].Sequence, false, CurrentData->PlayRate, Context.GetFinalBlendWeight(), CurrentData->InternalTimeAccumulator, CurrentData->MarkerTickRecord); | |
} | |
} | |
} | |
void FAnimNode_WRandomPlayer::Evaluate_AnyThread(FPoseContext& Output) | |
{ | |
if(Entries.Num() > 0) | |
{ | |
UAnimSequence* CurrentSequence = Entries[CurrentEntry].Sequence; | |
if(CurrentSequence) | |
{ | |
FWRandomAnimPlayData& CurrentData = PlayData[CurrentDataIndex]; | |
{ | |
// Single anim | |
CurrentSequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(CurrentData.InternalTimeAccumulator, Output.AnimInstanceProxy->ShouldExtractRootMotion())); | |
} | |
} | |
else | |
{ | |
Output.ResetToRefPose(); | |
} | |
} | |
else | |
{ | |
Output.ResetToRefPose(); | |
} | |
} | |
void FAnimNode_WRandomPlayer::GatherDebugData(FNodeDebugData& DebugData) | |
{ | |
FString DebugLine = DebugData.GetNodeName(this); | |
DebugData.AddDebugItem(DebugLine, true); | |
} | |
int32 FAnimNode_WRandomPlayer::GetNextEntryIndex() | |
{ | |
if(Entries.Num() > 0) | |
{ | |
{ | |
float RandomVal = RandomStream.GetFraction(); | |
const int32 NumEntries = Entries.Num(); | |
// Grab the entry index corresponding to the value | |
for(int32 Idx = 0 ; Idx < NumEntries ; ++Idx) | |
{ | |
RandomVal -= NormalizedPlayChances[Idx]; | |
if(RandomVal <= 0.0f) | |
{ | |
return Idx; | |
} | |
} | |
} | |
} | |
return INDEX_NONE; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. | |
#pragma once | |
#include "CoreMinimal.h" | |
#include "UObject/ObjectMacros.h" | |
#include "Math/RandomStream.h" | |
#include "Animation/AnimationAsset.h" | |
#include "Animation/AnimNodeBase.h" | |
#include "AnimNode_WRandomPlayer.generated.h" | |
struct FWRandomAnimPlayData | |
{ | |
FWRandomAnimPlayData() | |
: InternalTimeAccumulator(0.0f) | |
, PlayRate(1.0f) | |
{ | |
} | |
// Current time through the sequence | |
float InternalTimeAccumulator; | |
// Calculated play rate | |
float PlayRate; | |
// Marker tick record for this play through | |
FMarkerTickRecord MarkerTickRecord; | |
}; | |
/** The random player node holds a list of sequences and parameter ranges which will be played continuously | |
* In a random order. If shuffle mode is enabled then each entry will be played once before repeating any | |
*/ | |
USTRUCT(BlueprintInternalUseOnly) | |
struct FWRandomPlayerSequenceEntry | |
{ | |
GENERATED_BODY() | |
FWRandomPlayerSequenceEntry() | |
: Sequence(nullptr) | |
, ChanceToPlay(1.0f) | |
, MinPlayRate(1.0f) | |
, MaxPlayRate(1.0f) | |
{ | |
} | |
/** Sequence to play when this entry is picked */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings") | |
UAnimSequence* Sequence; | |
/** When not in shuffle mode, this is the chance this entry will play (normalized against all other sample chances) */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings") | |
float ChanceToPlay; | |
/** Minimum playrate for this entry */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings", meta=(UIMin="0", ClampMin="0")) | |
float MinPlayRate; | |
/** Maximum playrate for this entry */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings", meta=(UIMin="0", ClampMin="0")) | |
float MaxPlayRate; | |
}; | |
USTRUCT(BlueprintInternalUseOnly) | |
struct DPGPLUGIN_API FAnimNode_WRandomPlayer : public FAnimNode_Base | |
{ | |
GENERATED_BODY() | |
FAnimNode_WRandomPlayer(); | |
public: | |
/** List of sequences to randomly step through */ | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings") | |
TArray<FWRandomPlayerSequenceEntry> Entries; | |
// FAnimNode_Base interface | |
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override; | |
virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override; | |
virtual void Evaluate_AnyThread(FPoseContext& Output) override; | |
virtual void GatherDebugData(FNodeDebugData& DebugData) override; | |
// End of FAnimNode_Base interface | |
private: | |
int32 GetNextEntryIndex(); | |
// Normalized list of play chances when we aren't using shuffle mode | |
TArray<float> NormalizedPlayChances; | |
// The currently playing entry in the entries list | |
int32 CurrentEntry; | |
// Index of the 'current' data set in the PlayData array | |
int32 CurrentDataIndex; | |
// Play data for the current and next sequence | |
TArray<FWRandomAnimPlayData> PlayData; | |
// Random number source | |
FRandomStream RandomStream; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. | |
#include "DPGPluginPrivatePCH.h" | |
#include "Animation/AnimInstanceProxy.h" | |
#include "AnimNode_WRandomPlayerEditor.h" | |
#ifdef WITH_EDITOR | |
#include "EditorCategoryUtils.h" | |
#endif | |
#define LOCTEXT_NAMESPACE "AnimGraphNode_RandomPlayerNoLoop" | |
FLinearColor UAnimGraphNode_WRandomPlayer::GetNodeTitleColor() const | |
{ | |
return FLinearColor(0.10f, 0.60f, 0.12f); | |
} | |
FText UAnimGraphNode_WRandomPlayer::GetTooltipText() const | |
{ | |
return LOCTEXT("NodeToolTip", "Plays sequences picked from a provided list in random orders without looping"); | |
} | |
FText UAnimGraphNode_WRandomPlayer::GetNodeTitle(ENodeTitleType::Type TitleType) const | |
{ | |
return LOCTEXT("NodeTitle", "Random Sequence Player no Loop"); | |
} | |
FText UAnimGraphNode_WRandomPlayer::GetMenuCategory() const | |
{ | |
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Animation); | |
} | |
#undef LOCTEXT_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. | |
#pragma once | |
#include "CoreMinimal.h" | |
#include "UObject/ObjectMacros.h" | |
#include "Math/RandomStream.h" | |
#include "Editor/AnimGraph/Classes/AnimGraphNode_Base.h" | |
#include "src/AnimNode_WRandomPlayer.h" | |
#include "AnimNode_WRandomPlayerEditor.generated.h" | |
UCLASS(MinimalAPI) | |
class UAnimGraphNode_WRandomPlayer : public UAnimGraphNode_Base | |
{ | |
GENERATED_BODY() | |
public: | |
UPROPERTY(EditAnywhere, Category = Settings) | |
FAnimNode_WRandomPlayer Node; | |
// UEdGraphNode interface | |
virtual FLinearColor GetNodeTitleColor() const override; | |
virtual FText GetTooltipText() const override; | |
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; | |
virtual FText GetMenuCategory() const override; | |
// End of UEdGraphNode interface | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment