War is over…

May 10, 2012

Because of other projects (like this one if you’re curious) I have completely lost track of TinkerTanks for months. When I came back for the first time after long I noticed that my web host had disappeared, so the site is no longer online.

I still have that code lying around somewhere, but since I am the only player of the game and I am prone to distractions enough as it is, I am not gonna bother putting it online again until somebody explicitly asks me to 🙂

This blog I’ll still cherish, if only to reminisce in my own coding / gamedesigning journey!


Showing this to Helen

February 13, 2011

Hi Helen!


Allright: single-player campaign has arrived!

January 3, 2011

… I am quite excited about this because it has been on my to-do list for like a year, and also I think the absence of this feature is the main reason nobody ever stays on Tinker Tanks longer than 3 minutes. I am talking about a single player campaign of course.

So you start with an easy level and some basic instructions, once you finish that you see some new instructions to guide you with the next level etc … After all, you wouldn’t play something Red Alert or Age Of Kings in multiplayer right away would you? (No you wouldn’t, because William Wallace rocks :-)).

Two other tweaks in the code also made campaigns a bit better:

  • Bots do not move so unreasonably fast anymore if they have only few units. (this made it really hard to beat a bot, especially if you are not used to the ‘speed matters’ principle)
  • I can now edit existing maps in the map editor, so it is easy to make small tweaks to campaign levels based on how they feel. This was long overdue anyway.

Here are the first few ‘episode intro’ panes. First you get introduced to ‘moving and attacking’ and ‘ending a turn’:

Then we proceed to the rock-paper-scissors principle, how it is important to be aware of each unit’s different strengths and weaknesses relative to one another:

… Then there’s earning money and buying new units:

There’s more, but I do not want to give everything away of course, so you’ll have to go play the game to find out 🙂


Combining multiple images using PHP (and GD)

January 3, 2011

I made a rather quick&dirty script to do automatically combine many images into one – saves a great deal of time in showing maps! I used to take screenshots manually until now, crazy I know.

Now, since this is the kind of thing I typically stitch together after googling and then getting the info from blog posts of kind people, I thought I’d give back for a change.

The most common application of combining images with PHP is adding a watermark to a picture. I had to do a little bit more than that though, namely stitching many identically sized images together on one ‘background’. In essence I am combining 144 of these:

… into something like this:

So basically we will be putting many different images all together on one big ‘canvas’ image. If you need to do that for some reason, read on to find out how.

Note: you need to have the GD module for PHP enabled or the functions used will throw ‘undefined’ errors. Run a php script that has phpinfo() to find out if you have GD installed yet. If not, here is some more info on GD.

Anyway, here’s (a slightly simplified version of) my code to combine many images into one.

Step 1: get an array with source image locations

This step is different for anybody, but in its easiest form you would define something like this:


$srcImagePaths = Array('https://diceattack.files.wordpress.com/2011/01/tile_e_o_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_e_g_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_e_b_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_b_q_fh.png');

Step 2: define some measures and initialize a blank ‘background’ image

Here we use the first GD functions: imagecreatetruecolor() creates a generic ‘base’ image, imagecolorallocate() to define an RGB color and imagefill() to fill our generic image with that color.


$tileWidth = $tileHeight = 28;
$numberOfTiles = 12;
$pxBetweenTiles = 1;

$mapWidth = $mapHeight = ($tileWidth + $pxBetweenTiles) * $numberOfTiles;

$mapImage = imagecreatetruecolor($mapWidth, $mapHeight);
$bgColor = imagecolorallocate($mapImage, 50, 40, 0);
imagefill($mapImage, 0, 0, $bgColor);

Step 3:  think at which coordinates you want your source images to end up

There are some different ways to specify this, but if you are dealing with many images of the same size it makes sense to write a small function that maps an (array) index to a set of X,Y coordinates. Here is mine which arranges them all in a 12×12 square grid:


