Hi there! Today I’m going to talk about the level building workflow in Roll Playing Game.
What annoyed me the most in my previous game project/prototype (Thriceball, built with the OGRE Engine) was how long it took me to finish a simple level. Starting with Roll Playing Game’s development, that was the number one thing I wanted to streamline and make as efficient as possible.
For this reason (and because the movement in this game is generally limited to the X and Y axes), I decided to use tilemaps and import them in the UE4 as the basic structure of a level, using Tiled as the tool to create them. I’m trying to explain this workflow next.
This is the awesome tileset I’m using in Tiled.
The tilemap describes the complete floor of the level, as well as the position of point orbs (yellow spheres), standard floor traps (red) etc. The first draft of a level only takes a few minutes to build (or rather: paint). Tiled supports multiple tilemap layers, but I only need one for this game, which makes it easier.
The level tilemap is saved as a .json file by Tiled, which I then import into UE4 with a few lines of C++. I created a Tilemap class that extends AActor and handles the import using the Json module. I posted about this about a year ago in the forums.
In the Unreal Editor, I have a blueprint based on the Tilemap C++ class that calls ReadTilemapFile() in its Construction Script and then uses the information that was loaded into the Tiles Array to create the level. The Tiles Array is an array of a custom struct that contains information about a specific tile, e.g. if it’s a floor tile or a floor trap. The C++ class also calculates the floor tile type based on its surrounding tiles (floor, inner corner wall, outer corner wall, …). I have multiple Instanced Static Mesh (ISM) components on the Tilemap blueprint for each tile type. When parsing the Tiles Array, instances are added to the according components.
Not all tile types can be represented by Instanced Static Mesh components, for example the yellow orbs that are attracted and collected by the ball. For these, only their initial locations are stored during the Construction Script and they are spawned on Begin Play using the stored locations. I still have an ISM component for them on the tilemap, but only as static “gizmo”-like representations for me to be able to see their locations while editing the map.
Gameplay objects with properties that should be customizable in the editor (i.e. most of them) and those that are not positioned inside the 2D grid are obviously not loaded with the tilemap but manually placed. Projectile Turrets for example have a customizable direction, interval speed, projectile speed and more. Laser Beams have custom rotation and speed values as well. As I have to edit them one by one anyway, it’s not a problem to add them manually to the level in the editor and not in the tilemap.
That’s it for this blog post – I hope it was helpful or at least an interesting read for some of you. With an efficient workflow like this, I can finally focus on the gameplay aspect of level building, as it should be. If you have any questions or feedback about the workflow, feel free to use the comments section below!