DEVLOG 2023-06-17


This week I managed to complete the core of prototype 2 which, as a reminder, is about testing the situation where the “view” of the game is in Godot and the “model” is in C++. This is allowed by GDExtensions which using C++ means using the godot-cpp library. I first upgraded to Godot 4.1-beta.2 and did the same for godot-cpp then proceeded to write the “view” of prototype 2 in Godot:

Here the blue cylinder is the player, the purple ones are the npcs, which currently move each turn.

This is a screenshot of the same C++ roguelike code running inside Godot with a GDExtension exposing the state to a GDScript file that simply read the data and put visual objects where they should be. Here is the equivalent (with a different world state) when using SFML as a view with essentially the same code (there are minor irrelevant differences):

When I press the space key in both cases, the whole scene is rebuilt and I see the state of the next turn.

The C++/Godot version is very simple but already pointed a lot of things I wasnt aware of that were important for future development.

But before getting to that, I wanted to mention that I dont think rebuilding the whole scene view is the best way to handle this kind of game visuually, for example you might not be able to see movements that way. The better way (that we used in Hard Glitch) is to have the turn update function also return events summarize the changes in historical order that lead to the new state of the world. Then the view code (here the GDScript) should intepret these events as a sequence of animated changes to the visual state. Ideally, the resulting visual state should be compared against the World’s state and the view should be corrected if they are not in sync. And ideally that correction would only happen while developing the game, but if you are for example in an early access model, it would help with new features that dont yet have graphics related to them, so that even if the transition described by an event doesnt prevent the game from being playable. Maybe a bit less understandable.

Another importnat point here is that there is the possibility to write the code that “drives” teh view in the c++ side, and implement the details in GDScript. For now I’m not sure yet what whould be the best approach in the context of MEGASTRUCTURES, but I’m thinking hard about it. One related thing that I didnt test yet is how to expose values which are not just ints and vectors of ints to Godot. If it’s trivial to do, I could be able to just expose the whole model’s world state to the engien and use GDSCript for all the rest. On the opposite side, I could write the abstract logic of what should appear where when and which animation should be played when in the C++ code of the GDExtension, then implement the details in GDScript and that would prevent me from having to add bindings every time I add ore change something in the model. I’m not totally sure if my reasoning is correct though, so I need to experiment a little more.

Now getting back to the things I learned, in particular the “bad” surprises:

  1. I mentionned in last devlog that Godot doesnt handle hot-reloading yet for GDExtensions. This is one of the most painful things because changing some C++ code means building your GDExtensions , installing it in the right location in the Godot project, then reloading the Godot project if open in the editor. Actually, on Windows you might be forced to close Godot first, then install the GDExtension, then open you project with the Godot editor (I dont need to do that for some reason and I would have expected that behavior too). I managed to make that whole process a bit less slow by setting up a build command in VSCdoe that runs build2‘s b install command, which implies building and installing, setting up the install so that it automatically put the files in the right place, so I need to launch that command then just reload the project. It’s still a bother though, but I have seen worse in my carreer as a C++ developer :tears-smiling: The good news is that there is ongoing work to solve that issue: part of the solution is to make sure Godot copies GDExtensions in a temporary file before using it, otherwise on Windows you get the locking issue; another part is to detect the changes of the GDExtensions and notify the user that they have to reload; and finally when it’s possible just hot-reload the changed GDExtension when that change is detected. Unfortunately it apparently will not be possible for that hot-reload to work for every single case, but they identified that some kind of C++ code, in particular C++ scripts that are basically GDSCripts but in C++, can be reloaded because they are automatically serializable. Anyway long story short, it will be possible as long as you do some C++ things and not others. However I suspect it will take many months for that solution to be implemented and test. I will probably experiment with it once available.

  2. When making a C++ equivalent of a GDSCript through GDExtension, that C++ script is actually working like if it was marked as @tool , which is a marker for GDScript to tell the editor to run that script also in the editor. This means that if you put a sprite moving in the C++ code, it will move in the game as specified, but also in the editor. The GDExtension example documentation does exactly that, and while it’s funny at first, it makes very hard to edit a sprite that moves… Beyond that, it also means that when using GDExtension you dont have an exact same behavior compared to GDSCript. Good news are that it is still workable as there is a way to detect if we are running in the editor or not, but it implies adding a lot of ifs just to handle that case; and there are plans, related to the solution fo the previous point, to clarify that a C++ script is actually supposed to behave like any other script. So same thing than previous point, I intend to try the solution but suspect it will take some time to be available.

  3. I found a surprising bug where if my GDEXtension uses {fmt} (aka libfmt) which is the initial implementation of what we now have in C++23 for printing and formatting, and try to print something regularly, there is a point where the game will just close. It is not clear if it is a crash but I suspect it is. I can live with that actually, as I should control logs to go into Godot’s logging system when using Godot, but it’s still weird and might be a symptom for a hidden problem. I’m still investigating this one.

  4. When your C++ crashes silently, your game’s return code is different than “success” (usually 0) and that can be used to determine that the game crashed, it didnt close cleanly. Unfortunately, when this happens to your game running in debugging mode through the Godot editor, the editor doesnt tell you anything, it doesnt check for the status of the executable. It unfortunately leads to silent closure of the game when this happens and you have no way to have a clue at what’s happening just by looking at Godot’s editors information. While it’s not a big problem, when you dont know that behavior it is very spooky to see your game suddunly close without any error report anywhere, as if it was normal. And once you know you take any game window closing as suspicious.

Now I need to try some more complicated things with this setup to get a better idea of the cost of developping even a small game with that setup. For example I didnt try yet to attempt debugging C++ code when running Godot (which implies running the debugger for the whole Godot executable instance). I also need to experiment with the various ways to setup the view layer in C++ and GDSCript as described previously.

Lot ongoing, lots of learning!

Side note: I changed the day of livestreaming to Wednesday evenings, see this post for details.

Leave a comment

Log in with itch.io to leave a comment.