Melee Combo. How to implement

I have been working on a melee combo system for days and I am trying many things.
What I have to implement is a system allowing this:

Every Combo is an AnimMontage with the sequence of animations to perform the whole combo.
I have many sequences stored as strings like “LLLLR” (L->left click, R->right click).
I need to play the AnimMontage that corresponds to that sequence,

Where is the problem? Well, suppose I have 3 possible combos:

  1. LLLLL
  2. RRRRR
  3. LLLRL

When the player presses ‘L’ I start executing the AnimMontage associated with the combo 1.
Then it presses ‘L’ again and also a third time. The same AnimMontage is playing.
The it presses ‘R’. Here I need to change Montage to the 3d one.
I can already detect when this is necessary and when it comes the time to play that ‘R’ I call the Montage_Play with the new correct montage instead than on the old one.

The problem is that in this way it blends badly when I change AnimMontage.
Is there a better way (sure there is) to implement combo like these?

#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!

:slight_smile:

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 :slight_smile:

Again I’ve actually done this and got it working so I know it can work :slight_smile:

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;
}

Thanks.

I think I have problems with blending because with my system I start playing a different anim montage while another one is already playing. I suppose you don’t do this as you play one anim montage for each swing attack so you can just wait for the anim montage to end.

Another thing that can be a problem, my animations are made in this way: the first animation of a combo starts from Idle and ends in a position that is the same of the beginning position of the next animation in the combo (and so on). They don’t start or end in the Idle position.
Are your anims made in the same way?

A last thing…another thing I am scared is that having animations that ends in a pose that is very different from the Idle pose would require big blend out values. And with this high values when the attack is performed inside a combo sequence instead than alone it can break the visual continuity of the combo.

“Another thing that can be a problem, my animations are made in this way: the first animation of a combo starts from Idle and ends in a position that is the same of the beginning position of the next animation in the combo (and so on). They don’t start or end in the Idle position. Are your anims made in the same way?”

You can skip to different positions within an animation when you start playing it, and if each anim is its own montage, the montage will blend from wherever you skipped to.

Also

#You can simply do this

For Combo A To Combo B

A = start of combo chain

B = in themiddle

C = the end

Combo A Montage Blend in = 0.3

Comba A Blend out = 0

Combo B Montage Blend in = 0

Combo B Blend out = 0

Combo C Blend in = 0

Combo C Blend out = 0.3

These are set again in the montage assets


A last thing…another thing I am
scared is that having animations that
ends in a pose that is very different
from the Idle pose would require big
blend out values. And with this high
values when the attack is performed
inside a combo sequence instead than
alone it can break the visual
continuity of the combo.

your animation is responsible for returning to something reasonably close to idle if this is your concern

blend out from relatively-close-to-idle is all that you can ask UE4 to do if you want short blend out

Rama

Ok thanks, I think this makes a point on my next move with the combo system.
Thank you very much.

Anyway, playing a little bit with my implementation (one montage for each combo) I have found that if I have to switch between anim montages it works perfectly to use Montage_SetPosition. This gives me a great blend between the montages as they stop and start in a point where they have exactly the same pose for the skeleton. So now I have to decide if switching to the one-montage-per-attack implementation or not as it is working also in this way.

All the other blending problems comes from the fact that there are a couple of animations that ends in a pose very different from the Idle one.

Thanks again.