For my vocational degree in computer programming (2018-2021) I had to do a project using
technologies taught in
the program: C# , WinForms and MSSQL. So I chose to develop a map tool to be used in DnD
and
other games.
Design
The goal was to have two modes of the tool the level editor tool and the game master
tool. With the level editor
tool the user could create levels with 2D Tilemaps. After creating the maps for a game
night the user would
launch the game master tool. In this tool the user could render the maps on a separate
screen and keep notes for
themselves about the game session for future reference.
Implementation
State diagram
The tool opens with a "main menu" from which the level editor and GM tool can be opened
Game master tool
State diagram
The game master tool consists of two windows that are opened after a game is created. The
game window, a full screen
window that is placed on the monitor selected in the main menu and should be visible to
all players when playing a
tabletop game. Then a game master window, from where the gaming session can be managed
GM tools
In the game master tools levels can be loaded and drawn on to the game window.
Additionally the game master can keep
notes of the session on the game master window. Both of these options are saved into a
MSSQL database from which
they can be fetched again when the gaming session in continued.
Tilemap level editor
State diagram
The level editor is divided into two sections. On the left the map itself and on the
right the controls.
Map
The editor shown portion of the map and can be navigated with scrollbars horizontally and
vertically. The editor
consists of the map tiles which can be clicked on to place a tile texture on them or
clear it.
The tiles are implemeted as images that windows forms draws based on camera location and
grid coordinates.
The selected tile is calculated when mouse moves over the grid. This is for highlight
etc. When mouse is clicked on
the grid the selected tile is updated with the new tile information.
Code snippet
foreach (Tile tile in level.Layers[(int)layerSelection.Value].Tiles)
{
int tileX = tile.X * tileSize - cam.Location().X * tileSize + cam.FovX / 2 * tileSize;
int tileY = tile.Y * tileSize - cam.Location().Y * tileSize + cam.FovY / 2 * tileSize;
if (pos.X > tileX && pos.X < tileX + tileSize)
{
if (pos.Y > tileY && pos.Y < tileY + tileSize)
{
if (tile.X < cam.Location().X + cam.FovX / 2 &
tile.X > cam.Location().X - cam.FovX / 2 &
tile.Y < cam.Location().Y + cam.FovY / 2 &
tile.Y > cam.Location().Y - cam.FovY / 2)
{
selectedTile = tile;
}
}
}
}
Controls
In the controls panel there are UI for level file handling, layers, minimap and the
tilemaps.
Level files
The user is able to save the level into a file using JSON data format. To accomplish this
I created a static
FileHandler class that can save a level and load a level. To keep the file size small
only tiles with an image are
saved and all other are removed as for each saved tile the coordinates are saved with
the image details so that the
level can be re-constructed.
Code snippet
public static void SaveLevel(Level lvl, string path)
{
Level level = new Level();
foreach(TileMap map in lvl.Maps)
{
level.AddAMap(map);
}
foreach(Layer layer in lvl.Layers)
{
Layer newLayer = new Layer();
foreach(Tile tile in layer.Tiles)
{
if (tile.Image != null)
{
Tile newTile = tile;
newTile.PrepareForSaving();
newLayer.AddTile(newTile);
}
}
level.AddALayer(newLayer);
}
JsonSerializer serializer = new JsonSerializer();
using(StreamWriter wr = new StreamWriter(path))
{
using(JsonWriter writer = new JsonTextWriter(wr))
{
serializer.Serialize(writer, level);
}
}
}
Layers
The user can add layers of tile grids to the level which are then rendered on top of each
other. With this the user
can create complex sceneries with simple tilemaps.
Minimap
Due to the limited size of the grid that can be shown at a time, the editor draws a
minimap of the level for the user
to be able to have a clearer image of the whole map. This is done by selecting a tile
for an coordinate from the
highest layer, that has an image. Then the image is scaled to 1 pixel size and placed on
to the minimap.
Code snippet
public static Color GetPixel(Image image)
{
Bitmap bitmap = new Bitmap(1, 1);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(image, 0, 0, 1, 1);
};
Color color = bitmap.GetPixel(0, 0);
return color;
}
Tilemaps
Tilemaps are 2D images that consist of drawn tiles of specified width and height. This
image can be then parsed into
seperate tiles, from which a level can be built from.
When adding a tilemap the editor asks for the path of the image and the size of the
tiles. After this information is
given the image is seperated into tile buttons. When clicking a tile it becomes selected
and can then be placed onto
the level. These tile buttons are implemented with WinForm buttons.