Working without Godot editor
Hi,
I sometimes hear from other gamedevs that they avoid engines because they prefer a "code first" approach.
Thus I'd like to present the way I work with Godot, using almost only code.
By that I mean this:
- I basically have a single empty main "scene"
- all nodes are fully defined and instantiated from code.
I'm using C#, and when defining node trees I make heavy use of extension methods, to make the nodes configuration more compact and I believe easier to read (at least for me - you will tell me :) )
To make this more concrete, here a (fake) sample of some UI code instantiating a few nodes:
```
// A pannel with a title and two buttons vertically aligned
public class MyTestPanel: PanelContainer
{
public MyTestPanel(string title) // Not a scene; I don't need parameterless constructor !
{
var vbox = new VBoxContainer()
.SetSeparator(15); // SetSeparator is an extension method, I let you guess what it does
new Label()
.WithTxt(title) // WithTxt is an extension method, which just does what you think and allows one-liners.
.SetFont(GobFont.SmallTitle) // another extension method
.SetFontColor(Colors.Red) // ...
.AsChildOf(vbox); // equivalent to vbox.Addchild(label). But this way I don't even need a variable name for this label
new DoStuffButton(OnButton1, "Button 1") // custom subclass of button which connects to the action I pass as parameter
.AsChildOf(vbox)
.SetLayoutAndFlags(LayoutPreset.TopRight); // aligning to the right
new DoStuffButton(OnButton2, "Exit ")
.AsChildOf(vbox)
.SetLayoutAndFlags(LayoutPreset.TopRight);
vbox.WrapInMarginsContainer(20) // puts vbox ina margin container and returns the margin container
.AsChildOf(this); // finally adding vbox to the scene
}
void OnButton1() => GD.Print("hello");
void OnButton2() => this.GetTree().Quit();
}
// empty placeholder scene for testing -- here I have a tscn file in the editor, refering to this script and containing nothing else. public class TestScene : Control { public TestScene() { this.SetTheme(); this.RectMinSize = new Vector2(1920, 1080);
new MyTestPanel("My test panel title") // class defined belows
.AsChildOf(this) // adding it to the tree
.SetLayoutAndFlags(LayoutPreset.Center); // and centering it
}
} ``` ( Result here: https://imgur.com/yv44cBI )
Of course this is just a dummy example; if you really want to see what kind of game I'm making this way (spoiler alert: with goblins and silly quest)you can have a look to my steam page (and we are between devs - I know you're not here for that; but I don't need to explain you why wishlisting would help me ;) )
Reasons why I mostly do not use the editor
Of course, you may wonder why I work this way. The main answer could be summarised as "personal preferences", but here are some more argumented reasons. Please note here that I'm not saying you should not use the editor!! These are just the reasons why I'm * personnally * more confortable working this way.
Scene refactoring Quite often, I will want to make a new "scene" which has strong similarities to another already defined scene.
With my code-only approach, a "scene" is only a subclass of some kind of node, it is quite easy to either extract a base abstract class and make two concrete subclasses, or to extract some components or function to reuse. When I tried working with the editor, my experience trying to refactor one scene in two similar subscenes was less good.
No magic strings
well, when I see code like this.GetNode("some_magic_name");
my eyes cry.
Indeed, with the structure of the scene defined in the editor, changes to this scructure will require to change the code; I find this just difficult to maintain.
the same thing goes with signals: for a custom signal, I can write something like:
public const string _signaWithMeaningVariableName = "whatever_string_I_dont_care";
this.Connect(_signaWithMeaningVariableName, targetNode, nameof(OnSomeEventMethod));
I am never scared about renaming the signal or a method, because I know that there's nothing in some config file somewhere relying on this exact name.
No parameter-less constructors Most of my node subclasses require some parameters to be correctly instanciated.
I much prefer having all these parameters directly in the constructor, and since these nodes are not editor defined scene I just don't need a parameterless constructor.
Generated world Another reason why I'm not so much using the editor is that my game content is for a large part procedurally generated. I don't have "predefined" characters, or locations, tilemap, ... to put in the editor, they are all procedurally generated from code.
That was my "initial" reason for trying to work without the editor.
But once I got used to this code-only approach, I used it also for part of the game where this argument is not really valid, such as the game ui. (no my UI is not procedurally generated, I'm not that crazy yet : ).
And what about the drawbacks?
Well, obviously once in a while I would prefer to just click in the editor to correct some missplaced ui component than having to guess the right number of pixels and recompile :) For me, this is not enough to outbalance the reasons above why I prefer skipping the editor; but once again that's just personal preferences.
But here we arrive to what I believe is a very strong point of Godot: I can mix working 99.9% from code and once in a while use the editor !! I actually use it a bit to quickly load a scene difficult to reach from the game (making an empty test scene) , and I use it also for animations and particles.
Making animations. Ok, disclaimer here; animations are not my strong point. But I still use a few animations for my characters and enemies, and here I did use the editor to define these animations.
What's tre trick if I don't have scenes?
The sub tree I wanted to animate is made of a few sprites, with a structure like this:
character root
-- foot (Node2d)
-- head (Node2d)
-- body (Node2d)
-- shield (Node2d)
-- weapon (Node2d)
-- AnimationPlayer
... plus tons of other subnodes irrelevant to the animation.
So I made a scene in the editor with an exact copy of sub tree above. In the editor I added some sprites below these node2ds to view what happens, defined the animations in the animation editor, and exported the animations as standalone resources files. After that, I can just load the animations from code on the code defined scene and it works. The only constraint for this to work is that I have to keep the same tree structure and node names in this "fake" scene and in my code. Since it is just one single scene, this was not really an issue.
To summarize, I really like the fact that Godot does not enforce using the editor, and is perfectly usable this way.
I hope this post will motivate "code first" to try godot, which I believe provides a lot of value even in this less usual workflow.