Skip to main content

Heavy Loaded Head

Most games work best when you have more than one level, but ip until now that's all I've had - one level. Even worse, that level has been created directly from code written into the game itself - to change it I have to rewrite the code. What I need is data driven level loading - the levels should be defined by a data file.


In this post I will be defining a level format and writing code to load it into the game. Let's start by talking about how the data will be laid out..

Level Data

I'm going to be loading the levels from JavaScript objects. I started off my defining what I wanted a level's data to look like:


Hopefully that's pretty easy to understand. There's some meta-data about the level itself (name, etc.), a type, a version and then a list of objects. The type just makes it easy for me to check that I'm looking at the right kind of data, and the version means that if I make changes to the data format in the future I can detect old versions and handle them appropriately - probably by upgrading them. The main part of the level data is the objects list. Inside this list you can see an array for each type of game object that can be loaded: player, spawners and zappers. Bullets aren't included as objects that I want to load, so they're missing from this list. Inside each of these object lists is an array of object data, and each entry in that array includes entries for all of the objects properties. This data is the configuration for each individual object and is passed to the object's constructor.

The code to load all of these objects into the Object Manager is pretty simple. I walk through the list of object types, going inside each list and pulling out the configuration object inside and using them as arguments to construct new objects of that type:


Validation With Schema

When it comes to loading user generated data, you absolutely need to be able to validate it before you use it - you simply cannot trust data that comes from outside of your control, you should even be pretty careful about data that you do control. I'm going to load the data as JavaScript objects, so the easiest way to validate it is by using a JSON schema. Creating a JSON schema is a fairly tricksy topic, so I won't go into it in depth here, but suffice it to say that you can define what your data format looks like in a schema (what properties it has, what the allowable values are, etc.) and then use that to validate data against. Data will either pass the validation check, and then you can trust it, or it doesn't.. and then you can't. In the game, users will be able to edit levels via an in-game editor. This should guarantee that the data is always in the correct format anyway, but it's safest to not rule out that someone may somehow manage to upload tainted level data, or maybe just in an older format. I need to be able to spot such bad data and handle it.

Just for "fun", here's what the JSON schema for a level looks like:


This looks fairly complex - and it is. You might guess that it's hard to create such a schema - it is. Luckily, the code generates most the schema for me. I added a function to each object type to retrieve the properties from each object type. Here's the zapper's function:


A neat by-product of this is that I can define default values for each of these properties, then I can automatically generate a default config for each object type. This will come in handy when it comes to creating new objects in the level editor.

Validating Data Against The Schema

If defining the schema is hard, validating your data against it is even harder. Luckily, since JSON schema is quite popular there are some good libraries around to handle this for you. I settled on using the JSEN library - it's easy to integrate with my code and it's easy to use. Here's how I use it in the level loading code:

You can find out more about JSEN here.

Wrapping Up

I defined a level format, used a schema to validate levels against this schema and wrote code to load levels into the game.

The full code is here and the game can be played online here.

Next Time

Now that I have a well-defined level format and I can load levels from data rather than hard-coding them in the main code, I'm one big step closer to letting players create their own levels. Next time I'll start on some simple editing tasks - maybe just selecting and moving existing items with the mouse. If it's not too much work then I will add saving too, otherwise that can wait until a future post.



Comments

Popular posts from this blog

Set The Controls For The Heart Of The Sun

When we last met, I had just started work on a level editor. I'd got as far as adding the ability to select an object and move it around, and then I added an undo/redo system using the command pattern. That was a good start, but dragging items around the level is only fun for so long. What I really want to be doing is.. ..editing the properties of the bullet spawners! And I want to be doing this in realtime as the game plays so that I can immediately see what effect my changes have made to the gameplay of the level.

World In Motion

In the last post I touched on how easy it is to score in this game - you can just camp out on the score bullet spawner and watch the points rack up. I'm going to add a little delay to the score bullets so that they start out in a deactivated and uncollectable state, and then change to active and collectable after a short time - say, half a second. To make it clear what state they are in I'm going to add code to let me change the look of Objects and allow them to be animated.

The Long And Winding Road

I started this blog back in November of last year. My aim was to document the development of a Bullet Hell shoot-em-up, written in JavaScript. Here we are, six months later, and lots has happened. With 20 posts already written, I thought that now would be a good time to take stock of what I've already done, and to look to the future and see what's to come.