More levels for Machines vs. Machines

You wish! But no, this isn’t me announcing more levels. Instead, let me tell you how you can create some. But first, if you don’t know what Machines vs. Machines is, check out here.

Machines vs. Machines

If you have some graphics skills and know your way around with copying files/folders between your PC and the phone, it’s really straight forward to create a new level pack. No need to touch a single line of code. And this is how it’s done:

First check out a copy of lp:machines-vs-machines/levelpacks. In there you’ll find the existing level pack. Create a new sub-directory for your level pack, for example “my-first-level-pack”. All the files for your level pack should be inside this directory. The first step is to create a levelpack.json file. This file holds some basic description about your level pack. It holds the pretty formatted name, a file name for the title image, a copyright notice and the file name for the title sound:

{
"name": "My first level pack",
"copyright": "My full name",
"titleImage": "some-image-file",
"titleSound": "some-sound-file"
}

Place the image file in the same directory as this json file. The sound files instead are collected in the sounds folder.

title image for your level pack

In order to create levels you need to define some towers and enemies first. Let’s start with some enemies. Create a sub-directory called “enemies” containing a text file named “enemies.json”. Here is an example for its content:

[
{
"id": 1,
"speed": 0,
"energy": 10,
"reward": 5,
"image": "enemy-1",
"spriteCount": 1
},
{
"id": 2,
"speed": 1,
"energy": 15,
"reward": 10,
"image": "enemy-2",
"spriteCount": 8
}
]

This example file describes two enemies with different properties. The first enemy is a static image, it moves at the lowest speed and doesn’t stand many hits. It gives 5$ reward when defeated. The second one however, is an animated one, it moves a bit faster, is stronger and is rewarded with 10$. “image” holds the file name of the image file containing the enemy artwork.

Lets look at the contents of the image file: All images need to be in SVG format and should be readable by Inkscape as this will be used to generate png files in the end. All image sizes are defined by a base size of 256×256 pixels. If your image is a static image, it needs to have a page size of 256×256. For an animation with, lets say 5 frames, you need to set the page size to 5 times 256×256 squares, aligned in one row. This means the total page size needs to be 1280×256 pixels.

Set the “spriteCount” property to the amount of frames in your animation. To define the speed of the animation, additionally set the “animationDuration” property.

An enemy with different perspectives

Optionally, for enemies you can add different perspectives. If you want your enemy to look different whether it’s walking left or right, up or down, add up to 4 rows, containing single images or an animation sequence. The rows will be taken in this order: left, right, front, back.

An enemy with different perspectives

