Thursday, July 1, 2010

Writing a browser game is easy... or not

When I started programming a few years ago, I was playing browser games a lot. After completing a few small projects I decided to write my own browsergame; it looked like a ridiculously easy program could be incredibly sucessful. Well, both turned out to be wrong: The programs aren't simple, and most of them also aren't sucessful.


I was playing Travian when I decided to start this project and I liked it, so I intended to start a project similar to Travian: you raise a little village, fight against other players, expand, and the player with the highest score (i.e. most villages) wins. Although taking the basic gameplay idea from Travian, I did not want to make a clone; I had many ideas what should be different. For example, I wanted a real landscape instead of just randomly placed forest or sea squares, and I wanted a more intelligent user interface.

However, this soon turned out to be not as easy as expected. Even the most basic things like giving resources to players (or more exactly to villages) turned out to be very difficult (simply because using Cron jobs (for example, give resources every five minutes) is a BadIdea™ for various reasons). Thus, your program only can do something if a user actually requests a page, and this requires some quite sophisticated event handling when multiple events occur. For example, if a user comes online at 15:00, requests to level up a resource production building, which finishes at 15:30, and comes online again at 16:00. He obviously wants to know how much resources he has now; but that's not quite so easy to calculate, because we have to add more after the building finished. Imagine how complicated this may get when there's also battles and other events involved in this. So, after years (seriously!) of experimenting with the various solutions, I think this is quite the best one:
  • You need a class for an event, which has a "timestamp" attribute, and a "handle" method. An event is, for example, a building which is finished.
  • You need a class "EventDrivenObject", which represents something events can happen on, for example a village. This class also has a "registerEvent" method, which binds an event to this, whatever, village.
  • You need a global event handler. It collects all events and event driven objects (or more performant, all those which are relevant for the requested page, for example everything that belongs to the user requesting the page), then loops over the events. For each iteration, it calculates the time difference between the current and the previous event; for this time difference, it then can do things that happen all the time (give resources, most probably) on every event driven object. After that, it can simply handle the event.
  • This way, you kind of fast-forward what happened since the last request, and can do anything at any time in the past (you just have to register an event at that point in time).
What I did before was the other way round, I looped over every event driven object, handling all events that were registered on it. While that sounds good, too, it is slightly less flexible; you'll have some serious problems with events that depend on the state of multiple event driven objects. However, if you're absolutely sure you don't need those, the latter solution is faster in terms of memory and CPU cost.

Another thing which is very difficult about writing a browser game is debugging: since most of the gameplay is based on interaction between users, and since most of the bugs will also (only) be triggered by players interacting in a way you did not expect, it's very difficult to track them. Most probably, they'll only occur if you have at least a few dozen testers. Finding bugs is especially hard because your testers will probably be non-technically interested, often very young, and often frustrated (because of the bugs); in other words most of them are usually not capable of or not willing to describe bugs in a way enabling you to only understand what actually happened. There's honorable exceptions, however, some players, although not necessarily technically firm, provide very exact and helpful reports.

The next thing which was more difficult than expected was the balancing, especially regarding troops, and, even more important, game speed. What? Yes, right: game speed. Make it too fast, and crazy players will grow incredibly large accounts in a few days, then get bored and leave; make it too slow and everyone will leave after a few days because they can't discover many new things. Worst about this is that you'll always need a quite long testing phase (at least 6 weeks for my game), and you'll receive a lot of angry flames from the community, while you won't get much constructive ideas on how to improve balancing.

You also need to find a good balance between complex and easy-to-understand game elements. While complex elements will increase the long-term fun value of your game, they might also make less patient players go away. In fact, a game design that is easy to understand, yet complex to master is the key element of any successful (yet not necessarily of any good game; have a look at NetHack as an example for a very difficult to understand, but still fun to play game) game.
The same rule is valid for the user interface, but it's much easier to do here, and if you do a few tests, it should not be a large problem.

So, here's what I learned.
  • Before you start programming anything, make an as-detailed-as-possible document describing how everything in the game works. It's not too important to work out actual quantities here (like costs or so); you can do that later. It's of utmost importance, however, that you work out qualities: how do fight works, what do the buildings do, everything. Let other people read that document, and think think through as many game situations as possible.
  • Many people keep ranting about the importance of your choice of technology, mainly because of scalability issues. "What are you going to do with your PHP script if you have more than 100.000 users? It won't work any more then!". Well no, it won't. But who cares? Get 100.000 users first. If you have them, you can still think about that. If you get a scalability problem, you've done something quite right (because users seem to like what you do). It might be a bit annoying to change your technology then, but if the initial development is easier for you with the non-scalable technology, it's worth it in any case.
  • Write detailed logfiles, have a step-by-step debugger, and have a bug tracking system. Mantis is good, and users do actually understand it.
  • Have a version management system like git. The earlier, the better.
  • You cannot earn money with ads. You just can't. Especially not with a browser game. Those advertisement "sellers" are not very reliable, don't pay much, and do everything to make their ad scripts as buggy and annoying as possible. Instead, consider selling user interface enhancements for a small fee, or just pay for the server yourself until your game grows large, keeping it ad-free in return.
  • Same applies to making ads yourself: Not worth it. If you want to find players, register your game in as many toplists or whatever and reward your players for voting :p
  • If you have the choice between a difficult to understand but "deep", and an easy-to-understand but "flat" game design decision, take the easy one. There's a risk of your players leaving after a while because the game gets boring soon; but that's way better than having them leave before they even started playing because the game is too hard to understand.
  • It's also not the worst idea to provide a "noob" and an "expert" user interface for choice, if you have the patience to implement two of them.
  • If you're using MySQL, make much use of InnoDBs transactions. You will have handler scripts interfering with each other, and you will spend weeks tracking unexplainable bugs.
  • Make your friends, relatives, and in general everyone who has a computer start playing your game "from scratch". Don't explain anything, just watch what they do. This helps a lot in weeding out unintuitive user interface choices.
  • If you chose your game's speed, make it too fast instead of too slow. You can always make it slower when you see accounts growing too fast, but if it's too slow, your players will leave because they get bored too soon.
  • If possible, refrain from using too complex formula for your stuff. Many players actually care about them, and it's nice if it doesn't fill a page if you explain it somewhere.
  • When you're trying to balance something, don't add another extra rule / exception / condition. There must be a simple solution to balance it. If you add yet another condition, you'll end up with something like my village-capturing system where even I as the developer couldn't tell you about everything it requires.
What I also found is that the time of games like the one I made is ... over. They were really innovative a few years ago, but now there's so many of them that nobody cares any more. If you don't have a really, really good game design idea, better do something else.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.