Switching to Godot and a Genre Choice

Over the past month, I decided to tackle procedurally-generating the world, and have been working on implementing the Wave Function Collapse algorithm. It took several nights to get it working in Game Maker Studio, and I finally ironed out most of the issues I was having. I realized a few things in the process:

  1. I don’t like the GML
  2. Performance will likely be an issue in Game Maker
  3. I don’t think I’ll need Tiled at all since I’m switching to procedural generation
  4. I don’t need much in the way of engine assisted tools, like Game Maker’s level-editor and the sprite editor
  5. I use VIM exclusively in my day job and Game Maker’s native editor doesn’t support it. I was constantly having to remember different key combinations to do things, which really slowed things down.
  6. I don’t like the way Game Maker handles tabs. Another option is GMEdit , but there is no VIM support for it that I’m aware of.

Moving to Godot

All of these issues got me looking at other game frameworks. I looked at libGDX a bit, Construct 3, and settled on Godot, mostly at the recommendation of other devs and the ability to use C# and C++. Godot is open source and really has been a dream to setup and work with so far. It’s very intuitive and offers more mature languages (namely C# and C++). Finally a real object-oriented language (who needs OO when making a complex game??). And I can always drop down to C++ for things that need to be more performant. The documentation is also clearly written and organized.

So Godot it is. I was able to rewrite the GML Wave Function Collapse in C# in a couple nights. I’m still not entirely satisfied with the results of the algorithm. But it runs considerably faster in C#. I use Visual Studio Code to write the C# parts, and my experience of setting that all up was seamless. I downloaded the DotNET SDK and got C# code talking with Godot without any issues very quickly. I was expecting a lot of hassles with it on my old Macbook, but everything worked right out of the box. The C# IntelliSense is really useful as well.

Tweaking WFC

I’m not 100% my implementation is correct – I think I may have a key misunderstanding of the algorithm as my results do not seem as nice as some of the implementations I’ve seen, but I need to dive further into it. Right now it’s very random which is good, but I’d like some more order to the grouping of terrain types (like grass in bigger sections and water in more of a lake formation).

Here are a few examples of my WFC implementation.

Initial Attempt in Game Maker Studio:

Here is WFC running in Godot:

Another version with corner tiles added:

I haven’t done any art in the past 2 weeks, so am eager to do some creative things soon, but there are things I want to work out in Godot, such as figuring out the optimal resolution, different screen sizes, and I want to flesh out a better implementation of WFC. After that, I can start adding objects to the map and work on a basic UI.

—————————————–UPDATE————————————————–

I figured out the problem with WFC. Each tile type has a weight assigned that affects the probability of whether that particular tile is chosen by the algorithm. So a GRASS tile would be weighted 10, a WATER tile 3, and a DIRT tile 5. This allows you to control how often GRASS tiles appear vs DIRT and others. The following function chooses a tile index randomly based on these weights:

private static int RandomWeightedChoice(List<int> _weights)
{
  Random random = new();
  int totalWeight = _weights.Sum();
  int randomNumber = random.Next(totalWeight);
  int cumulativeWeight = 0;

  for (int i = 0; i < _weights.Count; i++) {
    cumulativeWeight += _weights[i];
    if (randomNumber < cumulativeWeight) {
      return i;
    }
  }
}

The weights did not appear to be affecting the result much and I was scratching my head trying to understand why. Out of curiosity, I bumped the GRASS tile up to 100 and re-ran the algorithm, and what do you know, more grass this time. I realized that the thing I was misunderstanding was that the weights were too low, in general. The smaller the sum of the weights, the less chance of some tile types being chosen more often than the others. For instance, if you set the Grass to 3, Water to 1, and Dirt to 1, the sum of these is 5, and it will randomly choose a number between 0 and 5. GRASS is more likely in this case, but not so much more likely. However, set GRASS to 100, and now the sum is 102, and for a hundred of those, GRASS is now MUCH more likely to be chosen. Maybe this is common sense, but I admittedly did not do well in probability in college. But it makes sense now!

With this knowledge, I adjusted the weights a bit more and came up with this:

I’m looking at possibly using Perlin Noise to modulate the weights, so that certain areas of the map are more likely to contain specific tile types. This seems somewhat straightforward, but I haven’t thought it through entirely. My ultimate goal though is to make this generation configurable by the player prior to starting the game.

Share on social media

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts