I recently built a Command Pattern system to allow non-programmers to easily create in-game events via the Godot inspector. While this is a Showcase rather than a full tutorial, I wanted to share the implementation to hopefully inspire someone!
I did my best to keep explanations very simple, this is mostly aimed at newcomers to Godot and game development overall. So here we go!
I was asked / hired to port a game from RPGMaker to Godot. Luckily my client didn’t require every single RPGMaker feature to be present, in fact, they only really needed a couple of things. One of which was a simple way to edit maps (scenes) AND to be able to create events in the game without having to write any code. I’ve always enjoyed creating development tools that make dev work easier overall, sometimes I find it even more enjoyable than actually using said tools!
After thinking about the implementation, I’ve quickly decided to go with the Command Pattern for it.
That book explains the pattern really well, but I noticed that many newcomers struggle when it comes to actually implementing these ideas into their own game. While this is C#, the general idea of it can easily be translated into GDScript too, and if you believe this feature could benefit your game in any way, feel free to try and implement it in GDScript based on the C# code! It might even be easier to do so since C# requires a bit more boilerplate for simple things. Again, this isn’t meant to read like a tutorial, I will mostly just be showing off how I achieved things.
At its core, this pattern is just a single abstract class with a single function that we call when we want said command or “action” to execute.
For Godot specifically, I’ve decided to make this abstract class inherit Resource, the simple reason is that they’re serializable, reusable across scenes, and show up very cleanly in the inspector, which is the main point my client needed. Requires no programming knowledge, just a few clicks.
[GlobalClass]
public abstract partial class TriggerAction : Resource
{
public abstract void Execute(Node caller, Node target = null);
}
Once we have an abstract class, we can start building on top of it!
The very first thing I tried was a very simple debug action, to print something to the console.
[GlobalClass]
public partial class DebugPrintAction : TriggerAction
{
[Export] private string _printWhat;
public override void Execute(Node caller, Node target = null)
{
GD.Print(_printWhat);
}
}
So why is any of this useful?
Simple, by doing this, we can implement something like a TriggerArea! These are Area2Ds that will do a certain action as soon as the player walks through them.
public partial class TriggerArea : Area2D
{
[Export] public Array<TriggerAction> Actions;
[Export] public bool OneShot = true;
private bool _hasBeenActivated = false;
public override void _Ready()
{
base._Ready();
BodyEntered += OnBodyEntered;
}
public override void _ExitTree()
{
BodyEntered -= OnBodyEntered;
base._ExitTree();
}
private void OnBodyEntered(Node2D body)
{
if (OneShot && _hasBeenActivated)
{
return;
}
if (body is not Player player)
{
return;
}
ExecuteActions(player);
_hasBeenActivated = true;
}
private void ExecuteActions(Player player)
{
// This is the core of the pattern! We loop through every resource
// in the inspector array and fire them off all at once.
foreach (TriggerAction action in Actions)
{
action.Execute(this, player);
}
}
}
Doing this gives you a very easy to use inspect menu, that looks and works like this:
This way, the moment this triggers, all the actions we added here will execute all at once. In this case, it will simply print whatever we wanted in the console.
Of course, there’s an inherent limitation when it comes to Resources, which is the fact that they cannot have knowledge of any given scene.
What this means is that we can’t just drag and drop a specific node we have in the scene to an Action we created, because these Resources don’t inherit Node. They have no knowledge of the scene tree.
To get around this limitation, I’ve created two base classes that still make it possible to interact with nodes in a given scene, and this is why every single TriggerAction requires the caller node to be passed, so I can still get to the scene tree if needed.
One of these base classes will use the Groups feature of Godot.
public abstract partial class NodeGroupBaseAction : TriggerAction
{
[Export] private StringName _groupToUse;
public override void Execute(Node caller, Node target = null)
{
if (_groupToUse == null)
{
GD.PushWarning("Node group was null! Please check your action!");
return;
}
if (_groupToUse.IsEmpty)
{
GD.PushWarning("Node group name was empty! Please check your action!");
return;
}
foreach (Node node in caller.GetTree().GetNodesInGroup(_groupToUse))
{
ApplyAction(node);
}
}
protected abstract void ApplyAction(Node node);
}
This allows us to give the Trigger a name for a group. This can be serializable very easily, and we only need to worry about actually connecting the dots during runtime. What this looks like in the inspector:
And for that specific Light2DToggleAction, all I had to do was this:
[GlobalClass]
public partial class Light2DToggleAction : NodeGroupBaseAction
{
protected override void ApplyAction(Node node)
{
if (node is not Light2D light)
{
GD.PushWarning("Node was not a Light2D! Please check your groups!");
return;
}
light.Enabled = !light.Enabled;
}
}
And as you saw in the NodeGroupBaseAction code, we call the ApplyAction function for every single item in the group.
The other way to implement with something specific on the scene tree is using Godot’s Scene Unique Nodes!
This is similar to the group one, except we mark a node so we can access it by its unique name, and in code, we can simply do this:
public abstract partial class UniqueNameBaseAction : TriggerAction
{
[Export] private StringName _nodeToUse;
public override void Execute(Node caller, Node target = null)
{
if (_nodeToUse == null)
{
GD.PushWarning("Unique name was empty for Node! Please check your action!");
return;
}
if (_nodeToUse.IsEmpty)
{
GD.PushWarning("Unique name was empty for Node! Please check your action!");
return;
}
Node node = caller.GetNodeOrNull($"%{_nodeToUse}")
?? caller.GetTree().CurrentScene?.GetNodeOrNull($"%{_nodeToUse}");
if (node == null)
{
GD.PushWarning($"Node with unique name '%{_nodeToUse}' was not found via caller or CurrentScene!");
return;
}
ApplyAction(node);
}
protected abstract void ApplyAction(Node node);
}
For this one I have a bit of a fallback, since finding the specific node might not always be immediately obvious, and I have a lot of null checking to make sure we did find the specific node we want to interact with.
So far the only action I made using this class is an action that can remove a specific node, see:
[GlobalClass]
public partial class RemoveNodeAction : UniqueNameBaseAction
{
protected override void ApplyAction(Node node)
{
node?.QueueFree();
}
}
Using Resources also mean that it’s super easy to change the actions while the game is running, so it’s very easy to experiment and change something!
This is only a very few and easy examples, but of course this can be expanded more and more, I currently have the following actions created:
Hopefully this can inspire someone or give ideas on how this pattern can be used in Godot!
If you have any ideas or improvements, or any questions about the implementation, feel free to comment!




