The Skills, unlike attributes, are essentially instructions on how to create a skill and which specific arguments they take.

Before going into their creation, we need to take a detour on understanding how Godot works for some of this makes sense.

Essentially, Godot has Scenes and Nodes. Games are built out of Scenes and Scenes are built out of Nodes.

Basic Example Scene

This is a basic World Scene. The root node of this Scene is also called World. It has child nodes “Player” and “Background”. (These child nodes can also have their own child nodes, and you can basically nest them quite a bit).

Notice the video player icon near the Player node. This means that it is a scene of its own that we’re treating as node in the current scene. If we were to click on the icon, we would be taken to the Player scene that looks something like this:

Player Scene

This is the Player scene with a Kinematic Body (defines movement and gravity), CollisionShape2D (defines how it interacts with objects in the World) and a Sprite (for its avatar).

Godot also has a SceneTree. This keeps track of which scene is currently active, and can query different parts of it (will be coming back to this soon)

This should hopefully have been enough of a detour for you to get familler with the general structure of Godot if you aren’t already.

Creating Skill Nodes

Creating Skill Nodes

Godot has an Observer pattern they call “Signals”, and you can use them by writing:

emitter.connect(“SIGNAL”, observer/target, “the_function_executed”)

e.g

Monster.connect(“SUMMONED”, Trap_Hole, “Destroy_Summoned Monster”)

When the Monster is summoned, it sends the signal that it was Summoned. Trap Hole then executes “Destroy_Summoned_Monster” on that monster. I’d have to connect all interested cards to each instance of Monster that was summoned. I know early on that this simply was not feasible.

I went so far as to create an Signal Manager which connected to all of the interested cards, while just having the Card’s execute method pass in itself, and delegate its operations to the Signal Manager.

I’ve dropped that recently in favor of groups.

In Godot, you have groups. Which (I assume) are not too unlike Unity’s Tags. You can add a Node to as many groups as you like, and there are a few helper functions available from the tree on working with groups. For example:

Calling the execute method on all cards in the OnSummon group

This function allows you to call the execute method on all skills in the “OnSummon” group. The default for these group calls are to happen during idle, after the current methods have finished executing. Depending on when you want to handle them, you can call get_tree().call_group_flags(2, group, method) to handle them immediately before returning to the method that called them. You can also pass arguments after the method name if required.

You could alternatively add a “push” method to skills that would add the called skills to a “stack” group (or Stack Array) like Magic: The Gathering. Then after all of the skills been pushed, you can ask the Stack Manager to handle resolution order.

For the time being, lets assume Trap Hole is executing immediately.

Keep in mind, we’re not calling “execute” on Trap Hole but rather “execute” on a child skill node of Trap hole.

In this example, Trap Hole only has one Component called “Destroy”. It takes the summoned monster as an argument and adds it to its owner Discard (using some built in helper functions for moving nodes around a Scene)

Components are added similarly to how Skills are added to Cards.

Adding a Component to a Skill

Each Component is an Object of a Class (all of which extend from a Base Component Class)

The above example is a “Draw” component. If we were for example to design a card like “Graceful Charity”:

Using Yugioh Cards because they’re complicated

This would consist of two Components: The first would be a “Draw” Component that draws 3 cards from the Deck. The second would be a “Discard” Component that takes an amount of 2. You could argue for a third intermediate component that “targets” or “chooses” card but that is actually particularly complicated over a turn-based multiplayer game and probably deserves an article of its own.

“Skills” can also be used to check against status effects. For example, “Frozen” Creatures in Hearthstone can’t attack. Frozen/Freeze would be two skills.

First we would have a card that applies Frozen to a target. All this really means is that we add a skill to the target. The Skill would be added to the group “OnAttack” and we would add a “Frozen” component to the skill.

When a card attacks, we call the execute method on the “OnAttack” group, passing in the Card (or maybe an attack command object), the Frozen Component checks if the id of the attacking card is equal to the id of the Frozen card, if so the Frozen Component flicks a “denied” boolean on the Card to true, so when return back to the card’s attack execution, it checks if it has been denied, and if so it stops. (Then right at the end of the attack method the denied boolean is flipped back to false).