Sign in to follow this  
Bent

A Level Editor Experiment (w/code)

Recommended Posts

A while ago in one of the streams someone asked if Massive Chalice would actively support modding. The answer was probably not considering a number of factors including the fact that the level editor being used at Double Fine is Maya.

I began to think about what a level editor for modding Massive Chalice might look like. I ended up creating a proof of concept based on my designs. The following details what I came up with.

The Requirements

A theoretical level editing system for use by end users has a number of requirements. It must be:

1. Cheap – A level editor for end users is not a primary or even secondary development priority. Its cost to develop must be minimal so that it doesn’t take up funds that could be used on things that are more important.

2. Discrete – It must be separate from the actual game so that its development doesn’t impact the development of the game (e.g. so it can be cut if need be without much fuss.).

3. Understandable - A level editor for end users need not be a powerful as Maya but it must be straightforward to learn.

4. Dual Purpose - A custom level editor should not only useful to end users but also to developers for quickly prototyping levels.

5. Extendable – A requirement for making a level editor useful for prototyping is that it should be able to be adapted to a variety of situations.

An Idea for a Solution

An easy way to develop something cheaply is to adapt things that already exist. This is where Tiled comes into play. Tiled is an awesome free program for creating 2D tilemaps. By using Tiled as a front end the cost of creating a level editor significantly decreases.

The crux of my design for an end user level editor is that the 3D components of a grid based game map nicely to a 2D tilemap. The following video shows this principle in action:

For example, this:

9cs7.png

becomes this:

u9m2.png

The idea is that the game would come with a predefined Tiled-compatible tileset so that users could then create a tilemap using Tiled and then run a separate map generation utility included with Massive Chalice to mung the necessary components together to create a 3D map.

Given how specific a map generation utility would be to the Massive Chalice engine I was unable explore that aspect of the level editor. Instead, I focused on how 2D tilemaps can be mapped to arbitrary data and how that is useful for prototyping.

TileUtils

TileUtils is the name of a package of Python modules I created to take a tilemap created with Tiled and translate it into useful data.

The type of data an individual tile can be translated into is only limited by what can be stored as in an element in XML. An XML translation table is what associates a 2D tile with useful data.

How It Works

The key to how TileUtils works lies in two files:

test.tsx:



<?xml version="1.0" encoding="UTF-8"?>













































test.ttt:



<?xml version="1.0" encoding="UTF-8"?>









../Objects/standard/blender/rampOneOne/pixen/rampOneOneL.blend/Object/rampOneOneL















../Objects/standard/blender/rampOneOne/pixen/rampOneOneU.blend/Object/rampOneOneU









../Objects/standard/blender/rampOneOne/pixen/rampOneOneR.blend/Object/rampOneOneR









../Objects/standard/blender/rampOneOne/pixen/rampOneOneD.blend/Object/rampOneOneD









The first file is an example of tileset created with Tiled. Each tile in this tileset has a unique name associated with it through the use of a property element.

The second file is a tile translation table (.ttt). A translation table is how useful data is associated with a 2D tile.

The parts of a translation table are as follows:

defaulttranslations – An optional section that is searched for a tiletranslation if one is not present in a tilesettranslation for a given 2D tile.

tilesettranslations – This section contains all of the tilesettranslation sections.

tilesettranslation – A tilesettranslation contains all of the tiletranslation elements for a specific 2D tileset.

tiletranslation – These associate useful data with a particular 2D tile. Each element in the values section (e.g. blenderObjectFromScene) is a translation type. Translation types hold the actual data associated with a 2D tile and there can be multiple translation types contained in a tiletranslation. The possible translation types and the format of the data they contain is not defined by the translation table standard. For example given the following tiletranslation for the 2D tile named “rock”:








objectName="bigrock",polyCount=10000

objectName="bigrock",polyCount=5000



if “rock” were to be translated using the translation type of "highpoly" the translation would yield the string “objectName="bigrock",polyCount=10000”. Whereas if the "lowpoly" translation type is used the result would be the string “objectName="bigrock",polyCount=5000”.

Creating Translation Tables

As the development of TileUtils progressed the importance of being able to easily create translation tables become apparent. TileUtils contains several scripts (see: Utilities) that ease the process of translation table creation. Translation tables can be generated from directories (see: dirttt.py) and be created and/or modified using a spreadsheet (see: tttcsv.py, csvttt.py).

Share this post


Link to post
Share on other sites

Producing Output

tileplacer.py is a utility in the TileUtils package that translates a tilemap using a specified translation table and translation type and then uses the translated data to produce output.

tilepacer.py produces different output based on the translation type and environment specified. Currently tileplacer.py has support for the following environments:

