Home

2024

Worklog

LETSGO Game

Coding Without a Map

Coding Without a Map

Date
December 16, 2024
Hours
1.5
Tags
UnrealCodeC++LETSGO

There are consequences of having loose design goals for the next feature of my game.

I’m taking the lessons of Avoiding Overdesign Traps to heart.

I have a goal, a direction, but not a clear path forward.

I’m coding without a map.

One of the consequences is I don’t have a clear idea of how I’m going to accomplish the design goals laid out in 🙉From Audio Chaos to Actual Music

But I know there will be “some kind of object managing ‘song sections’”.

So, I made some kind of object managing song sections:

This isn’t a perfect representation of the object I intend to make, and only represents Intro section, leaving the rest to be built later.

It’s a vertical slice of how a Song Section object could be managed.

This approach has already paid off- I now have a Song Section object, and I have a place where it’s initialized.

Iterating and improving on what exists is easier than creating the perfect object on the first try.

Modifying the Strategy Pattern

Even more beneficial is that it has revealed the big sticking point for this feature.

I am using the Strategy Pattern to represent different musical strategies:

class LETSGO_API IMusicStrategy
{
	GENERATED_BODY()

public:
	virtual FInstrumentSchedule GenerateInstrumentSchedule(FComposerData& CurrentComposerData, const AMusicComposerState* State, const int StartAtBar) = 0;

	virtual float GetStrategyAppropriateness(FComposerData& CurrentComposerData, const AMusicComposerState* State) = 0;

	virtual float GetInstrumentAppropriateness(FComposerData& CurrentComposerData, const AMusicComposerState* State) = 0;
};

It allows me to use a common IMusicStrategy* interface object to generate music, leaving the “how” that music is generated to the specific strategy.

It lets me focus on the output of the GenerateInstrumentSchedule function, rather than the implementation.

This is great, unless you need to modify the signature for GenerateInstrumentSchedule.

If I wanted to pass a new object into it, or change what it returns, I have to update every Strategy that’s currently implemented.

And that’s the sticking point for this feature, I think. I’m pretty sure I’ll have to update this strategy.

  • I have a concept of “Musical Ideas” I wish consumed by the Strategy, although can be in ComposerState so no changes needed there.
  • Each Song Section contains a set of Musical Strategies and an associated appropriateness for each strategy- meaning GetStrategyAppropriateness will have to be updated.

Vertical Slices Cut to the Bone

There is only one defined Song Section representing the Intro.

It’s revealed changes to an interface that will force me to update each implementation of that interface.

Thankfully, there’s only two strategies thus far.

My last feature was to create Musical Strategies- and I only implemented a vertical slice.

Because I did the bare minimum then, it makes refactoring it now easier.

There’s a time to go wide with a feature, and a time to go deep.

When you’re coding without a map, it’s best not to cast too wide a net.