Level Editor
Made with: Unity, C# for PC
Solo project
Module ‘Production Tools’ - 8 weeks
June 2025
Functionality
For this project, I developed a 2D platformer level editor in Unity. The tool is divided into two main components: the "Create" section and the "Play" section.
In the Create section, users can build new levels from scratch. When creating a level, the tool checks whether a level with the chosen name already exists and prompts the user to select a different name if needed. Users can also view existing levels, edit them, clear them, or—if they’ve already cleared the level—upload them to the Play section.
The Editor scene allows users to place various tiles on a tilemap, such as spikes that deal damage and collectible coins. Additional settings include configuring the time limit for the level and the number of starting hit points. The middle mouse button lets users move the camera for easier navigation, and right-clicking removes placed tiles.
Pressing ‘Esc’ opens a menu with the following options:
Save & Clear: Saves the level and initiates the clear-check process
Save & Quit: Saves the level and returns to the main menu
Save: Saves the level without exiting
Quit without saving: Exits to the menu without saving
Clearing a level is required to upload it to the Play section. The player must first complete the level themselves to prove it is possible. Once cleared, the level can be uploaded using a unique name or saved for later upload. Levels that have been cleared are visually indicated with a green checkmark; uncleared levels show a gray checkmark.
In the Play section, users can play through uploaded levels. The system tracks completion time and the number of coins collected. If a player beats their previous high score, it is saved and displayed in the Play menu.
Development process
I was excited to take on the challenge of building a level editor, and this project proved to be a perfect opportunity. I began by researching how other level editors, such as Super Mario Maker 2, structure their tools. After outlining the core features, I built a simple prototype that stored data using JSON. From there, I iteratively expanded the tool into its final form.
One of the main challenges was ensuring reliable data handling—such as proper serialization of levels, erasing tiles, supporting multiple tilemaps, and handling unique logic for interactable tiles. While I’m satisfied with the final result, I would have liked to expand the tool further, for example by adding enemies.
Technical Overview
Level Creation
When creating a new level, the tool checks for name conflicts in the Edit folder. If the name is unique, a new level is created. Each level is represented by a LevelData
class, which contains:
levelName
A list of custom
TileData
(tilemap, tileType, and position)Booleans for
isCleared
andisBeaten
Integers for
coinsCollected
andtimeToComplete
Floats for
playerStartX
,playerStartY
, andfastestTime
The data is serialized to JSON and saved in Unity’s persistent data path.
Saving Levels
When saving a level, the LevelData
is serialized and overwrites the previous file. A snapshot of the current camera view is saved as a PNG thumbnail and displayed in the level selection menu.
Loading Levels
To load a level, the tool retrieves the JSON file based on the level name, deserializes it into a LevelData
object, and recreates the level by instantiating tiles according to the saved data.
Level Building
Level construction uses Unity's Tilemap system. Tiles are assigned in the Inspector and dynamically converted into selectable buttons at runtime. Variables like maxPlayerHealth
, timeToComplete
, and playerStart
are also stored during editing.
Uploading Levels
To "upload" a level, its JSON file is copied from the Edit folder to the Play folder. This is only possible if isCleared
is true
, ensuring that only completable levels can be shared.
Playing & Clearing Levels
When testing or playing a level, the editor is disabled and the player controller is activated. The game tracks the completion time and collected coins, updating the corresponding values in the level’s JSON file. This also marks the level as cleared or completed.
Tile Logic
Each placeable tile has a unique name, which maps to a delegate via a lookup table. Tiles are defined in the Inspector using TileBase
, a string representing the action to invoke, and an optional integer for extra parameters (e.g., damage amount). These are stored in a dictionary with the tile name as the key and TileInfo
as the value.
When the player collides with a trigger tile, the system checks if an action exists for the tile’s name and, if so, invokes it with parameters such as the tilemap, cell position, and action value. This flexible system eliminates the need for multiple tilemaps while allowing diverse tile behaviors