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…


Captchas and caches with PHP

December 28, 2009

Just added two thingies every single dynamic website out there has, but Tinker Tanks still hadn’t: captchas in submitted forms, and some caching. As usual, what I ended up with is rough, more a playful exercise and starting point than actual production-worthy code.

A colleague of mine suggested to use memcached to do the heavy reading/writing needed to make a game advance. However, as memcached is key-value based and my round mechanism depends rather heavily on id lookups and things like that, I am not entirely sure yet how I would make that work. Also, I don’t own the server so it’s easier to play around with the php code then with the server stuff.

So, while reading up on caching anyway, I implemented a super basic PHP caching mechanism, more to get a feeling for it then for actual practical purpose (I am pretty sure it actually slows me down now). It is time based, with a ‘time to live’.

When fetching data from the database I can now opt to do a ‘cached call’,  and pass on a timeout parameter for how long a cache remains valid: e.g. calling $db->getResults(true, 3600) would cache results with a time-to-live of an hour.

The cache itself is a bunch of serialize()d .txt files. The lookup key for individual cache results is simply the filename which has a hash of the exact SQL query in it.

So, say we fetch data with a function that queries for ‘SELECT * FROM users WHERE userid=35′ the cache-enabled way, here’s what happens:

  • Look trough the caches and see if we find a file which has a matching filename and (if it has non-infinit TTL) is modified recently enough.
  • If we find a match, unserialize() it and return that as query result.
  • If we find no match, do a ‘normal’ query in the database and (over)write the text file.

And that’s it. Many users will also typically mean many cache files, but we can live with that.

The forum a bit more polished

The forum is a tad more polished (but still ugly)

Poking around with the forum a bit (I admit it, I felt too tired to plunge in the descent-bot bee hive again) also led me to create a captcha. I never read about them or downloaded one or whatever, but giving how they are I guess my mechanism is the ‘usual one’.

Here’s a the mechanism in its barest form – it’s three steps:

  • In the php controlling the page that has the form to be submitted, generate some random captcha string that the user will have to type. Put this string in the $_SESSION.
function generateCaptcha()
{
   $captcha = (string) rand (0,999);
   $_SESSION['latestCaptcha'] = $captcha; //store for checking on next submit
}
  • In the page itself, insert a dynamically generated image (using GD) with this string in it (in my case the src of an IMG points directly to a captcha.php file that gets the needed string from the session and sticks it on a fixed image). Something like this:
<?php
$im = imagecreatefrompng('http://mydomain.com/img/background_g.png');
$color = imagecolorallocate($im, 255, 255, 255);

session_start();

$captcha = $_SESSION['latestCaptcha'];
$x = 2;
$y = 4;
imagestring($im, 4, $x, $y, $captcha, $color);

header('Content-type: image/png');
imagepng($im);
imagedestroy($im);

?>
  • Finally, among the checks that happen on a submitted form, add one that checks if the submitted captcha matches the latest generated one.

function checkCaptcha($submitted)
{
   $isValid = ($submitted == $_SESSION['latestCaptcha']);
   unset($_SESSION['latestCaptcha']); //so there's no confusion with the next captcha check

   return $isValid;
}

Now, even with the function parameter checks I left out this is obviously not a very good captcha: my string is just a number, extracting those non-disorted characters out of my decoy-less background violates the basic captcha characteristics, so the captcha string could easily be extracted by software. But it was still interesting putting it in there, and surely it will do while my site is still unknown – that’s becoming a recurring theme :-)

Oh, I am also tinkering with another one of those everybody-has-it things: an automated welcome mail that has markup and makes it trough spam filters (hint: not there yet).

That’s it for today folks!


Who said debug consoles have to be boring?

December 8, 2009

(Quick note: I did write a following part of my openSocial series but stupid wordpress keeps inserting weird stuff in my pasted code snippets. Yes, others noted and diagnosed it, so I’ll post&fix it sometime later. Stop nagging you imaginary reader)

One of my quirks as a programmer is that I often sprinkle cr*ploads of comments and debug log messages all over the place, preferably in conversational tongue-in-cheek tone, even if I’m the only one on the team that might ever read them.

On a slightly related note, yesterday I got fed up with my PHP debug console’s boring endless-lines-full-of-unit-char-codes and the likes, so I dropped my real work and instead tweaked the output formatting a bit for two reasons:

  1. If I spend so much time staring at the darn thing while tweaking bot behavior – attack me you stupid! - might as well make it a bit more ‘visual’ when debugging gameplay-related events, and
  2. because I can. Ha!

So here’s a snippet of my debug output during gameplay as it currently looks:

My php debugger, mid-action

Chaotic, lively, and just a tad short of ’serious’: now there’s how hobby coding projects should be.

P.S.: the bots are still buggy now.


Making the bots better

December 5, 2009

As experience has learned by now, nobody will ever ‘get’ this game from the first time, let alone when playing directly in multiplayer. As with any RTS, and true to the name, some tinkering will be mandatory for each player to understand the gameplay enough to enjoy a game.

(I wonder how the chess inventor ever got betatesters?)

Conclusion: without descent single-player the game will never take off. And obviously there’s the next step, an actual training campaign: ‘first, your men must learn how to march!’ (Say it with a Scottisch accent)

So I am tweaking my bots a bit (there are actually quite some severe bugs in the decision algorithm, but at the time I was just happy to have something that could advance rounds without me having to play myself from to browser windows).

As you can see, they are still not very bright, but this one is definitely more assertive than before:

bot_john decided that playtime is over

bot_john (blue) decided that playtime is over


From php game to openSocial app – part 1: the plan

November 6, 2009

