I have one month to make an MMO: Day 5
Woah, slow down cowboy. I just did another 14 hour day, this is in addition to the 4 hours yesterday that was supposed to be my day off. Whoops.
In the below chart “content” stands for content generation, this would include things like making maps, art, dialog, etc. In this case, the tools needed to parse and upload maps are also related to “content”.
Not surprisingly, I got a whole lot done, putting together the actual pieces of the map that players will be able to walk around in.
Tiled
As mentioned in the plans from yesterday, I’m using Tiled, an excellent open-source tile editor. I’ve fallen in love with this software, it’s chocked full of features that are useful for a project like this. Come, let me walk you through some of them, and why I’m jazzed to use them.
Infinite maps
Creating a new Tiled project, there is an incredibly tempting radio button that says “Infinite”. I mean, who doesn’t want infinite?
A fixed-size Tiled map has a certain number of tiles wide and high, and the coordinates start at 0,0 in the top-left corner. When you make an infinite map however, things get interesting: you can now place tiles to the left, and above the origin, meaning tile indexes can go into the negative numbers; but more interestingly, Tiled no longer stores your map as fixed-size array of tiles, it cuts your map up into 16x16 tile chunks. This turns out to be perfect since I planned on doing chunk-loading anyway. It saves me from having to chunk up the map myself.
Terrains
Tiled has a concept of “terrains” which are akin to Autotile. Terrains allow you to paint different ground surfaces, and have Tiled automatically select the best corner/edge tiles to merge the two ground terrains.
But what I really enjoyed was how Tiled allows you to quickly define the terrains — you select the Terrain you want to define, then you can mark tile corners to indicate which corners of this tile are of that terrain. Tiled handles the rest and automatically selects the best tile to use from your defined . What’s more, when you have multiple options for a tile, Tiled will randomise it, giving your map more natural-looking variation.
Tiled’s normal autotile works as expected too, and feels slightly nicer to use compared to GM’s autotile. Tiled also supports autotile between three sets, rather than just two.
Layers and Stamps
For those familiar with GameMaker, Tiled Stamps works a lot like tile brushes, but they’re just a lot more nice to use, being able to easily select and turn a batch of tiles on the map into a Stamp. Stamps also support randomization, so you can define a few variants, and have the stamp automatically decide on variations for you.
The file format
Tiled stores its data in a reasonably well document XML format. This means we can parse it, and we can be reasonably sure we aren’t doing something weird to the data.
The XML format also makes it much much easier to upload and track changes in git, since git can efficiently diff the changes. Aside from the map format, I’m also able to keep the tilesets in their own separate .tsx file so they (and their autotiles and terrain settings) can be shared between Tiled projects easily; the Stamps are stored too a .stamp files in the project directory.
Everything is just nicely thought out and a pleasure to work with.
Jupyter lab
Aside from quickly throwing together a bare-bones starting area with which I can test the game client, I’ve also written a Tiled project parser in python, which is able to read all the tiled data, do some re-formatting to make them more friendly to use in a GameMaker project, and upload the map data to a database.
To write this parser, I switch over from the usual command-line python running to Jupyter Lab. For those of you who write python but haven’t ever heard of Jupyter before, you need to stop what you’re doing and… wait no, don’t stop reading just yet, finish this blog post and then go check it out. Jupyter is best destribed as a a live programming environment that works really well with Python (it supports other languages too).
A common thing people do when writing interpreted languages is to use a text editor; and then when they’re ready to test, drop to a command line and run the interpreter. Then check the errors, and go back to the text editor to continue editing. More advanced users may have python drop to an interactive shell when an error occurs, and inspect variables to check their values (an interactive shell is one where you can type commands for python to interpret).
However, Jupyter changes all of that. Jupyter provides a browser-based environment that lets you execute your blocks of code in any order, inspect variables, edit and re-run specific blocks of code, and to boot, a lot of graphing and graphics libraries can output images directly in the browser output, making it ideal for data analysis projects, but also great for any time you have a complex python script to put together and need a lot of testing and probing to get right.
Without Jupyter, writing python is far slower. I recommend it for everyone who touches any python at all. Including professional snake wranglers and zoo keepers working in the reptiles department.
Tiled parser and uploader
The job of the parser is to take Tiled’s raw project files, pre-process them into a format that’s easy to deal with in GameMaker later, and upload them to a database. Fortunately, I’ve already built both parsers and GameMaker tile display runtimes before, so I’m coming at this already with ideas in mind on how the data should look, and what the storage format is.
The main trick is that Tiled pools all the tiles from all the tilesets in the project into a single tile value. This means for example tile values from 0–1000 might be from one tileset; and 1001 to 2000 might be from another.
In GameMaker doesn’t do this, and so we have to translate Tiled’s single tile value into a pair: the specific tileset, and the index of that tile on the tileset. It’s also necessary to translate the tile rotation/mirror bits, as GameMaker and Tiled use slightly different values for these.
I won’t bore you with the details, but the results look something like this:
You can see the 8 world chunks pop up into the database as the parser runs.
This python script is run manually for now, but it can quite easily be attached to either a git hook, or even handled by a CD service that’ll trigger the python script to run every time someone pushes updates to the map using git.
The Art
The art assets I’m using is an asset pack by FinalBossBlues (Jason Perry). After consulting with a fellow game dev, and possible artist for the game, I’ve settled on a 16x16 tileset, and Jason’s work fits the bill (for now). I happen to also support Jason on Patreon, go check him out.
The idea here is to pick a tileset and just start creating, rather than be bogged down at this stage with having to produce art. The sprites can be edited and replaced later if need be, and it becomes much easier to produce the sprites needed when an artist can take a look at the exact set of tiles actually used in the game, rather than try to figure out what tiles are needed from scratch.
Day 5 Task summary
My bumper 14 hour day has seen me bulldoze through four points of tasks, which in theory should have cost 2 days, or 16 hours. So this is about right. I’ve just worked more than I should have in one day. I feel like I shouldn’t make a habit of doing this, I’ve burned out so many times in the past from overwork, I know I’m liable of doing it.
The next tasks now that tiles are online, is to write the tile server component, that grabs the tile data out of the database and pushes it to the player client; and to have the player client be able to load and display these tiles. Those seem like complex tasks, but I’ve got some GameMaker tile loading code from before, so I’m confident this won’t take long.
Still, I’d better watch out for burnout. I may need to force myself to reduce my work hours tomorrow as a preventative measure.