Freezing Enemies

The last core mechanic of the GLOO Cannon is to slow and ultimately gloo enemies in their tracks!

Lets make a new ActorComponent which will handle the weight.

The idea is that whenever gloo hits a character, we will AddWeight which slows the character's MaxWalkSpeed on their MovementComponent with each gloo till it exceeds a threshold and freezes in place.

.h

// WeightComponent.h

void AddWeight();

UFUNCTION(BlueprintCallable)
bool IsGlood() { return WeightContributorCount >= WeightThreshold; }

UPROPERTY()
UCharacterMovementComponent* MovementComponent;

UPROPERTY(EditAnywhere, meta=(ClampMin=1))
int WeightThreshold;

int WeightContributorCount;

.cpp

// WeightComponent.cpp

void UWeightComponent::BeginPlay()
{
	Super::BeginPlay();

	const ACharacter* Owner = Cast<ACharacter>(GetOwner());
	if (Owner)
	{
		MovementComponent = Owner->GetCharacterMovement();
	}	
}

void UWeightComponent::AddWeight()
{
	if (IsGlood())
		return;

	++WeightContributorCount;

	if (MovementComponent)
	{
		const float CurrentMaxWalkSpeed = MovementComponent->MaxWalkSpeed;
		MovementComponent->MaxWalkSpeed = CurrentMaxWalkSpeed * 0.8f;

		if (IsGlood())
		{
			MovementComponent->DisableMovement();
		}
	}
}

Just slamming a new value into the MaxWalkSpeed is rather abrupt, and if you wanted a smoother experience you could interpolate instead.

Now we just need to make the call to AddWeight whenever gloo hits a character. Lets add a new function to handle that in Projectile

.h

// GlooCannonProjectile.h

void AddWeightToTarget(const ACharacter* OtherCharacter) const;

.cpp

// GlooCannonProjectile.cpp

void AGlooCannonProjectile::CreateGlooBlob(AActor* OtherActor, UPrimitiveComponent* OtherComp, const FHitResult& Hit)
{
	// ...
	if (GlooBlob)
	{
		// ...
		if (const ACharacter* OtherCharacter = Cast<ACharacter>(OtherActor))
		{
			AddWeightToTarget(OtherCharacter);
		}
		else
		{
			GlooBlob->AddSplatter(Hit);
		}
	}
}

void AGlooCannonProjectile::AddWeightToTarget(const ACharacter* OtherCharacter) const
{
	if (!OtherCharacter)
		return;

	UWeightComponent* WeightComponent = Cast<UWeightComponent>(OtherCharacter->GetComponentByClass(UWeightComponent::StaticClass()));
	if (WeightComponent)
	{
		WeightComponent->AddWeight();
	}
}

Now we can add the WeightComponent to any character we want affected by Gloo!

Lastly to avoid visual jarring it would be nice if the animation also slowed down with the speed to make it more believable like it's getting harder and harder to move.

A simple way to achieve this is by making the animation's PlayRate dependent on move speed

Additionally I randomly spawn gloo blobs on select bone sockets when the character is hit which I think looks nice.

Last updated