Building The Core Gameplay Loop
🔨

Building The Core Gameplay Loop

Tags
Owner
Justin Nearing

It's been the first week of work at my real job. Tired, excited, etc.

Probably means output on LETSGO will crater as things get going, but I’ve been so amped that I have energy to work on this as well.

Especially as I have the pieces necessary to implement Designing The Core Gameplay LoopDesigning The Core Gameplay Loop

Here’s the thing, that design is bad.

Over-engineered slop that doesn’t actually do the thing it’s supposed to.

I quite literally fell into Architecture Astronomy.

The main problem is the SetTonic phase needs a reference to the AudioPlatform that sends the OnAudioPlatformTriggered event.

My whole design is supposed to separate those objects.

Start With What’s Real

So I decided to work backwards from what currently exists.

My last big task for LETSGO was Refactor the Old Before Creating the NewRefactor the Old Before Creating the New, where I have my Audio Platform triggering an event when stepped on.

So starting with the AudioPlatform and the OnAudioPlatformTriggered delegate, I started to come up with a design to get it connected to the Set Tonic Phase as easily as possible.

	 *	AudioPlatform Broadcasts OnAudioPlatformTriggered
	 *	SetTonic Phase has references to three AudioPlatforms
	 *	On Activate()
	 *    -> SetTonic spawns the three AudioPlatforms in front of the Player
	 *		-> Binds to all OnAudioPlatformTriggered events
	 *	When OnAudioPlatformTriggered event received:
	 *		-> Destroy all Platform
	 *		-> Set Tonic in GameState

This decision removes the concept of Actions and Executors and all that shit.

Just spawn the things you need and do the action yourself, as God intended.

I may need some kind of Action executor in the future, but the current design is just… over engineered.

I’m not upset that I put all that work into designing this beautiful, well organized, over-engineered architecture design.

I needed some kind of plan to force the refactor of the Audio Platform.

But now I’m looking at it and am like “why don’t I just do the thing instead?”

So, feeling pretty good about that- if only because I’ve massively reduced the scope of this core gameplay loop thing.

FeelsBadMan: Refactoring Audio Platform Spawner

Those good feels hit a brick wall of “Oh I have yet more things to refactor”.

I have an Audio Platform Spawner blueprint that technically works, but needs to be updated to support spawning multiple platforms as a set:

image

This BP does a couple things:

  • Generate all the notes for all the scales
  • Add those notes to a NoteContainer
  • Call the Spawn Platform function every 1.0 seconds.

It’s this BP that is creating the Platforms and deciding the note of each platform:

I will need to update this so that:

  • Note Container is provided as a parameter outside the object, instead of generating its own NoteContainer.
  • Platforms are spawned next to each other in front of the player, instead of spawning every second
  • Propagate a Note selected from any platform up to the SetTonic phase object.

The intent is that when the SetTonic phase is active, three platforms will be spawned in front of the player, with 3 separate notes.

  • Stepping on any Platform will destroy all platforms
  • The Note is sent to the SetTonic phase object
  • SetTonic updates the “Tonic” note, setting the musical key the rest of the song will use.

So, first thing I need to do is make a AudioPlatformSpawner class, and update the BP parent class to it.

Got that done pretty quickly.

In order to spawn the actual platforms, I need a location for it to spawn to.

Currently I have a function that will get Vector Forward of the Camera and multiply by an arbitrary amount (500.0f).

That was all done in Blueprints, so I had to move that to code:

FTransform AAudioPlatformSpawner::GetCameraVectorForward() const
{
	// Assumes only a single local player in the world at index 0
	const APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
	const APlayerCameraManager* CameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(),0);

	const APawn* PlayerControlledPawn = PlayerController->GetPawn();
	const FVector PawnVector = PlayerControlledPawn->GetActorLocation();


	const FVector CameraForward = CameraManager->GetActorForwardVector();

	// Get the camera location and offset by some amount
	// Added to the player controlled pawn location
	// Gives you a world location where the player is looking
	const FVector Vector = FVector(
		(CameraForward.X * CameraVectorForwardOffsetAmount.X) + PawnVector.X,
		(CameraForward.Y * CameraVectorForwardOffsetAmount.Y) + PawnVector.Y,
		0
		);

	const FTransform VectorTransform = FTransform(Vector);
	return VectorTransform;
}

Now that I have that, I can use this function to get a root spawn location for the platforms SetTonic intends to spawn.