Finding node dependencies when using the strategy pattern

The strategy pattern is one of my go to tools for building game features - you can use it to make things as modular as you need, and it makes it really easy to swap out pieces of behavior as you’re prototyping new ideas. This video - I’m sure has been shared many times here - covers a way to implement the strategy pattern in Godot using custom resources, but I’ve found that using a node hierarchy for choosing strategies is actually more useful in certain applications.

The video I just mentioned is great, and if you haven’t watched I’d highly recommend. But I’ve realized pretty quickly that it doesn’t fit as well for every use case of the strategy pattern. The problem in particular comes in when your strategy depends on data from another node in your scene. You can only export node members if it’s also a member of a node. So if your strategies are all subclasses of a resource, referencing members from external nodes is no longer as trivial as dragging them in from the editor.

Let’s take for example a project I’m currently working on as an exercise in game prototyping - a clone of Coffee Caravan. In this game you have interactable stations that each represent a part of the process of making coffee. E.g. “Grab beans from this sack” or “Grind into coffee grounds” or “brew coffee.” Each of these stations have some kind of an inventory, but what these inventories can accept depends on the kind of station it is - a perfect place for the strategy pattern.

For example, you can only put whole coffee beans back into the sack of beans - so its “inventory condition strategy” might be something like “only accept items with type” with an exported resource that can change what type of item it accepts. However, the coffee grinder and the coffee brewer are in some sense “crafting stations” - they have a recipe that accepts inputs and produces an output. So we might want a different behavior for these stations: “only accept crafting items” that references the input and output items from another node that represents a crafting component.

But how do you reference the crafting component from the inventory condition strategy? My default approach would be to put an export variable directly on the strategy so you can choose the crafting component on the strategy instance in the editor. However, this isn’t possible if your strategy is a resource, since resources can’t export node members.

What I’ve done instead that so far seems to work nicely is to make use of the node hierarchy: whatever node that wants to use a strategy will simply look for instances of that strategy in its children. In my example, I have an “InteractableInventory” component that’s responsible for translating player input into messages sent to the inventory component. When checking to see if the inventory can accept the item in the player’s hand, it will look through its children for nodes that implement an “InventoryAcceptCondition” interface (interfaces are most straightforward in C#, but they can be crudely implemented in gdscript). Now I can reference the crafting component on node that represent the strategy instance via an export variable.

it seems like you are burning energy trying to enforce the use of the strategy pattern. The quoted problem can be easily solved in a bunch of different ways. But you seem to be making it more difficult by requiring that a certain abstract method be used.

How do you know how much energy I’m burning? The solution I came up with really isn’t difficult at all - so much so I came up with it even before learning how to use custom resources to implement the pattern. I started burning energy when I tried refactoring the strategies into custom resources and ran into problems finding my dependencies that were previously set up using exports - hence why I made this post to share my findings

I don’t know why you think I’m trying to “enforce” a design pattern here. I saw a place where it felt applicable and used it. That’s how design patterns are meant to be used… Mind you, the implementation didn’t take long at all and now it’s super easy to customize inventory conditions on a per-station basis. I think the strategy pattern makes a lot of sense here actually

I meant no offense, friend. I didn’t read the post in depth. I just skimmed it

The “strategy pattern” is honestly just a fluffy computer sciencey name for a practice that to my understanding is pretty common in the industry. I learned it during my time working in Unreal as a gameplay engineer at an AA indie studio and have found that it’s an excellent tool to expose customization points to designers.

The workflow there was often to make some kind of system in C++, then expose “blueprintable” classes that the designer could customize. This was especially useful since the “blueprintable” strategies were often simple enough code that a designer without much programming experience could implement their own. As a solo dev now, I’m both the programmer and the designer, but if anything that makes it all the more transparent of how useful of a tool the strategy pattern is for iterating on features.

1 Like