I am currently experimenting with a prototype for a MOBA style game using Godot.
I am struggling to figure out a way to manage the characters and their skills.
All characters will have similar attributes (Name, health, run speed, strength and so on). However, the skills will be different for all characters (although some will be pretty similar, for instance projectile based skills would have things like: distance, speed, texture/vfx) that should be configurable but allow for re-usable behaviors when possible.
I am not sure how to build something that will allow for simple maintenance/programming.
I tried to use resources for the skills and characters. However, it looks like resources might not be the way to go since I can't seem to have different behavior/scripts for each resource instance.
I.E: Skill Resource
Name: Frost Arrow Speed: 20 Texture: frostarrow.png
However, I don't think I can attach code to it, or if so, I haven't found out how.
I also tried with a PackedScene. While I can have custom code using a scene, I can't figure out how to access the skill name from the packed scene.
And then, for the Character. I think for this one, I can use a Resource. I would have a Name, Sprites/3D model and so on. I would like to have a way to assign skills to my characters.
And from my player controller, be able to access those skills to display them on screen and call them when needed.
For the purposes of this answer:
The general answer is that will use resources. To be more specific you will use custom resources plus scenes.
I'll start with the scene stack because is the clearer part of this. These are all scenes that exist in the game source:
Now, if you want to change how it behaves you need a different agent. If you want to change how it looks you want a different prop.
So there can be multiple things with the same behavior but different appearance (given by the prop), and there can be multiple things with the same appearance but different behavior (given by the agent).
However, what I described above exist in the scene tree. Things do not always exist in the scene tree (sometimes they exist in menus or inventory-ish containers). There you need custom resources.
There will be two kind of custom resource classes, and I'll get back to that... What I say here can apply to both.
The custom resource classes:
PackedScene
s properties, they can instantiate.PackedScene
s, which also sets a property of the instance to the custom resource instance itself (this is a form of dependency injection and inversion of control).So there can be multiple things with the same behavior but different configuration (given by the custom resource).
Sometimes the custom resource will reference multiple PackedScene
s. Here are a few cases:
PackedScene
to instantiate as Prop/Skin inside of the Character/Agent.PackedScene
to instantiate a weapon when equipped, than when dropped in the world.It is better if you don't think the scene is the thing. The custom resource is the thing, and the scene is just a wrapper you use when it needs to exist in the scene tree... And you might use different wrappers for different occasions.
Of course, if some of the wrappers are generic, you don't need to have a property you configure in the custom resource. Similarly, the custom resources do not need to have methods to instantiate every kind of wrapper scene... Just do the ones you actually need.
In practice you will likely need two kinds of custom resource classes:
For example one general resource might represent a weapon model, and it has stuff like ammo capacity. But there can be multiple weapons of the same model in the game. The specific resource represent one of those weapons, and it has stuff like the amount of ammo it currently has.
You will want the general resource to have the PackedScene
of the Agent/Character, because they all behave the same. But the specific resource to have the PackedScene
of the Prop/Skin because each one might be customized to look different.
Also, the custom resource you want to inject into the scene instance is the specific resource. This way the scene has access to all the data (since the specific resource has a reference to the general resource), and it can take control of specific data (e.g. it will update its ammo count). You proably don't want to change the data of the general resource in runtime.
Furthermore, the general resources would probably exist as resource files in the source of the game. But the specific are created in runtime (and you might save their data when saving the game, and of course recreate them when loading the game). In fact, you might want to include a method in the general resource script to create instances of the specific resource.