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.