Lets move on to the towers. Those follow the same basic rules as enemies, but have some more different properties to tweak. Here’s the example:
[
{
"id": 1,
"name": "Standard Tower",
"locked": false,
"unlockPoints": 0,
"configs": [
{
"image": "tower-1-lv-0.png",
"shotImage": "tower-1-shot.png",
"shotSound": "tower-1-shot.wav",
"shotCenter": { "x": 128, "y" : 90 },
"shotStartDistance": 90,
"damage": 1,
"radius": 1,
"slowdown": 0,
"shotDuration": 200,
"shotRecovery": 600,
"cost": 10
},
{
"image": "tower-1-lv-1-sprite",
"spriteCount": 4,
"shotImage": "tower-1-shot.png",
"shotSound": "tower-1-shot.wav",
"shotCenter": { "x": 128, "y" : 90 },
"shotStartDistance": 90,
"shotDuration": 200,
"shotRecovery": 500,
"damage": 1,
"radius": 1.3,
"slowdown": 0,
"cost": 5
},
{
...

Each config section describes an upgrade of a tower. If the player builds a tower, he’ll get the first config, upgrading the tower once will move on to the second config and so on. You can have as many upgrades for a tower as you wish.

Note that towers can have different shot types. You’ll find examples for all of them in the existing level pack. Note that the shot type has an impact on how the animation is played. This is probably the trickiest part and requires a bit of fiddling with the values to make it look good, but it offers a lot of different ways to model a tower and it’s capabilities.

The images work the same as for the enemies. You paint each animation frame in a 256×256 square and place them in a row.

A tower

You’ll need a different image file for each tower config. If you don’t want to change the look when a tower is upgraded, you can give the same image for multiple configs though.

Additionally you’ll need a shotImage. This needs to be a 64×64 pixel sized svg. For example:

A shot image for a tower

Make sure to continuously check the existing level pack. Many things for towers can be tweaked with properties that I can’t all list here. For everything that the game engine supports you’ll find and example in there.

Now, let’s create the first level. For each new level, create a sub-directory. Those sub-directories need to be named “levelX” where “X” is to be replaced by an increasing number, starting at 1. Each level directory needs to hold a file called level.json. The contents are as follows:

{
"startMoney": 150,
"rewardPoints": 20,
"board": {
"rows": 5,
"columns": 10,
"fieldsOnPath": [31, 41, 42, 43, 44, 34, 24, 14, 15, 16, 26, 36, 37, 38, 39, 29, 19],
"forbiddenFields": [0, 1, 10, 11, 12, 20, 21, 22, 30, 32]
},
"waves": [
{
"interval": 2000,
"enemies": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]
},
{
"interval": 1000,
"enemies": [1,1,1,1]
},
{
"interval": 1000,
"enemies": [1,1,1,1,1,1,1,1]
},
{
"interval": 1000,
"enemies": [1,1,2,1,1,2,1,2,1,1,1]
}
]
}

Let’s have a closer look at the properties. Start off with setting the start money and the reward points. The reward points will be given to the player when completing a level. They’ll be distributed depending on how many lives the player has left. Defining the board, you first set the amount rows and columns your field should have. FieldsOnPath is a list of fields where the enemies will walk along. They’ll follow the fields in the specified order. Make sure you specify fields that are next to each other.

Now the interesting part. Grouped into waves, you list the enemies that should walk across this level. The numbers point to the “id” in the enemies.json file. The interval specifies the time delay between the enemies entering the field. The reference is when playing on hard. For medium and easy, the interval will be made bigger by the game engine. So make sure you test your levels in “hard” mode to get the proper feeling.

Last but not least you need the background for the level. The graphic should reflect the path you defined in fieldsOnPath. To calculate the size for the image, use “columns” by 256 for the width and “rows” by 256 for the height. This will be the area that’s most visible to the player. However, the image should be bigger, double its size and fill the empty space around it with some neutral background. This will only be visible when the screen size doesn’t match the 256×256 concept and when zooming in on the level at the beginning. Here’s the example image:

That’s it. Your first level should be ready. Now you just need to compile it. For that, get a copy of lp:machines-vs-machines and copy your level pack into the data/levelpacks/ folder. Then execute ./setupdata.py in the data directory. This will generate a ready to use level pack in the lpbuild folder. You can copy that folder into the data directory of an existing Machines vs. Machines installation, or build the game from the source you just checked out and run it in place.

If you create a level pack you can then build your own game package if you want. If your level pack is of decent quality, I’ll be happy to accept it into the official repository and publish it with an update of Machines vs. Machines.

And remember, hard is supposed to be hard.

This entry was posted in Ubuntu. Bookmark the permalink.

10 Responses to More levels for Machines vs. Machines

  1. Kugi Javacookies says:

    Cool! It’ll be cooler if we can download user created levels within the game or share our own.

    Also, hard is supposed to be hard….I agree
    but Level 1 should be the easiest and it is not the case in this game!
    not that I’m complaining,it’s actually the opposite. Keep up the good work! :)

    • Michael says:

      Yeah, I already thought about some mechanism to share levels. Let’s see if I find the time to create something.

      And Level 1 is really not *that* hard :D

  2. gorn says:

    Thanks for great addictive game.

    Finished medium, now struggling with Hard level 1. It IS hard, or I overlook something. Currently my last hope is some sort of dynamicall rebuilding of towers, but it drains economy quite fast.

    • Michael says:

      It is quite hard, yes. However, Level 1 really not is *that* hard yet. You just need to find the right spots :) For Level 1, try putting them into the center row…

  3. velo says:

    Hi Michael,
    thanks for the greate game! I’m nearly there (4 stars missing on hard)…
    There is a cute little glitch hidden in http://bazaar.launchpad.net/~mzanetti/machines-vs-machines/trunk/view/head:/backend/modules/Machines/engine.cpp#L456

    ...
    if (m_lives == 0) {
    ...

    Don’t know, if you hid/did that on purpose, though…

    Nevertheless, this game is really one of the better things on current UT,

    — Cheers!

    • Michael says:

      Not sure what the problem is. Can you explain please?

      • velo says:

        Okay sure ;)
        It is possible (I cheated my way through some of the hard levels that way :o ) to get past 0 lives by triggering some concurrent action (for example the pause button) the very moment the livesChanged() is emitted.

        Once m_lives is below 0, the if-condition is never met again and the level just continues with m_lives=-1, m_lives=-2 and so on.

        Actually, I have not looked at the entirety of your code and sure have not understood it thoroughly. My explanation here is solely based on the observed glitch (surviving a level with negative lives) and glancing over the sources quickly, looking for that exact line.

        Disclaimer aside, I believe if you’d change that line to:

        if (m_lives < 1) {

        that glitch would be no longer exploitable (so easily), because it would then just fire with the next enemy entering the heart.

        Well…now that I wrote all that, I’ve come to the conclusion that it probably still would be exploitable by using pause on every other enemy for every remaining wave. But that at least would require a lot more timing skills than just getting it right once ;)

        Please let me know, if you have a nicer fix for this!
        HTH!

  4. Sleep_Walker says:

    This game is driving me crazy.

    Easy difficulty is good, medium was tough, especially levels 25 (finished with all stars after 4 days) and 26 (still a star missing). I don’t have all stars for any level for difficulty hard.

  5. Tomek says:

    Can anyone tell me where can I find the file that stores the level progress and will let me play on two devices? If I lost my phone or the tablet breaks down I’ll have to start all over again. I need to backup my progress somehow.

Leave a Reply

Your email address will not be published. Required fields are marked *