Hello, everyone! How do you do? There’s been some significant advances in the game this week too. Let’s have a look at them!
What I’ve done this week
- Improved the “map warp” system, that is, the system that takes you from one map to another through a door. Now the player doesn’t appear in a predefined, fixed position in the map: instead, the landing player coordinates are defined on a case by case basis, so two doors can take you to the same map, but make you land in different positions.
- Also regarding the map warp system, I’ve implemented indoor maps, so you can enter and exit houses, caves, etc. without the states and positions of objects being reset. If you’re interested in learning how I did it, have a look at the bottom of the post!
- Changed the font, since it didn’t have accented caps (Ó, Ò, Í, À, etc.), which are important in Catalan and Spanish, two of the game’s supported languages. The new font is called Amstrad CPC Extended Tweak, it’s been made by ruboku (with some additions by gecko.jsc) and it looks like this:
What I want to work on next
- Improve the titlescreen displayed at the beginning of each episode, so it also shows some basic info apart from the title: episode goal, description and available time to reach the goal.
- Implement the clock countdown system.
- Add a system that detects whether the player is standing on a “water tile” or not, and changes the player animation to swimming instead of walking (this is important, since at some point I’ll add the option to dive underwater and enter underwater maps).
- Add a game over event when your health drops to 0 or the clock reaches the max available time.
Things I want to do but will leave for later
- Implement a savefile system with encrypted files.
- Add a system to save several game stats to the savefile (time it took to finish every episode, items found, etc.). Also include a scene in-game to be able to check those stats, and another scene that runs when you finish every episode and displays that particular episode’s stats.
- Create an actual config menu.
- Add custom keybindings.
- Implement the item system + random drops when you destroy obstacles and take the relevant data from a json database.
- Fixed the bug that, sometimes, after entering the element/spell selection menu, made you unable to exit it.
- Caused and fixed a lot of bugs (that indoor map system was a nightmare).
Known bugs to fix
- The system that lets you choose the size of screenshots is broken. For now it’s beyond my control, since apparently there’s an engine bug regarding the resize() Image function.
Making-of: indoor map system
As I mentioned above, this week I’ve implemented a simple indoor map system in the game. I say simple, because it isn’t recursive: that is, you cannot enter maps inside of other maps indefinitely. You can have an outdoor map and warp to an indoor map from there, but you can’t have indoor maps inside of other indoor maps.
How have I achieved this? And why is there such a limitation to the system?
In order to explain this, one must first understand Godot’s way of handling scenes. In Godot, everything (from a character, to a bullet, to a menu, to a tileset, to a full-fledged map) can be turned into an individual scene, and such scenes can be instanced inside of other scenes. In my case, I’ve structured the game more or less like this:
- basic system stuff (autoloaded)
- hud menu
- dialog system > hidden unless active
- sound effects player
- active map scene
- spell selection menu
- NPCs and obstacles
Every item in this list is a scene, and some of them have several subscenes, subsubscenes, etc.
As you can see, certain stuff is loaded at the beginning of the game and is always present (the hud menu, the dialog system, etc.), but other things, such as the player and the NPCs, are loaded as “children” of the active map scene. That means that, every time that the active game map changes, the player, music, NPCs, etc. are destroyed and instanced again as children of the new map.
This mostly makes sense: except for the player, everything else (the music, the NPCs/obstacles and the grid) is different depending on the map. But it also makes it difficult to create an indoor system. Why?
Certain obstacles in the game are randomised. That means that, every time a map is recreated, the positions and states of obstacles change randomly. But you can also destroy obstacles, create them, or move them around. Therefore, if you enter an indoor map and exit it, you don’t want everything outdoors to be reset and randomised every time: you want it to stay the same. In practice, this means that, when you enter an indoor map, the outdoor map should stay in the background and not be deleted.
In general, when “changing” scenes in Godot, you use the following command:
That’s what I use when I want to change the “active map scene”. But, for indoor maps, I don’t want to completely change the scene: I just want to add another scene “on top”, and keep the previous one hidden. So I’ve come up with a workaround. Instead of changing the scene, I remove the player, and add it again as a child of the indoor scene. That way, the previous scene remains inactive and it looks for all purposes like the map has changed. Here’s some pseudo GDScript to demonstrate this:
onready var Player = preload("res://player/player.tscn") func go_indoors(map_id): # instance new scene on top of the old one var new_scene = load("res://maps/" + str(map_id) + ".tscn") var new_scene_instance = new_scene.instance() previous_grid.add_child(new_scene_instance) # remove previous player previous_grid.previous_player.queue_free() # add new player new_player = Player.instance() new_player.set_position(get_player_position()) new_grid.add_child(new_player)
In order to return to the outdoor map, it’s as simple as removing the indoor map instance and recreating the player again, as a child of the outdoor map.
So, why isn’t the system recursive? Simple: for it to be so, I’d need to add layer upon layer of inactive maps, and it would take up a lot of memory. I’d rather just have an inactive hidden map at max.
There’s other ways to achieve this without having to keep the previous map active, of course, but this is the easiest solution I could come up with and it will be enough for now.
Also, this system will probably get five times as complicated once I get around to implementing the underwater/overwater dual map system, but let’s not think about that for now, haha.
That’s all, I think. Thank you for reading and see you next week!