19 July 2024

Course "Unity C# Mobile Game Development: Make 3 Games From Scratch" by GameDevTV

The course I took on game development in Godot for mobile platforms left me wanting more. So I decided to take the equivalent course for Unity and compare the two platforms. Specifically, I chose another course from GameDevTV: "Unity C# Mobile Game Development: Make 3 Games From Scratch." In this case, I bought it on Udemy, where I already have other courses.

It is based on developing three projects: a sort of Angry Birds, a racing game, and an Asteroids game. All are very simple but cover the basics: physics configuration, camera handling, and a lot, really a lot, of UI configuration.

  • Regarding mobile-specific topics, the course explains:
  • Editor setup to simulate mobile platforms.
  • Compilation for Android and iOS.
  • Input management through touchscreens, including multi-touch inputs.
  • Notifications.
  • Ads.
  • In-app purchases.

Overall, it's good, but there are several points where it clearly needs an update. The most glaring issue is that the instructor himself acknowledges some of these points. For example, when it comes to Ads, Unity offers two options. The instructor admits that the classic option is already obsolete and that Unity's development is moving towards the second option, but guess which one he explains in the end? Exactly, the one he acknowledged as obsolete.

There are also several moments when Unity has evolved, and the components used in the class either do not appear or do not behave exactly as shown. When that happens and you get stuck, I recommend checking the comments section of the particular class. You'll see it's full of students asking questions, but the instructor never responds. Even so, it must be acknowledged that GameDevTV assigns associate instructors to answer questions, although, in most cases, their answers don't provide much help. In the end, the best tips come from other students' comments. I have also left some contributions, hoping they help someone.