function indexToCoords($index)
{
 global $tileWidth, $pxBetweenTiles, $leftOffSet, $topOffSet, $numberOfTiles;

 $x = ($index % $numberOfTiles) * ($tileWidth + $pxBetweenTiles) + $leftOffSet;
 $y = floor($index / $numberOfTiles) * ($tileWidth + $pxBetweenTiles) + $topOffSet;
 return Array($x, $y);
}

Step 4: loop over the source images and copy them on the base image

We use function imagecopy() to do this, like this:


/*
* COPY SOURCE IMAGES TO MAP
*/

foreach ($srcImagePaths as $index => $srcImagePath)
{
 list ($x, $y) = indexToCoords($index);
 $tileImg = imagecreatefrompng($srcImagePath);

 imagecopy($mapImage, $tileImg, $x, $y, 0, 0, $tileWidth, $tileHeight);
 imagedestroy($tileImg);
}

… Note how we used the indexToCoords() function in there – we do not want all the source images on the same position of course.

Step 5 (intermezzo): resizing an image with PHP

The same imagecopy() function we used to put our source images on the base image can also be used to resize images. Handy if you want to generate thumbnails automatically! Here’s how you can do that:


/*
 * RESCALE TO THUMB FORMAT
 */
$thumbSize = 200;
$thumbImage = imagecreatetruecolor($thumbSize, $thumbSize);
imagecopyresampled($thumbImage, $mapImage, 0, 0, 0, 0, $thumbSize, $thumbSize, $mapWidth, $mapWidth);

Final step: set header to tell the browser there’s an image coming, and output the final image


/*
* OUTPUT THUMBNAIL IMAGE
*/

header ("Content-type: image/png");
imagepng($thumbImage); //change argument to $mapImage to output the original size image

And that’s it!  Note that you may not want a uniformly filled background but rather a real background image – you can easily do this by using imagecreatefrompng() in step 2.

Here’s all the code once more together for convenience.


<?php

//Source image paths (DISCLAIMER: this is just to demonstrate, to generate a real TT map you need 144 of these)
<pre>$srcImagePaths = Array('https://diceattack.files.wordpress.com/2011/01/tile_e_o_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_e_g_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_e_b_fh.png',
'https://diceattack.files.wordpress.com/2011/01/tile_b_q_fh.png');
</pre>
/*
 * INIT BASE IMAGE FILLED WITH BACKGROUND COLOR
 */

$tileWidth = $tileHeight = 28;
$numberOfTiles = 12;
$pxBetweenTiles = 1;
$leftOffSet = $topOffSet = 1;

$mapWidth = $mapHeight = ($tileWidth + $pxBetweenTiles) * $numberOfTiles;

$mapImage = imagecreatetruecolor($mapWidth, $mapHeight);
$bgColor = imagecolorallocate($mapImage, 50, 40, 0);
imagefill($mapImage, 0, 0, $bgColor);

/*
 *  PUT SRC IMAGES ON BASE IMAGE
 */

function indexToCoords($index)
{
 global $tileWidth, $pxBetweenTiles, $leftOffSet, $topOffSet, $numberOfTiles;

 $x = ($index % 12) * ($tileWidth + $pxBetweenTiles) + $leftOffSet;
 $y = floor($index / 12) * ($tileWidth + $pxBetweenTiles) + $topOffSet;
 return Array($x, $y);
}

foreach ($srcImagePaths as $index => $srcImagePath)
{
 list ($x, $y) = indexToCoords($index);
 $tileImg = imagecreatefrompng($srcImagePath);

 imagecopy($mapImage, $tileImg, $x, $y, 0, 0, $tileWidth, $tileHeight);
 imagedestroy($tileImg);
}

/*
 * RESCALE TO THUMB FORMAT
 */
$thumbSize = 200;
$thumbImage = imagecreatetruecolor($thumbSize, $thumbSize);
imagecopyresampled($thumbImage, $mapImage, 0, 0, 0, 0, $thumbSize, $thumbSize, $mapWidth, $mapWidth);

header ("Content-type: image/png");
imagepng($thumbImage);

?>

If there are any errors here or you have other suggestions, feel free to let me know in the comments!

