By now you probably know that we are making a TCCG sandbox. The git repo is setup (here's a link to it: https://github.com/IndieGameDev/tccgsandbox) and having exchanged emails with my good friend Alex (touched on some repo organization points) first tiny bit of structure has taken shape. So what now?
Today I have been doing something interesting on my way to work. I was thinking: what is a major common part among the games we would like to play? And I came to a conclusion that it is player's turn. Actually all games can be divided by this factor. On one side you have all your action oriented and sports games (like football, Counter Strike or trying to win the attention of a girl you like) - actions in such games are taken simultaneously and are only limited by laws of physics or economics. On the other side we have turn based games (chess, card games, stuff we'd like to make a sandbox for). These tend to be in our interest group.
This lead me to thinking: what is the major problem with developing turn-based games that support multiple people. Especially if we consider this in the realm of HTTP requests - polling would spring into mind. So what's the problem?
The "Donkey" problem
When one player needs to know if it is his turn - he needs to ask game server about it. Traditionally it is done by setting up an interval and just asking "Is it my turn yet?"
"Is it my turn yet?"
"Is it my turn yet?"
"Is it my turn yet?"
"Is it my turn yet?"
....
This can get really annoying, really quickly! (by annoying I mean, overhead in sending extra HTTP headers just to get a negative response and also killing mobile device battery life!).
So what can we do instead?
The solution
First of all we need something that doesn't require a fancy pants push notifications server! Why? These things are expensive to implement (time issue) and maintain (money issue). We are an indie game shop after all!
We also want something that doesn't require a LOT of socket management to keep connections from closing.
Finally, it should be easy to swap out if needed!
So here's what I'm thinking:
The server
For the sake of illustration our server script will look like this:
<?php
sleep(rand(1,10)); echo("[".date("h:m:s")."] Here is a server response!");
?>
It is very simple. It waits for a random number of seconds and then returns a message with time.
Now the client
This is where the magic is! (using DojoToolkit here).
<script>
function smartLongRequestHandler(){ dojo.xhrGet({url:"serverScript.php", async:true}).then( function(data){ console.log("success: "+data); setTimeout(smartLongRequestHandler, 0); }, function(data){ console.log("error: "+data+" server probably timed out!"); setTimeout(smartLongRequestHandler, 0); } ); } smartLongRequestHandler();
</script>
So what happens?
First we are calling our server asynchronously and are waiting for response. It can take between 1-10 seconds for us to get one. So connection just sits there open. Then, as soon as we get something back (or fail on server timeout) we re-queue! and wait again. This is that simple.
First we are calling our server asynchronously and are waiting for response. It can take between 1-10 seconds for us to get one. So connection just sits there open. Then, as soon as we get something back (or fail on server timeout) we re-queue! and wait again. This is that simple.
So what does it win us?
Say, for the sake of argument, we have 1 sec delay tolerance. In polling implementation we'd have to check the server every second for message. The request/response timeline would look like this
1s Client: are we there yet? Server: NO!
2s Client: are we there yet? Server: NO!
3s Client: are we there yet? Server: YES! Here is your message!
4s Client: are we there yet? Server: NO!
5s Client: are we there yet? Server: NO!
6s Client: are we there yet? Server: YES! Here is your message!
7s Client: are we there yet? Server: NO!
8s Client: are we there yet? Server: NO!
9s Client: are we there yet? Server: NO!
10s Client: are we there yet? Server: YES! Here is your message!
So we get 10 request/responses and 3 meaningful messages! Yay!
Now in our implementation
1s Client: are we there yet?
3s Server: YES! Here is your message!
4s Client: are we there yet?
6s Server: YES! Here is your message!
7s Client: are we there yet?
10s Server: YES! Here is your message!
So we get 3 request/responses and 3 meaningful messages!
100% effectiveness (if server doesn't timeout, but we'll talk about it tomorrow!) vs 33% effectiveness.
The choice is yours!