1. Blender – The 3D examples in the An Idea for a Solution section were created with this environment.

2. Terminal – Data from the translated tiles is printed to the terminal.

tileplacer.py also has theoretical support for Maya using the maya.standalone module but since I don’t have access to a copy of Maya the code has never been run and is unlikely to work.

tileplacer.py can easily be extended to support additional environments/translation types (see: tileplacer.py in Utilities).

Remaping

Remapping is the process of redefining what the 2D tiles in a tilemap mean.

tileplacer.py explicitly supports the remapping from one tileset to another. For example given the following translation table:


<?xml version="1.0" encoding="UTF-8"?>









Wooooo















Blarg









Drat









Dang













Yes









Sweet









Tubular









Before Remap:


tileplacer.py mymap.tmx mytable.ttt text --env terminal 



layerNumber: 0 x: 0 y: 0 data: Blarg

layerNumber: 0 x: 1 y: 1 data: Drat

layerNumber: 0 x: 25 y: 6 data: Dang

layerNumber: 0 x: 30 y: 20 data: Wooooo

After Remap:


tileplacer.py mymap.tmx mytable.ttt text --env terminal --remap tileset_one tileset_two



layerNumber: 0 x: 0 y: 0 data: Yes

layerNumber: 0 x: 1 y: 1 data: Sweet

layerNumber: 0 x: 25 y: 6 data: Tubular

layerNumber: 0 x: 30 y: 20 data: Wooooo

5 Ways To Remap Tiles

There are several ways to remap tiles using TileUtils.

1. --remap

Use the --remap option for tileplacer.py to remap one tileset to another.

2. New Translation Table

Create a translation table that specifies different data for a given translation type.

3. Use Defaults

Create default translations for each tilename. Then incrementally add tilename entries in the tilesettranslation section as development continues.

4. Use Links

Use the --link option to tell tileplacer.py to, when possible, create links (a.k.a. references) instead of importing objects. This technique means that the translation table stays the same but the 3D map changes as objects the it is created from change.

5. Use Translation Types

Use different translation types to give a 2D tile different meanings.

Workflow

When using TileUtils to prototype 3D levels the general workflow would go something like:

1. Create a tileset

2. Name the tiles

3. Create dummy objects.

4. Create a translation table that maps the tileset to the dummy objects.

5. Prototype maps.

6. Remap tileset.

Typically, steps 1 - 4 would only need to be done once whereas steps 5, 6 would be repeated multiple times.

The Utilities

dirttt.py

dirttt.py [-h] [--csv] [--env {default,blender}] [--errors]

[--nodefaults] [--save SAVE] DIR

A utility used to generate a translation table from the contents of a directory tree. The name of the directory DIR is used as the name of the translation table. The names of the directories contained directly in DIR are used as the names of the tilesets with the exception of the directory named DEFAULTS which, if present in DIR is used to generate the defaulttranslations section of the translation table. The names of the directories directly in the tileset directories are used as the translation types present in that particular tileset. The translation type directories are then recursively searched and any non-directory files found are (possibly) used to generate tile translation values. The names of the files found are used to generate the names of the tiles and the content of the files is used to create the translation values.

If --save is used the data generated for the translation values is created relative to the directory that file SAVE is in. This is differs from the default behavior of creating the generated data relative to DIR.

dirttt.py can be extended to support new environments and/or translation types by subclassing TileTranslationCreator and registering an instance of the new class with the directoryConverter object.

csvttt.py

csvttt.py [-h] [--save SAVE] CSV

A utility that converts a translation table in csv format to ttt format.

ertileplacer.py

ertileplacer.py [-h] [--env ENV] [--link] [--nodefaults]

[--remap REMAP REMAP] [--save SAVE]

[--steps STEPS STEPS STEPS]

commandwithargs tilemap translationtable translationtype

A wrapper used to run tileplacer.py (see: tileplacer.py) using a custom command in Tiled.

tileplacer.py

tileplacer.py [-h] [--env {blender,maya,terminal}] [--link]

[--nodefaults] [--remap REMAP REMAP] [--save SAVE]

[--steps STEPS STEPS STEPS]

tilemap translationtable translationtype

The main script of the TileUtils package. tilepplacer.py translates a map and uses the translated data to produce output. What ouput is produced depends on the environment type and type of translation.

tileplacer.py is a versatile script and depending on the environment type may be run from the command line or by an embedded python interpreter (e.g. Blender).

If the environment variable TILEPLACER_ARGS is set tileplacer.py will look there for its arguments rather than the command line.

tileplacer.py can be extended to support new environments and/or translation types by subclassing EnvironmentSetter and/or StandardPlacer and registering instances of the new classes with the tilePlacer object.

tttcsv.py

