Introduction
The TileEditor
control edits a grid of tiles. It can be used to quickly create fast editors of tile based games. It supports 2D grids with multiple layers, and can paint relatively fast using GDI.
The current version supports editing of small and medium maps, mutliple selections of tiles, copy and pasting of tiles and multiple undo and redo actions.
Background
Frequently, I have needed a Tile Editing control so I can quickly make editors to edit maps for Tile Based games. None were around at the time, so I decided to create my own. The control is a quick painting tile editor, letting you create editors of many kinds quickly and easily.
History
- 2.0 (27th May 08)
- Added selection of tiles.
- Added copying and pasting of tiles.
- Added undo and redo actions
Using the Control
Painting the map
The TileEditor
control can be used like any other control. The map and tile sizes are simple properties which you can change in design time and runtime. To add spacing between the tiles, you can set the TileSpacing
property to the number of pixels you want between the tiles. To draw the tiles, there is an event called PaintTile
which is passed a TileEventArgs
instance which contains the location of the tile that is being drawn and the PaintEventArgs
instance. You can then paint anything you like; the following example is from the demo which paints the tile image inverted if selected or normally if not selected.
private void TileEditor_PaintTile(object sender, TileEventArgs e)
{
int tile = TileEditor[e.Location];
Bitmap b = (Bitmap)GetTileImage(tile).Clone();
if (e.Selected) {
e.PaintArgs.Graphics.DrawImage(TileEditor.InvertBitmap(b),
e.PaintArgs.ClipRectangle, new Rectangle(0, 0, 32, 32), GraphicsUnit.Pixel);
} else {
e.PaintArgs.Graphics.DrawImage(b,
e.PaintArgs.ClipRectangle, new Rectangle(0, 0, 32, 32), GraphicsUnit.Pixel);
}
}
Editing the Map
To edit the map, you will need to add the MouseDown
event. This is passed the MouseTileEventArgs
instance, which includes the location of the tile that was clicked. You can add code to change the tile in any way; in the demo, there are two selected tiles (one for the left mouse click and one for the right). If shift is held down, it will edit the bottom layer instead of the top layer. For continuous editing when dragging, you will need to do the same code in the MouseMove
event. To make it more efficient, you can record the last tile the mouse is on, and only edit the tile if the last tile is different from the current tile. An example is as follows:
private void TileEditor_MouseDown(object sender, MouseTileEventArgs e)
{
TilePoint pt = e.Location;
if (ShiftDown)
pt.Z = 0;
else
pt.Z = 1;
if (e.MouseArgs.Button == MouseButtons.Left)
TileEditor.SetTile(pt, LeftTile);
else if (e.MouseArgs.Button == MouseButtons.Right)
TileEditor.SetTile(pt, RightTile);
}
TilePoint LastMouse;
private void TileEditor_MouseMove(object sender, MouseTileEventArgs e)
{
TilePoint pt = e.Location;
if (ShiftDown)
pt.Z = 0;
else
pt.Z = 1;
if (pt != LastMouse) {
if (e.MouseArgs.Button == MouseButtons.Left) {
TileEditor.SetTile(pt, LeftTile);
} else if (e.MouseArgs.Button == MouseButtons.Right) {
TileEditor.SetTile(pt, RightTile);
}
LastMouse = pt;
RefreshSelectedTiles();
}
}
bool ShiftDown;
private void Editor_KeyDown(object sender, KeyEventArgs e)
{
if (e.Shift)
ShiftDown = true;
}
private void Editor_KeyUp(object sender, KeyEventArgs e)
{
ShiftDown = false;
}
Obtaining Different Zoom Levels
Zoom levels can easily be done by just changing the tile size. When drawing in the PaintTile
event, it should automatically resize the image or drawing to the size of the tile. It will repaint the whole map when the tile size is changed, so this could take a few seconds.
private void x32ToolStripMenuItem_Click(object sender, EventArgs e)
{
TileEditor.TileSize = new Size(32, 32);
}
private void x16ToolStripMenuItem_Click(object sender, EventArgs e)
{
TileEditor.TileSize = new Size(16, 16);
}
Undo and Redo
Undo and Redo actions can now be easily achieved by calling a few functions. Undos are done in groups of saved tiles, you can create groups and add tiles to them with their saved values and then add the group to the Undo stack. The TileEditor control has several functions for adding tiles to its own UndoGroup which can then be added to the stack instead of creating your own group.
TileEditor.ApplyAndClearUndoGroup();
TileEditor.AddSelectionToUndoGroup();
TileEditor.AddTilesToUndoGroup(new Rectangle(0, 0, 5, 5));
TileEditor.AddTileToUndoGroup(new UndoTile(5, 3, 0, 2));
TileEditor.ApplyAndClearUndoGroup();
In the demo the group is cleared when the mouse down event is called for the tile editor control and is applied in the mouse up event. Tiles are then added to it in the MouseMove event.
Selecting, Copy and Paste
To activate selection for the control do TileEditor.AllowSelect = true;
. Remember to unselect all the tiles when setting it to false. TileEditor.UnselectAll();
You can use the selected flag passed in the PaintEventArgs for the paint tile event to draw a different image or an inverted image to show it is selected. You can retrieve the selected tiles by doing TileEditor.SelectedTiles
which returns a list of TilePoints. To copy the selected tiles do TileEditor.CopySelectedTiles();
. The following code pastes the tiles after adding the tiles that are to be overwritten to the UndoStack.
private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
{
TileEditor.ApplyAndClearUndoGroup();
TileEditor.AddTilesToUndoGroup(TileEditor.PastingSelectionArea);
TileEditor.ApplyAndClearUndoGroup();
TileEditor.PasteSelectedTiles();
}
Known Bugs
- Large maps. At the moment, an image of the whole map is stored so that the control can achieve fast painting, so you may get an 'Out of Memory' error if the image is too large.