Also if anybody would be interested, the next thing I do is of course store this resulting image somewhere (generating them dynamically each time would cost ridiculous amounts of time); perhaps that would make for a nice follow-up post?


Guest login and straight to portal

November 2, 2010

I had done it before but I am doing it again, and I think I’ll really stick to it this time: skipping the intro screen and going straight to the portal on first land on the site.

Previously you would first land on this screen:

And then, if somehow you were convinced signing up for a game would be worth it (never mind the 123040234230 games you can just play instantly), you landed here:

… Where the button I want you to press is one of those three in the upper left corner. Yuk, how could I ever expect somebody to make it all the way trough that?

In the shiny new version, everybody who lands is logged on automatically as a ‘guest’ account, lands in the portal, and will probably be able to figure out which button to press:

Other changes:

  • On the left you now have some basic game play instructions.
  • The quick challenge box below the chat is gone, but I never made it to work anyway. The sad news is that it also had the currently online users, which was nice for knowing who you can chat with or challenge.
  • The Start Game button takes you to campaign mode, which is designed to ‘ease in’ players into the game. I still need to work on that a lot though, for example level 0 which starts with just 2 soldiers is nearly unbeatable for beginners because the bot moves too fast 🙂
  • Logging in with your account is moved discretely to the top
  • Multiplayer / practice / guide are also more visible, but still obviously less important than campaign mode.

The only thing I don’t like that much is that you cannot see who is online anymore in the portal. So I think I should look for a way to get that information somewhere in the portal I think. Perhaps using some kind of dropout, so that it does not clutter the layout even more? (I want to keep the amount of text to a minimum at all costs)

As of this writing the web site is down btw and this change is not deployed live yet.


Quick video tour

July 14, 2010

I made a small promo or ‘quick tour’ video to show people how the game looks so they can decide if they like it before having to sign up or whatever:

Of course it’s just another excuse to use my own soundtrack of which I am so proud 🙂


Building big social games

February 9, 2010

Interesting presentation from Farmville’s lead developer: Building big social games. Especially the ‘incremental new features’ thing seems insteresting.

Perhaps TT could be built up a lot more ‘unlocking features’ way, where players start out with only few units (like really, just tanks+soldiers or something) but gain new ones the more they play and/or the more friends they get into the game?


Rating stars, harmonica menus, submarine sounds and boat-buying bots

January 12, 2010

Well, I guess the title says it all… First of all, I did some more household cleaning this weekend, sorting pictures neatly in folders by category, separating out frontend files by page, etc. Nothing fancy, just the kind of stuff that needed to be done sometime and you can’t ignore forever or your code becomes unworkable.

Now for the fun stuff. I got sick of the boring map 2 player basic always showing up first when creating a game. I am sure that puts a lot of people of because it’s so boring compared to, say, Chokehole! or Treasure Island. So I wanted a better way to sort the presented maps in, and as usual the tweak came with a feature: map ratings!

Obviously you have seen these a thousand times and ignored them, which is fine because I just wanted them as an excuse to place my favourite maps on top of the cue:

Map ratings

Map ratings

I don’t take any credit since I took them from Beau Scot, and that file is really a good example of a simple, clean, efficient and maximum reusable little javaScript class (thx to Prototype of course).

Next, I revamped the menu in the portal a bit, including a subtle but (I believe) gigantic useability step forward: allowing the user to choose between single- or multiplayer before creating a game. Number of bots is chosen automatically now, and even better: when you start a multiplayer game an invitation is posted in the portal chat for the others!

The portal is still traditionally ugly, but I can’t believe it took me so long to make that part of the experience a bit more pleasant. There was really no excuse for the earlier game creation process (i.e. creating game, leaving it to come back at the portal to tell the others the game id …).

And finally, as usual these days, some more bot enhancing: they can now also buy naval units, the code behind them is a bit cleaner with even more ‘behavior’ parameters separated out.