tttcsv.py [-h] [--save SAVE] TRANSLATIONTABLE

A utility that converts a translation table in ttt format to csv format.

The Code

There is too much code to post here but it is available on github (https://github.com/PaulWGraham/TileUtils).

Share this post


Link to post
Share on other sites

Bent this is so awesome! The way that we're currently talking about the levels they are going to be pretty hand-crafted, but I like the idea of having a simple tool that would let us whitebox the crap out of levels very quickly. If we had something like this it would even let community members submit layouts that they think would be awesome. Let me show this to Chad and company! :D!

Share this post


Link to post
Share on other sites

Brad,

I've sent you both a PM and an email under the theory that it's not spam if it's ham*.

-Bent

* Though sometimes they taste the same to the person sending them.

Share this post


Link to post
Share on other sites

I am always fond of the idea of more maps and diversity. One of the things that bugged me about new X-Com was the maps. Obviously only so much can be created for a game, but the maps started to feel stale after a while---especially since you always started at the same location I think for any given map, instead of say at one of 3 or 5 or x possible spawn points.

I look forward to seeing what MC Team can come up with in terms of maps and any possible tools associated with them.

Smiles

Share this post


Link to post
Share on other sites

Update:

Considering that there is a chance that my code might be seen by other actual humans I added some documentation to the repo.

I added test.tsx, test.ttt and associated files to make it easier to experiment with TileUtils.

And I bumped the TileUtils package version to 0.0.2 due to some bug fixes.

Share this post


Link to post
Share on other sites

My best mate's the one doing programming, so I'll have to ask him if I want to understand any of this, but those pictures at the top look awesome! Obviously the team would be aiming to get a more handcrafted feel to the maps, but I'm just wondering if it would be possible to have both options? What I mean is that the team use advanced methods of putting together maps, but a tool in this vein be integrated and released to the community? Issues I can already see with that could be the extra programming to get that in place and a large drop in quality from DF maps to community maps. Then again, I'm always astounded by what other people can put together with the simplest of tools, so I could be pleasantly surprised.

btw, Bent, this is ridiculously cool. It'd be awesome to have some sort of talent that could be as useful to the game as this, imagine getting the finished product and seeing an idea that you created make it in!

Share this post


Link to post
Share on other sites

@Leo99999:

The best way to explain what is happening in the video above is to use Legos. Imagine that you're planning to build a structure out of Legos so you get some graph paper and start coloring in squares, each color you color the squares represents a different type of Lego brick and each sheet of graph paper represents a different layer of the structure.

I realized that the same kind of setup could be applied to grid based games like Massive Chalice or XCOM. So I wrote some code (TileUtils) that wired the graph paper (Tiled) to the Lego bricks (Blender).

Share this post


Link to post
Share on other sites

Update:

I've added experimental.tsx, experimental.ttt and associated .blend files to the repo. experimental.tsx looks like this:

un97.png

(full size)

Using experimental.ttt with translation type of blenderObjectFromScene every tile in experimental.tsx translates to a 1x1x2 cubiod.

experimental.tsx represents a move away from standard.tsx (which was tailored to XCOM style terrain elements) toward a more generic tileset.

The final list of terrain types (swamp, water, goo, etc.) for Massive Chalice is not publicly known. It is possible that the final list of terrain types is still undefined. The rational behind experimental.tsx is that since the meaning of tiles is assigned with a translation table and a map, if need be, can be translated using a unique translation table assigned only to that map, for any given tilemap it doesn't matter what iconography/tile translates to what 3D terrain element so long as the usage within that tilemap is consistent.

This setup allows a designer to decide to assign a terrian type (or any other game element that fits to the grid) to an arbitrary tile. Add a large generic tileset (i.e. experimental.tsx) to this scheme and designers can start to prototype using new (and as yet undeveloped ) terrain elements without having to wait for a specific tile to be created and added to the de facto tilesset.

If at some point in the future a standerd tileset is created the tile maps created using experimental.tsx can be converted algorithmically.

Share this post


Link to post
Share on other sites

Update:

Added new tiles to experimental.tsx.

Added brown background to all grounps of tiles in experimental.tsx

sn9j.png

Added utility tilenames.py

tilenames.py

Displays the names of the tiles in a tileset.

Added utility createtmrc.py

createtmrc.py

A GUI front end for tileplacer.py.

ccpu.png

auhx.png

createtmrc.py represents a move away from command line based utilities by TileUtils. createtmrc.py allows for the creation/modification of TMRC files. TMRC files store all of the information needed by tileplacer.py to translate a tilemap. createtmrc.py along with a GUI translation table editor (in development) and a replacement for ertileplacer.py (in development) should allow a designer to be able create and translate a tilemap without having to leave Tiled.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this