As a platform, Unity is much more mature for making games and monetizing them on mobile platforms than Godot. It is evident that they have components for everything, although I did miss the greater clarity of Godot and, above all, its faster development speed. It drives me crazy every time I modify a Unity script, switch to the editor to test it, and have to spend 5 or 6 seconds staring at the screen while Unity does one of its famous "domain reloads." In comparison, the workflow in Godot is much more agile, with practically instant executions (even using C#), so it doesn't feel as tedious. In my opinion, if you want to make a mobile game intending to profit from ads or in-app purchases, Unity is the best option, although I wouldn't rule out Godot for prototyping, much less for PC games (for which I believe Godot is very well-suited).

In conclusion: the course is good and worth it. It allowed me to solidify concepts, some of which the Godot course had already introduced to me, and it finally helped me understand how to configure UIs in Unity (it's hard to believe, but I hadn't quite grasped it until now). However, be aware that some content is outdated and won't work as expected. So, if you get stuck, it's best to check the comments section because you might discover that the issue isn't your code. With that caveat in mind, I think it's a course that can be very beneficial.

12 July 2024

Course "Master Mobile Game Development with Godot 4: From Concept to App Stores" by GameDev.TV

I'm continuing with the courses included in the latest Humble Bundle pack that I bought, which features courses from GameDev.TV. This time, I'm taking the "Master Mobile Game Development with Godot 4: From Concept to App Stores" course. You can find it on both GameDev.TV and Udemy. Buying the course on one platform or the other will depend on your preferences and which one offers a better discount at a given time. In the end, the course is exactly the same.   

It is focused on game programming for Android or iOS mobile platforms.

The course is supposed to be at an intermediate level, although the first two sections of lessons, where you build a very basic platform game without touching a mobile device, work very well as an introduction (or a refresher, if that's your case) to all the 2D aspects of Godot.

The third section dives into the more specific parts of the course and explains how to set up Godot to generate installable packages for Android and iOS. Regarding mobile gameplay, it covers how to use the device's accelerometer and how to detect and correct screen scaling issues.

I found the fourth and fifth sections quite tedious because they focus on setting up the entire UI and adding functionality to the menu buttons. It's useful if you haven't seen this topic for Godot before, but if you're already familiar with it, these two sections can feel long. Even so, I don't recommend skipping them because what follows relies heavily on the UI set up in this part.

The sixth section is the most interesting because it focuses on how to interact with the Google Play API to offer in-game purchases. It uses Godot's official plugin for this. This section is quite complex and has a couple of points that are not well explained, not due to negligence on the author's part, but because these issues seem to only occur when using Google Play for the first time. Once resolved, they don't happen again, and you forget about them. Since the author has already worked on several Google Play projects, he didn't encounter these issues, and his lesson proceeds smoothly, not realizing that first-timers might face more difficulties. For example, the explanation on how to register as a developer on Google Play seemed brief. There's also a lesson, 6.12 "Acknowledging," where there's an entire thread of comments from people who faced the same issue, without the author stepping in to help. After much searching online, I managed to solve my problem and shared my solution in the comments. The solution was to unlock developer mode, not on the mobile device (which is explained in the course), but in the Play Store app itself. I suspect the author didn't mention this because it's something you unlock at the beginning and then forget about... until you face the issue again. In an introductory course like this, it's a mistake not to mention it.

The seventh section is about publishing the application, but compared to everything else, it is very simple.

The author uses GDScript, but I was translating it to Godot C# on the fly without any issues until the in-game purchases part, which forced me to practice how to call a component in GDScript (the plugin) from C#. Nothing complex. Once you realize that it's about loading the plugin as a GodotObject and then calling its internal methods with the Call() method, everything becomes very straightforward. You just have to keep in mind that the plugin returns Godot's own types, like Array or Dictionary, which are not exactly the same as C#'s native types. In this case, I had to analyze the plugin's source code (in Java) to understand it. For the author, all these type issues were transparent due to GDScript's dynamic typing.

The author explains things well. He is Turkish, but his English is one of the clearest I've heard in a course, and if listening to English is a problem for you, there are subtitles, which are quite accurate based on the few times I've needed to use them. I also found the author's programming practices to be "healthy," resulting in a well-structured program. The principle of "downstream you call methods on references, while upstream you return signals" is something I had already suspected from my own experience, but this is the first time I've heard it explicitly mentioned, and it's a design principle I liked a lot.

Overall, despite its small flaws, the course is generally good and interesting. I recommend it.

08 June 2024

How to implement health bars for characters in Godot games

It is very common for game characters to have progress bars, at their feet or above their heads, to show how much life they have left. 

Godot has two ideal nodes for this: ProgressBar and TextureProgressBar. The first one has everything we might need for a basic bar. The second node is an evolution of the first, allowing for a more attractive visual appearance using textures instead of plain colors. In this tutorial, we will focus on ProgressBar; once you control this, using the TextureProgressBar node is relatively simple.

In Godot2D, adding a progress bar to your character is very simple. Just add the ProgressBar node to the character's scene hierarchy and then resize and position the bar using its visual handles.

From there, you only need to configure the visual appearance of the bar and implement its script, as we will see later.

However, adding a life bar to a 3D game character is not so straightforward. The problem is that ProgressBar is a 2D node and cannot be directly added to a 3D game. In fact, if you try to add the node to a 3D game character, as we did with the 2D case, you will see that the scene editor switches to the 2D tab and does not allow you to place the node as part of your 3D scene.

The trick is to use a node we already used in the article about minimaps in Godot: the SubViewport node. This node creates an independent viewing area in a region of the screen. In the case of minimaps, we used it to show the top-down camera's view, while the rest of the screen continued showing what the main camera saw. In this case, the node's role will be to display a 2D element in a region of a 3D game screen.

For minimaps, the trick worked by making the Camera3D node a child of the SubViewport and placing this in the desired screen region using a SubViewportContainer node.

For life bars, it's done similarly: you place the ProgressBar node as a child of the SubViewport, but in this case, you can't use the SubViewportContainer node because it places things in a specific screen position and not relatively to a character, so they move with it through the scene. For this, we can use a Sprite3D node. This node can be positioned relatively to a character, as part of its scene hierarchy. So, we will make the SubViewport and ProgressBar nodes children of the Sprite3D.

Once finished, the life bar will still not be visible. This is because we need to configure the Sprite3D to show the life bar. In other words, we need to configure the Sprite3D to display the image rendered by the SubViewport. To do this, find the Texture property of the Sprite3D in the inspector. When you find it, it will be empty, so you need to create a New ViewportTexture in it and select our SubViewport in the popup window that appears. From that moment on, the bar will be visible within our character's scene.

Normally, beyond tinkering for testing, you will want to concentrate all the bar nodes in their own scene, so you can reuse it for different characters. That’s what I did and what is shown in the previous screenshot.

That’s the hardest part of configuring life bars. The next step is to configure the visual appearance of the bar. We will set its size using the Size property of the SubViewport. I usually disable the Show Percentage property of the ProgressBar to not show the percentage. As for the bar colors, we need to look for the Themes Overrides section in the ProgressBar inspector. There, we need to expand another section called Styles. It has two parts: Background and Fill. The first is for defining the visual appearance of the bar’s background, and the second for the main bar. The simplest way is to assign those properties with StyleBoxFlat resources and edit their BG Color property with the desired colors. For example, we could set the background BG Color to a color with Alpha 0, making it completely transparent, and the bar color to blue.

What remains is the logic to update the bar’s values as the character's values change.

The three basic properties of a ProgressBar are: MaxValue, MinValue, and Value. The first two are usually set at the beginning, for example in the _Ready() method, and define the maximum and minimum values the bar will cover. Meanwhile, the Value property is the one we will update throughout the game to make the ProgressBar update the bar length based on the Value relative to the minimum and maximum.

An approach I often follow is to create a C# script for the Sprite3D, with a reference to the ProgressBar:

From that reference, I create properties for the maximum, minimum, and current values, so when these values are modified from outside the script, their equivalents in the ProgressBar are also updated. For example, for the maximum value:

The properties for the minimum and current values are almost identical.

I exported these properties to set initial values from the inspector. For the configured inspector values to apply to the progress bar at the beginning of the game, we will use the _Ready() method:

Once the game starts, the properties will update the ProgressBar as the reference to it will no longer be null.

The remaining task is to provide a means to update the CurrentValue property and, with it, the bar. You can do this in many ways, for example, by having scripts that will update the bar hold a reference to the bar script and manipulate the CurrentValue property through it. This is a valid approach but increases coupling by requiring a direct reference between objects.

Another option, reducing coupling, is to make scripts that modify the life level emit signals (Godot's version of events) whenever a change occurs and have the bar subscribe to these signals. In my example, I followed this approach and included a handler in the bar script to respond to such signals:

Then, I subscribed that handler to the signal emitted by the character whenever it takes damage:

In my example, the damage signal is emitted by the CharacterLifeManager.cs script, which defines the signal as follows:

The previous signal is emitted from line 46 of the ApplyDamage() method of the aforementioned script, which is called whenever the character takes a hit from its opponents:

Using deltas, instead of absolute values, in the OnCurrentValueChanged() handler allows subscribing it not only to damage signals (which transmit negative deltas) but also to healing signals (whose deltas are positive). In this case, the script that manages healing, when the player picks up a potion, emits a signal with a positive delta to which we can subscribe just as we did with the damage signal:

The definition and launch of the signal are very similar to the damage signal, so I won't go over it here.

By relying on signals, we have reduced coupling between components and achieved a highly reusable bar that we can apply to any game element as long as it emits signals with the increment value (whether positive or negative) whenever a monitored value changes. This way, we can reuse this life bar we implemented here with other components to display values that don’t have to be life, such as ammo, karma, or armor level.

This concludes the article; I hope you liked it. If the explanations and screenshots were not enough, you can download the example project I used from my DungeonRPG repository on GitHub. I used as a base the mini-game I made following the GameDevTV course "Godot 4 C# Action Adventure: Build your own 2.5D RPG," which I highly recommend. The course does not cover life bars, but the mini-game it implements is an excellent base for learning how to create them.

01 June 2024

Course "Godot 4 Shaders: Craft Stunning Visuals" by GameDev.TV

 I am still working through the courses I bought in the Humble Bundle pack, and this time it’s "Godot 4 Shaders: Craft Stunning Visuals" from GameDevTV. Unlike other GameDevTV courses, this one is not on Udemy, so you’ll have to watch it on the GameDevTV platform. This comes with a couple of drawbacks: you don’t have English subtitles and you can’t speed up the video. Fortunately, the course instructor has good pronunciation, so everything is understandable, and he speaks at a good pace, so there’s no need to speed it up.

The course lasts about 5 hours and focuses on giving you an initial dive into shaders to dispel any fears of delving deeper on your own. It is structured into three parts:

  • Shader fundamentals.
  • 2D Shaders, focused on creating common effects in this type of game: flashes, monochrome transitions, dissolves, masking, scrolling, and distortions.
  • 3D Shaders, aimed at setting the basic properties of albedo, metallic, roughness, and normal. Although it doesn’t go very deep, it concludes with a tutorial on creating a water effect.

I had taken shader courses in Unity before, but this was my first one focused on Godot, and I must say I liked it a lot. In the shader courses I had taken for Unity, I would follow the tutorial steps, but I felt like I wasn’t really understanding the general concepts. Basically, I was repeating actions without really knowing why I was doing them. Fortunately, this was the first course where I didn’t feel that way. The instructor makes an effort to explain more basic concepts, such as fragment or vertex phases, or what UV coordinates are, and this effort is greatly appreciated. For the first time, I understood why I was doing things.

Another pleasant surprise was that I didn’t mind that the instructor did not use Godot’s visual shaders and focused on code shaders instead. Initially, I thought this might make the course more complicated, but now I think it actually simplified things quite a bit. If you’ve programmed in C#, the language Godot uses for its shader code is very similar. It doesn’t take more than 10 minutes to get the hang of it. From there, I feel that code shaders are more concise than their visual counterparts, which made it easier for me to follow the course.

Regarding content, the 2D shaders section seemed very complete to me. However, the 3D shaders section felt a bit short. The 3D part stays at the basics.

In any case, for a 5-hour course, I think it’s very good and enjoyable. The immediacy of Godot makes it very comfortable to follow the course. What a difference compared to Unity and its domain reloads every time you touch the editor!

So, I highly recommend the course.

26 May 2024

Course "Godot 4 Multiplayer: Make Your Own Online Game" by GameDev.TV

A few days ago, I finished the course that gives this article its title, and now I’m ready to share my thoughts on it. I took the course on Udemy. It’s also available on GameDevTV’s own platform, but since I already have other courses on various topics on Udemy, I prefer to keep buying them there to have everything in one place. Another advantage of Udemy is that it often has English subtitles, which can be a lifesaver if the instructor has a very thick accent. In theory, GameDevTV’s platform should allow you to enable subtitles, but I haven’t seen how in the few courses I have there.

On Udemy, the course is advertised as covering the following topics:

  • Building an online multiplayer game using the Godot 4 libraries.
  • Creating common multiplayer game mechanics such as switch tiles, movable objects, unlockable doors, etc.
  • Synchronizing these mechanics over the internet to allow players to interact and collaborate to overcome challenges.
  • Using W4 Games' infrastructure to enable players to connect even if they are not on the same local network.

The game developed to explain these principles is a simple 2D platformer, where 2 players can collaborate to reach switch tiles that open doors and create bridges, allowing access to previously unreachable areas. It also includes a mechanic for opening a chest to collect a key that unlocks the level’s end gate. As you can see, the game itself is very simple, but it covers a range of very common mechanics in this type of game.

The entire first section of the course is dedicated to shaping the base game. If you haven’t touched Godot in a while, it can serve as a refresher. If you’ve never used Godot, it can also work as an introductory tutorial.

In the second section, the implementation of player connectivity within the same local network begins. It turns out that Godot only needs 2 specialized nodes to offer a complete multiplayer experience. This simplicity and elegance speak volumes about this engine. With those 2 specialized nodes and RPC calls from the code, you have everything you need to set up your online game.

The third section, the longest, explains how to apply the concepts from the previous section so that the different game mechanics can be synchronized for all players at the same time, ensuring they always see the same game state.

The course implements its code in GDScript, but I followed along by implementing my code in C# and had no issues.

The instructor explains very well, his pronunciation is good, and he doesn’t ramble. The project chosen to support his explanations is simple enough not to be complicated, but more than enough to cover the most common mechanics usually implemented in a platformer. By the end of the course, you have a pretty good idea of how to structure a basic multiplayer game.

However, there are areas for improvement. For starters, Godot's multiplayer tools (the 2 nodes and RPC calls) are covered in a very practical manner, which isn’t bad, but I was left wanting more theoretical depth. You end up guessing what each thing does, but not with the confidence of knowing what it does internally. For example, RPC calls are extensively covered and used in the course, but I would have liked more in-depth explanations on their general functioning and how they would be used in other contexts.

Another area for improvement is that despite mentioning W4 Games' services, they are not mentioned at all in the course. It’s true that the fine print warns that these contents are not yet available and will come later, but W4 Games has long since opened its beta for people to try out their services. I expected that by now they would have included that part in the course, or at least said when they would. None of this has happened, and that’s why I didn’t give it 5 stars on Udemy. If they eventually include the section explaining how to use W4 Games' services, I will revise my rating upward.

Despite this, the course is highly recommended, though not at the full price advertised on Udemy and GameDevTV. My advice is to wait until it’s on sale on either of these platforms to buy it. I’m not sure about GameDevTV, but on Udemy, sales are very frequent, so my advice is not to make the rookie mistake of buying it for €50 or €90 when it’s very often on sale for €10 or €15.

08 May 2024

"Programming Game AI by Example" by Mat Buckland

It's not easy to find good books on artificial intelligence (AI) applied to games. Most of them don't go beyond the introductory level, and when they explain the A* algorithm, they consider it advanced material and leave it there. In my opinion, the real gem in this field is Ian Millington's "AI for Games," which combines vast content with clear, detailed explanations that are truly relevant to game development. Since I read it, I hadn't come across another work that could compare until I stumbled upon the one we're discussing in this article. It's worth noting that Buckland's work was one of Millington's references.

While "Programming AI by Example" may not match the breadth of content in "AI for Games," it certainly delves into the topics it covers with great depth and clarity. It's also worth noting that it addresses several topics absent from Millington's work, such as integrating scripting systems into our games (to simplify AI algorithm design) and the chapter on goal-driven agents.

The book is filled with good illustrative figures that aid comprehension.

Unlike Millington, the implementations are illustrated not in pseudocode but in C++, which, in my opinion, is a downside because it's not exactly the most intuitive language in the world. However, the explanations are extensive and clear enough that a full understanding of the code is not essential.

I also noticed the emphasis on showing UML diagrams of the class hierarchies of the different implementations. I understand why this is done, and it's not excessive, but it made me smile because it feels somewhat outdated. UML diagrams are not commonly seen in books anymore.

Despite all these signs of the time elapsed since the book was published, the field of AI for games has not advanced so much as to render its content obsolete. The principles it covers remain relevant. If anything, some tools that have emerged later, such as behavior trees or neural learning, are missing.

In conclusion, I found the book excellent. I recommend reading it before Millington's. That way, you can enhance its usefulness as an introductory piece to facilitate later understanding of Millington's work and expand on what Buckland leaves pending. With this approach, I believe you'll cover the best of what has been written so far in the field of AI for games.

07 May 2024

How to implement a MiniMap in Godot

A few days ago, I published an article about a Godot course I had just finished on Udemy. It was about a 2.5D action game, so even though the course itself didn't cover it, I thought it was the perfect foundation for learning how to make MiniMaps in Godot.

As you may know, a MiniMap is a small window included in many games to show where the character is within the level. You have an example in the image that opens this article, corresponding to the MiniMap of World of Warcraft.

It turns out that implementing a basic MiniMap in Godot is very easy and, in its most basic version, doesn't even require code. Let's start by explaining how to implement a stationary MiniMap and from there we'll progressively sophisticate it by adding the following features:

  1. We'll make the MiniMap move following the main character.
  2. We'll represent the character and its surroundings with icons inside the MiniMap.
  3. We'll see how to make the MiniMap round.
  4. We'll adorn the MiniMap with a border.
  5. Basic stationary MiniMap

Basic stationary MiniMap

This MiniMap doesn't move with the character but shows a section of the scenario. It only makes sense if our level is very small and can be entirely shown within the MiniMap. Still, despite its limited usefulness, it's the basis from which all MiniMaps start.

To implement it, we'll need to add the following nodes to the hierarchy of our scene:

The SubViewportContainer node will allow us to anchor the MiniMap to the area of the screen where we want it to be located by simply selecting that node and setting its anchoring in the main view tab:

Once the MiniMap is placed, you'll probably want to define its size. To do that, you need to first set the size of the SubViewport node, responsible for showing the camera view. To do this, select that node and configure the Size property.

It's possible that after resizing the SubViewport node, you'll need to re-set the anchoring of the SubViewportContainer node.

Once that's done, we'll have a window, overlaid on the main game window, that will show what the third node focuses on: the camera view. What we'll need to do is to place that camera over the scenario, focusing vertically. I usually set up this camera in orthogonal projection because it makes the MiniMap clearer. With its Size parameter, we can encompass more or less of the scenario within the focus. Finally, it's important to uncheck the Current parameter so as not to override the main game's main camera function. Ultimately, those camera parameters can look like this:

At this point, we'll have the most basic version of the MiniMap.

However, this MiniMap has many shortcomings that we'll address in the following sections.

Moving MiniMap

The first problem we have at this point is that since the camera doesn't move, we have to give it a gigantic Size so that the entire scenario fits in the MiniMap frame. This reduces its value because the larger the scenario, the more its details will be reduced in the MiniMap. What is normally done in these cases is to reduce the Size of the camera, causing it to focus only on a part of the scenario around the player character and make it follow the character. This way, although the camera doesn't cover the entire scenario, it will provide enough detail of the player's environment, which is what really matters.

To make the MiniMap camera follow the player, you need to add the following script to it:

As you can see, it simply locates the camera in the same position as the player, retaining the initial height at which we would have placed it in the editor. Since we've implemented the _Process() method, the camera's position is updated every frame. The effect will be that the camera will move with the player, focusing on them from above.

The _player field is just a reference that will be passed throug inspector, dragging the scene player object over that field.

Representation with icons of characters and map elements

The next problem will be that, no matter how much we've brought the camera closer, it's very possible that many of the important elements are too small or not clearly visible. To solve this, most MiniMaps represent those elements with icons, as can be seen in the example MiniMap that starts this article.

In my particular case, since my game was 2.5D, the characters were sprites, so being flat, they were invisible when focused from above with the MiniMap camera.

The solution is to add a sprite just above the elements we want to show on the MiniMap. These sprites will display the icon we want to represent those elements.

For example, in my case, I added the sprite of a helmet above my enemies.

Logically, this icon must be on a plane perpendicular to the focus axis of the MiniMap camera so that it can capture it properly. If the MiniMap camera focuses from the Y-axis, the icon will have to rest on the XZ plane.

At this point, the issue will be that these icons are invisible to the main game's main camera and only show up on the MiniMap camera. To solve this, we can use rendering layers.

In my game, I've created the following rendering layers, within Project > Project Settings... > General > Layer Names > 3D Render:

I placed the pieces of the scenario in layer 1, the player character in layer 2, and the enemies in layer 3. This is configured in the VisualInstance3D section of the main sprite of each of the elements. For example, in the case of the sprite representing the player, its configuration is as follows:

For 3D elements, the rendering layer is configured in the MeshInstance section.

As for the markers' icons, both for the player and the enemies, I've left them on layer 4.

To ensure that the main game's main camera doesn't show the MiniMap icons, set its Cull Mask so that it doesn't display the layer where you've placed those icons.

In the case of our example, the main game's main camera has the following Cull Mask:

Considering the layers I had created, the above means that the main game's main camera only shows the scenario (layer 1), the player (layer 2), the enemies (layer 3), but not the MiniMap markers (layer 4).

In contrast, the MiniMap camera's Cull Mask should include the layer where the icons are.

In the example's case, the MiniMap camera has the following configuration:

Note, therefore, that the MiniMap will show the scenario (layer 1) and the marker icons (layer 4). I don't show the player or the enemies because these are already represented by their respective markers.

The result will be that the player and enemies will be represented as follows on the MiniMap:

Round MiniMap

At this point, we'll have a functionally complete MiniMap, albeit aesthetically modest.

It may be that in our game, a square MiniMap fits, but how would we do it if we wanted a round MiniMap?

There are several ways to do it. Some prefer to use a shader, but I think it's much simpler to use a mask. This is a sprite that overlays an image to define which parts of the image can be seen and which cannot. The sprite that acts as a mask will define the parts that can be seen with an alpha of 1 (regardless of color) and those that cannot with an alpha of 0 (transparent).

A graphic editor like Gimp may be sufficient to create a mask like the following:

Import the mask image into Godot and associate it with a Sprite2D node that you should place as the parent of the MiniMask:

For the sprite to act as a mask, you must set the Clip Children parameter of its CanvasItem section to Clip Only. This will mask all the nodes that it has as children.

When you reposition the MiniMap nodes under the mask sprite, you may need to ensure that the sizes (Transform-Sizes) of the SubviewPortContainer and Subviewport nodes match. If they don't match, you may only see a portion of the MiniMap.

Also, make sure that the Anchor Preset parameter of the SubViewportContainer is set to FullRect so that it fits the size of the mask sprite.

The problem with this scheme is that the MiniMap will lose automatic anchoring to the screen because the parent of the MiniMap (the mask sprite) will no longer automatically reposition when the game window is resized. In these cases, it's usually a good idea to place the mask sprite (and all its children) under a PanelContainer node so that we can anchor it to the screen position we want.

At this point, the problem will be that the MiniMap will be round, but for some reason, the panel on which it is displayed will not be entirely transparent (zoom in on the photo and look at the edges of the MiniMap):

The cause is that the default style of Godot panels includes making their background not transparent. So, we have to change that. Go to the properties of the PanelContainer and, in the ThemeOverrides > Styles section, create an empty StyleBox resource. This will reset the default values of the Panel Container style, and it will become completely transparent.

MiniMap Border

It's common to give the MiniMap a border to highlight it against the background and to match the general aesthetics of the game. Let's see how to do it.

If we're not artists, we can search the Internet for borders for our MiniMaps. However, I advise you to check the rights of what you find to make sure you can use it in your game. A search for "circular Minimap texture download" terms can offer many examples. One of them is the one I used in this tutorial:

Note that the image must contain an Alpha channel, setting with value 0 all those areas, such as the inside of the ring, through which we want our MiniMap to be visible.

The idea is to place that image over the MiniMap, covering the edges. To do this, we have to add a TextureRect node as a child of the MiniMap's PanelContainer. On this new node, we should drag the border image, which will show it in the editor.

The image may have a size that doesn't fit our MiniMap, so we'll have to resize it. To do this, we must set the Expand Mode parameter of the TextureRect to Ignore Size. From there, we can change the size of the border image by modifying its Custom Minimum Size parameter. We'll probably also have to change the Position and Scale parameters of the MiniMapMask node to resize and center the MiniMap image within the border.

The resulting node scheme will be as follows:

And the result:

Note that, in Godot, the painting order of nodes is from top to bottom of the scene hierarchy. That means that nodes closer to the root are painted first, and then their children. So it's important that the TextureRect is below the MiniMapMask so that the MiniMapMask is painted first, and then the TextureRect. The consequence of this is that the TextureRect will be painted on top of the MiniMapMask node, covering its edges.

Try reversing the order and see the effect.

01 May 2024

"Godot 4 C# Action Adventure: Build your own 2.5D RPG" course review

Throughout the past year, I became interested in Godot as an option for game development. I was content with Unity, but what I was reading about Godot was fascinating to me. I was particularly drawn to its focus on streamlining and speeding up development. Unity is great, but working with it is slow. The constant reloading of the domain with even the slightest script modification and the slow compilation times make the workflow in Unity slower than I would like. The scandal last September, with Unity's unilateral change in terms, made me decide to start learning Godot. I'm not sure if I'll end up developing anything in Godot, but it's always good to have other options if staying with Unity becomes unsustainable, and it's also not bad to broaden the spectrum of engines if you're learning game development, as the concepts you learn in one engine will likely be useful in another.

So, I got down to it, starting with books on Godot, which I've been discussing here. Once I understood the basics, I started looking for courses on Godot to start practicing in a guided way. I had taken GameDevTV courses on Unity before and liked them, so I ended up buying a couple of their courses on Udemy. I know I could buy them on their own platform, but since they also sell them on Udemy, I prefer to buy them there and centralize all my courses. Otherwise, I end up scattering them across different platforms and forgetting what I have on each one.

One of the courses I chose is the one that gives its name to this article, "Godot 4 C# Action Adventure: Build your own 2.5D RPG" and it differs from others on Godot in that it focuses on development with C# instead of GDScript. GDScript has multiple advantages: it's very easy to learn and read, flexible, fast, and tightly integrated into the Godot editor. However, when coming from Unity, what you want is to smooth the learning curve as much as possible, and Godot's decision to support C# is a very smart way to ease the transition for Unity developers. Apart from saving you from having to learn another language, using C# has multiple additional advantages:

  1. Increases game performance. It's true that Godot games developed in C++ are faster, but games developed in Godot's C# are much faster than those using GDScript.
  2. Much better supported by IDEs. Godot's editor offers a lightweight version of an IDE for GDScript, but when coming from a fully-featured IDE like Visual Studio or Rider, Godot's built-in IDE falls very short. You end up missing the conveniences that a proper IDE offers by default. While you can also program GDScript in those IDEs, their support for it is very limited, and you still miss things. Ultimately, when you decide to program in C# in Godot, you can do it from your preferred IDE and feel right at home. Plus, Rider has an official plugin for Godot C# that makes the experience of using it with Godot very similar to using it with Unity.
  3. Opens the door to using third-party libraries. Unlike Unity, Godot allows you to integrate NuGet libraries into your project, minimizing the chances of having to reinvent the wheel.
  4. Greater code sophistication. GDScript is gradually maturing, but it still lacks many of the sophistications and abstractions that C# already offers. When coming from Unity, it's very difficult to give up many programming patterns that you've internalized in C#.

This course is one of the few that approaches Godot using C#, even though the C# developer community is one of the most vibrant in the engine's ecosystem.

Therefore, my main goal was not so much to learn new concepts as to put into practice what I already knew in a new engine, using C#. I wanted to see what the workflow could be like with C# and Godot. The result has been fully satisfactory. Not only did I find it very comfortable to work with Godot and C#, but I also learned a few tricks and concepts along the way.

The course focuses on programming a small 2.5D action game. The environments are in 3D, but the characters are 2D sprites, hence the 2.5D aspect. As for the RPG part in the title... well, it doesn't show up anywhere. Don't expect inventory management or skill tree management, as you would see in an RPG. The game ends up being purely action-based, focusing on attacking enemies with stabs and fleeing from them when they start to surround you. To add excitement to the battles, the game implements a couple of special attacks with bombs and lightning.

Things I've learned in this course:

  • To shape the environments, it teaches you how to generate MeshLibraries, which are like palettes of scenery objects. It seems that Godot doesn't yet support palettes spanning scenes (the equivalent of Unity's prefabs), but only meshes with an associated collider. However, that, combined with a grid system, allows you to shape the environments comfortably and fairly accurately. I found it a bit awkward to move around while the grid was active because the right mouse button, which is used in the rest of the editor for free movement through the environment, is used to delete objects when you're in grid mode.
  • Coming from Unity, I thought Godot's Node system was too granular. I didn't take long to get used to it. In the end, it turns out to be as comfortable, or even more so, than Unity's component system. The course explains it very well.
  • Godot's Input system is like a simplified version of Unity's New Input System. I appreciated that it's much easier to set up than Unity's, although it's also true that the game only requires simple key presses. It remains to be seen how it performs in games that require more complex controls.
  • In Godot, you won't miss Scriptable Objects. Here they're called Resources, and I've seen quite a few possibilities in them. The possibility, which the course teaches you, of dumping a resource to a file to use it as a shared repository for data among various scripts (decoupled from each other) seemed very powerful to me.
  • Godot has a node called AnimationTree, which is essentially a combination of Unity's Animator and Animator Controller (all in one). On the one hand, it's more limited in transitions between animations (I missed being able to choose at what point in the animation to exit the previous state and at what point in the next animation to land in the next state), but on the other hand, it's used through a method called travel(), which allows you to transition from one state to another from disparate points in the state graph using A* to choose the route. It also has parameters, like Unity's Animator Controller, but lacks triggers. The course doesn't talk about AnimationTrees, but instead chooses to create state machines through code and call animations directly. Despite that, I insisted on using AnimationTrees with the guards, to learn to use that node. My conclusion so far is that the similarities between Godot's AnimationTrees and Unity's AnimatorControllers are quite superficial. Although they're used for the same purpose, their handling is very different. If you insist on using an AnimationTree through parameters, as you would in Unity, you'll probably run into problems. You'll also miss triggers a lot. My feeling is that in the end, you have to replace the use of triggers with calls to travel(), and that AnimationTrees are much more confined to animations than AnimatorControllers, which seem more general-purpose.
  • Godot's navigation system is very easy to use. It's very similar to Unity's. If anything, I missed being able to define a step height for the agent in Godot's navigation system, which gave me problems with small steps that I had to replace with invisible ramps.
  • I missed Unity's Gizmos and Handles. The course doesn't cover this, but I looked into it on my own. In a first sweep, I didn't find anything obvious. There's some mention in the documentation, but I admit I still don't have a clear idea. I have to delve into it more.
  • The course taught me a combat system based on colliders (hit boxes and hurt boxes) that I hadn't thought of and that greatly simplifies other approaches I've used to implement sword combat.
  • Godot's user interface system is a piece of cake. Very easy to use. If you're coming from Unity, it's more similar to uGUI than the new UI Toolkit, although it's true that unlike uGUI, things are edited in its own editor rather than overlapping with the 3D view of the scene (which I've always found horrible in Unity).
  • Godot's signal and event system is very effective. It's true that in C#, it's not as straightforward as in GDScript, but once you get used to ending the definition of your events/signals with the suffix ...EventHandler(), everything goes well.
  • The course touches on shaders, but only provides an example of a simple shader implemented through code (Godot's version of GLSL). I would have liked it better if it had explained it using Godot's Visual Shaders (which it has), but I was left wanting. I'll have to find another course that covers it.
  • As for particle systems, they're very similar to Unity's.
Overall, not bad. The risk with these courses is that they're too basic. Fortunately, this one strikes a good balance between explaining the engine from scratch and reaching concepts that are interesting for people who already know other engines.

So, I recommend this course. I haven't regretted buying it and dedicating time to it. As for those of you who might be put off by the English, I'll mention that the Udemy course has English subtitles, so if you already read game development books in English, you won't have a hard time following the course. Plus, the instructor speaks very slowly, his pronunciation is very clear, and he uses very simple vocabulary. I, at least, haven't had any trouble following him.

07 January 2024

"Artificial Intelligence in Games" by Paul Roberts

The best book I've read so far on how to develop game AI is AI for Games by Ian Millington. The problem is that there aren't many books on the market that cover the game AI branch in a practical way. The ones that exist are either too theoretical or they only cover a couple of topics, such as pathfinding and state machines. That's why I read Game AI Programming with Unity by Paul Roberts with eagerness.

Fortunately, it has a practical and introductory approach. I would recommend that anyone who wants to get started in the world of game AI read this book before Millington's, since Roberts's book doesn't go as deep, but it's written in a more plain language. It's ideal for a first contact with the different branches of AI used in games, to then go deeper with Millington.

The topics it covers are varied and interesting: steering behaviors, terrain analysis with influence maps, pathfinding, decision structures, fuzzy logic, minimax, genetic algorithms, and neural networks. Unlike Millington's, you won't end up with enough knowledge to implement your own version with Roberts's book, but you will have a good understanding of the main concepts, which will make things much easier when you start reading more detailed texts.

The Kindle digital version has some defects that have made it difficult to progress at times, mainly that the formulas are not well formatted and have lost most of the operators in the digital conversion. So it's very difficult to get an idea of the formula just from what's in it. Fortunately, the formulas are not abundant or complex, so in the end you end up figuring out what they mean, even though you have to think about it for a while. I really don't understand why he didn't do the same with the diagrams, which are hand-drawn and digitized, but at least they are understandable. If he had done the same with the formulas, there would have been no problem.

But more than the theory, whose depth I have already said is quite scarce, where the book really shines is with the practical part. The author has developed a series of mini-games in Unity to test the concepts of the book. So, after the theoretical part of each chapter, there is another part in which he guides you, step by step, in a tutorial format, to implement those concepts to create an AI that will face you in the mini-game. It must be recognized that the author has made an effort to create complex, well-presented mini-games that are very well suited as a platform for testing theoretical concepts. I think this is the main value of the book. There are others that explain the different concepts better and more in depth, but they stay in theory. Having the opportunity to tinker with and test these concepts directly in a game is something that only this book has offered me so far.

So, it's a book that I recommend. Recognizing its limitations and defects, I think it's a book that adds value to the limited ecosystem of books on game AI.