#The Combo System I Use
Dear Ivan,
In my game I have a sword combo system, and I do the following:
- each swing / phase of combo is stored as a separate animation
- there is an anim slot for the arm associated with the swing, like the right arm, if I want to do it while running
- there is a full body slot for swings that must use the legs
Then I have a global FString that stores the keys the player has pressed, stored very similar to what you write above of LRRRL etc
FString ComboString;
As the player is pressing keys I add them to the combo string and check where the player is in the sequence, and play the appropriate animation on the anim slot (via play anim montage).
#Blending
Blending between animations being played on the same animation slot works perfectly for me!
I customize how fast a particular animation blends in and out using the values available within each anim montage itself, again keep in mind each anim montage corresponds to exactly 1 phase of any combo
#Summary
Using an FString stored in C++ I track what phase of a combo the player is in and play each animations separately, often on the same anim slot but not always
blending animations on the same anim slot, one after the other, works fabulously for me
Again I’ve actually done this and got it working so I know it can work
Rama
PS: here’s the anim montage code I am using, it is server function because I have multiplayer game
#.h
/** play anim montage */
UFUNCTION(reliable, server)
void PlayMontage(class UAnimMontage* Anim, float PlayRate = 1.0f, float StartTime=0);
UPROPERTY(Replicated)
float CurMontageDuration;
UPROPERTY(Replicated)
float CurMontageStartTime;
UPROPERTY(Replicated)
float CurMontagePlayRate;
UPROPERTY(Replicated)
UAnimMontage* RepAnim;
UPROPERTY(ReplicatedUsing=OnRep_PlayMontage)
bool DoRepPlayMontage;
UFUNCTION()
void OnRep_PlayMontage();
#.cpp
void VictoryChar::PlayMontage_Implementation(class UAnimMontage* Anim, float PlayRate = 1.0f, float StartTime=-1)
{
//Rep
CurMontagePlayRate = PlayRate;
CurMontageStartTime = StartTime;
RepAnim = Anim;
DoRepPlayMontage = !DoRepPlayMontage; //to rep all things and repeate calls
//Server
OnRep_PlayMontage();
}
void VictoryChar::OnRep_PlayMontage()
{
if(CurMontagePlayRate == 0) return;
if (RepAnim && Mesh && Mesh->AnimScriptInstance)
{
const float TheDuration = Mesh->AnimScriptInstance->Montage_Play(RepAnim, CurMontagePlayRate);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SET MONTAGE POSITION
if(CurMontageStartTime > 0)
{
//Move Montage To Position!
AnimationBase->Montage_SetPosition(RepAnim, CurMontageStartTime);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Server only set the duration
if (HasAuthority()) CurMontageDuration = TheDuration/CurMontagePlayRate - CurMontageStartTime;
return;
}
//Server only set the duration
if (HasAuthority()) CurMontageDuration = 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Replication List
int32* VictoryChar::GetReplicationList(uint8* Recent, FPropertyRetirement* Retire, int32* Ptr, UPackageMap* Map, UActorChannel* Channel, FReplicationFlags RepFlags)
{
Ptr = Super::GetReplicationList(Recent, Retire, Ptr, Map, Channel, RepFlags);
DOREP(VictoryChar, DoRepPlayMontage);
DOREP(VictoryChar, RepAnim);
DOREP(VictoryChar, CurMontageDuration);
DOREP(VictoryChar, CurMontagePlayRate);
DOREP(VictoryChar, CurMontageStartTime);
return Ptr;
}