Among the tweakable bot-settings we now have these two: landUnitCountBeforeConsideringNaval and unitCountBeforeConsideringBuilding. Of course in a later phase it would be neat to make these depend both on bot ‘character’  and on the map and/or the number of enemy units.

But the best of all is of course that the submarine now makes bubble sounds when moving/firing!


More bot tweaks and while we’re automating anyway: auto-firing towers!

January 4, 2010

More tweaking on the bots this weekend! I created lots of auxiliary functions, moved some bits and pieces around, and also tweaked the bot’s core logic a bit more,  to achieve the following:

  • If there’s no candidate enemy units within attack range, scan in a wider perimeter and moveTowards() the interesting target if one is found. Since the natural ‘enemy’ of an ore truck is the ore field, this means ore trucks will find and occupy nearby ore fields now.
  • Some parameters are centralized in a botSettings object, such as: avgTimePerMove, maxMovesPerRound, buyProbability … This allows for easy tweaking and experimenting with bot behavior and ‘difficulty setting’.
  • With those new helping functions (scanning for enemy units nearby …) it was straightforward to add as a bonus: auto-firing towers, hooray! Towers will now automatically attack all nearby enemies: these are extra moves appended without even a timing penalty. This instant multi-move behaviour may make towers a bit too powerful actually, we’ll see.
    In any case we may have an interesting new ‘construction engineer plus tower rush’ added to the possible strategies now….

All this ‘automated movement’ code opens up another interesting gameplay approach, beyond bots and towers: in principle it isn’t too easy to make all units auto-attack nearby enemies now (and use some random generator for ‘move time’ or whatever). This is something that’s come up as a suggestion from testers sometimes. After all, ‘regular’ RTS games behave like this, you just send hordes of units in the right direction but when a unit is near an enemy it will automatically attack. This would make the game more ‘overview’ and less ‘move by move’ in a way. More like Age Of Kings, less like chess.

I have a feeling this would make the most sense when combined with larger playing fields, whereas with the current small board the ‘placing moves’ aspect is still rather central and nice. But still an interesting thing to keep in mind for later.


On the path to bots ‘understanding’ the situation better: round analysis

December 30, 2009

As I was thinking about how to have my bots make good decisions, I realised something crucial was missing: a ‘high-level overview of the map.

Early AI researchers trying to build a chess computer were faced with the same problem: how can we quantify how strong a position is? Given a position, who has the so-called ‘strategic’ advantage? (as opposed to small-scale short-term ‘tactical’ advantage)

In Tinker Tanks there’s a lot obvious stuff we humans can grasp from just a glance at the map in any given round: in what corner are most of a player’s units? Where are the mines to be found? Who seems to be winning this game, anyway?

So I created a small php function that tries to summarize some indicators about each player’s situation, based solely on the map. Here’s how it looks for now:

Player analysis pane, based on current round situation

Player analysis pane, based on current round situation

(only visible in debug mode for now)

True to Age Of Empires, ‘environment’ (they called it Gaia) is also a ‘player’.

Avg. X and Avg. Y measure where all units are ‘on average’, expressed in grid tiles. I am also playing with the idea of adding a ‘schematic’ green square with an ‘average’ dot for each player, where dot size is proportional to score (see below).

For the Environment player, XY position is calculated taking only the ore fields into account. So if a truck has no obvious ore field nearby he can have an idea where to go explore for the goodies!

I also (finally) took a first pass at defining a meaningful score: it is the sum of price*health over al units currently on the map. This can be refined of course, just as with chess strategy we might incorporate a ‘position advantage’ or something like that later on. Or factor attack bonuses into the equation.

Currently, the buildings/units available at game start are included in the score calculation, so even at round 0 score is quite high because homebases, war factories and ore trucks cost so much.

If I ever show this to players during a game I may have it start on zero for everybody, but I am not really sure if that’s the best approach for guiding a bot’s judgement yet.

In any case, I feel this ’round analysis’ is a nice pass towards giving bots a better ‘understanding’ of what is going on in the game. Soon all that will be left for them is to sense emotions based on your mouse gestures so they can use some psychological warfare…