Gloo Blob Functionality

Next we want to create the GLOO projectile.

First we can disable the bounce effect and reduce the intial collision radius to match the original game

.cpp

// GlooCannonProjectile.cpp

AGlooCannonProjectile::AGlooCannonProjectile() 
{
	// ...
	CollisionComp->InitSphereRadius(2.5f);
	ProjectileMovement->bShouldBounce = false;
	// ...
}

Gloo Spawning

Now we can get to the creation of the GLOO object.

Create a new Actor class which will represent a GLOO blob and give our Projectile a reference to this class

.h

// GlooCannonProjectile.h

UPROPERTY(EditDefaultsOnly, Category=Projectile)
TSubclassOf<AGlooBlob> GlooBlobClass;

We want to spawn a GLOO object whenever it hits something (special logic for hitting enemies later on)

.cpp

// GlooCannonProjectile.cpp

void AGlooCannonProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	if (GlooBlobClass && (OtherActor != this))
	{
		CreateGlooBlob(OtherActor, OtherComp, Hit);
	}
	
	Destroy();
}

The CreateGlooBlob will be responsible for creating a new gloo object.

For now it's quite simple but we will build upon it as we get further

.cpp

// GlooCannonProjectile.cpp

void AGlooCannonProjectile::CreateGlooBlob(AActor* OtherActor, UPrimitiveComponent* OtherComp, const FHitResult& Hit)
{
	if (UWorld* World = GetWorld())
	{
		FActorSpawnParameters SpawnParameters;
		SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
		
		World->SpawnActor<AActor>(GlooBlobClass, GetActorLocation(), FRotator::ZeroRotator, SpawnParameters);
	}
}

Before we can start shooting GLOO we need to finish the GlooBlob class

.h

// GlooBlob.h

UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Component")
UBoxComponent* BoxCollision;

UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Components")
UStaticMeshComponent* StaticMesh;

.cpp

// GlooBlob.cpp

AGlooBlob::AGlooBlob()
{
	PrimaryActorTick.bCanEverTick = true;

	BoxCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxCollision"));
	BoxCollision->SetCollisionResponseToAllChannels(ECR_Block);
	BoxCollision->SetGenerateOverlapEvents(true);
	BoxCollision->SetBoxExtent(FVector(25)); // change to your step height preference
	RootComponent = BoxCollision;

	StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMesh->SetGenerateOverlapEvents(false);
	StaticMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	StaticMesh->SetupAttachment(BoxCollision);
}

A core aspect of the GLOO blobs is that the player can walk on them as ramps, or bridges so changing the CharacterMovementComponent's 'Walking' and properties to your needs (increasing the step height or walkable flooring...etc)

I'll leave it to default but tweak as needed

Create a BP of the new Gloo object class and set a reference to it in the Projectile Blueprint

BP_FirstPersonProjectile

Rotate to Surface

One thing to notice is that the Gloo Blobs are always spawning facing the same direction which doesn't look the best

To fix this we simply need to rotate the spawned Gloo Blob so its forward is parallel to the surface Normal

UE's forward vector is the (Y) axis therefor we need to rotate around the (Z) axis

Instead of using FRotator::ZeroRotator we'll use the rotation based off the surface normal when spawning our Gloo Blob

.cpp

// GlooCannonProjectile.cpp

void AGlooCannonProjectile::CreateGlooBlob
{
    //...
    const FRotator SpawnRotation = FRotationMatrix::MakeFromZ(Hit.Normal).Rotator();
    World->SpawnActor<AActor>(GlooBlobClass, GetActorLocation(), SpawnRotation, SpawnParameters);
    //...
}

Adding Weight to physics objects

Another core mechanic of Prey's GLOO is that it adds weight to physics objects so lets do that here.

A simple solution, without worrying about managing an objects total weight, or keeping track of an independent weight multiplier value, instead since Physics objects already respond to gravity we can apply a small bit of force in the opposite direction which gives the effect of weight being added onto wherever the blob attaches

.cpp

// GlooCannonProjectile.cpp

void AGlooCannonProjectile::CreateGlooBlob
{
	//...
	// We need to store the newly spawned gloo object now so we can attach it
    	AGlooBlob* GlooBlob = static_cast<AGlooBlob*>(World->SpawnActor<AActor>(GlooBlobClass, GetActorLocation(), SpawnRotation, SpawnParameters));
	if (GlooBlob)
	{
		if (OtherComp->IsSimulatingPhysics())
		{
		   	const FAttachmentTransformRules AttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, true);
			GlooBlob->AttachToActor(OtherActor, AttachmentRules);
			OtherComp->AddImpulseAtLocation(-GetVelocity(), Hit.Location);
		}
	}
    	//...
}

Last updated