I’m embedding Tinker Tanks in social network Netlog (not for real, just using their sandbox) to get familiar with openSocial (both the JS and RESTful API), and I plan to write down my steps pretty carefully. So yes, this will be an OpenSocial tutorial series, with real code snippets and all.

For part 1, let me just list the steps to take as I see them now…

  1. Injecting the entire game page in openSocial ‘canvas’ view, by inserting a new iFrame element in the DOM with the ’src’ parameter pointing to my game. Thanks to Prototype JS this takes just one line.
  2. Wrapping some openSocial stuff around it, like fetching the user’s nickname. Also, we’ll be doing calls to the  Netlog-specific openSocial extension to make the user pay ‘credits’ to pay the game. Currently the user would have to pay each single time he wants to play, but I will transform this in paying after a free trial period. I will do this by storing the number of times played or the time since first play as persistent appData.
  3. Passing on a security token as a GET parameter to that iFrame URL, along with the user’s JS-fetched nickname and some ‘I came from Netlog’ indication. Then I will catch this information on my site, and auto-create a user-account if needed, or auto-login the user with his earlier-created Netlog-originated user account. This way I still have my user’s nicknames, scores, played games…. in my database, while also skipping the login/signup stuff for users that come from Netlog.Of course, everybody can append GET parameters to a URL so I will need to carefully check that my security is watertight.I am also considering prepending Netlog_ to their nickname or something, so that there’s less chance of nickname collision and so that Netlog players are distinguished as such from non-Netlog players (or maybe later, players from other Social networks). Note that I am keeping it all on my server’s, so users can play happily together wherever they originate from.
  4. Start implementing openSocial REST, so that I can send ‘activity messages’ from within the game. For example, if a game is over I can post ‘player1 won from player2 in a game of Tinker Tanks!’ back to the social Network. It’s viral baby!
  5. Also, once openSocial REST works properly, I can start doing all kinds of cool stuff: fetch their avatar image for in-game use, send Netlog notifications from my server reminding players it’s been a while since their last game or that they were challenged, etc…
  6. Back to my monetary model. As said, I will take a ‘free trial’ approach, asking a one-time payment after a certain trial period (either time- or gamebased, not sure yet). Apart from this I will also go freemium on them, making them pay for added-value features, most notably creating and saving custom maps.As the Netlog credits API is by far easiest accessed trough openSocial JS, I think it is best to ask users beforehand if they want to do ‘premium’ stuff like creating maps. Or maybe just create a ‘premium type’ account or whatever. Definitely to be retought later!
  7. [EDIT] Ah what the hell, let’s also do it the other way around too as a bonus: users simply visiting tinkertanks.com can log in using their Netlog user account: in other words, would be nice to get my feet weet with the most esotoric of all these ‘open’ protocols flying around: OAuth and OpenID and that stuff.

Ok that’s it for now. If I pull all of these off succesfully I think I can rightfully say I’ve covered the most important ‘openSocial’ bases.

As the title indicates, I will approach these posts as a series, with detailed explanations and examples. So for the first time in this blog’s history I will (finally) go a bit more technical, posting real code snippets and all.

Canvas view asking for credits - first draft

Canvas view asking for credits - first draft

Ok that’s it – check back for more to come soon!


Next steps: blogging and advertising!

November 4, 2009

*** Posting this because I found it in my ‘drafts’, but it is already outdated :-) ***

Ages since I posted something, or did anything on the site for that manner. That’s because I’ve been too busy finishing up my master’s thesis (but that’s over now, yay!). I DID start on a better ‘invite other online users’ scheme, seen in the portal below the chat.

I also did some more bug fixing and a bit of redesigning, mainly of the front page. Things still look butt-ugly, mainly because my big splash’s transparent color doesn’t quite match the page’s.

Also, I decided to have a change in ’strategy’. In my very first post I stated that ultimately I would be to implement Tinker Tanks as a an app in a social container, but now that I am working for one of those myself I think it’ll be more fun to keep it as a site on its own, and use it as a personal playground for testing new techniques/ideas.

Some new things I would like to implement:

- User blogs so they can write cool ‘battle reports’, or even tournament reports, because…
- A tournament system with fancy tournament calendars and invitations and ‘RSVP’ requests, etc… (I am building a PHP calendar for some other project anyway so might as wel reuse it)
- A nice spot on my site to put ads, and a system that cleverly rotates the ads from my many, many affiliates :-)


Dusted off the Social Container plan…

November 3, 2009

In my very first post I mentioned that the original idea behind Tinker Tanks was to create it as an OpenSocial app within some kind of social network. Preferably this one, as they allow developers to ask for ‘play money’ to its young users, which can be traded for hard, real-life cash later on :-)

Anyway, I left that ambition quite a while ago, since building the game itself was already enough of a challenge without having to worry about the ‘integration’ part. However, I always kept the design in its original, compact form.

Which turned out to be a good idea, because, hooray, I am now playing around with stuffing Tinker Tanks as an app in a social network! The reasons are twofold:

  1. It turns out that all the XML-containing-HTML is not needed for your entire app, you can just use it as a wrapper and use JS to inject an iFrame element in your app. Remember iframes? Yeah, me neither, but somehow they kept around since I last encountered them (somewhere in ‘98).

    Even better, their site-within-a-site qualities make them perfect for just stuffing your entire external site in an openSocial ad. BAM, an openSocial app created in 30 seconds!

  2. I actually work at the aforementioned social network myself, as my loyal readers know, and I got transferred to the helping-external-developers-integrating-their-stuff-with-Netlog department. Which means I am reading and plucking around with Everything Opensocial like a madman, to get up and running ASAP.

So opensocial-ized Tinker Tanks, here we come!

(just have to read up on that NDA to make sure my fun hobby side project doesn’t become property of my employer … )