I’ve decided to embark onto a new project this week: TankGL. Why you might ask? I’ve seen a lack of WebGL games around tanks. I really like tank games, as I played BattleTankz as a child.
I plan for TankGL to be some sort of massive online/bot-based tank battlefield. This isn’t going to be an easy task because of the immediate challenges of scalability and efficiency.
TankGL has a foundation on the following technologies:
- three.js [Client Side Rendering]
- node.js [Server Side Logic]
- physijs [Server Side Physics]
- Web Sockets
The general idea is to offload all the computationally expensive game logic to the server, and have the client act as a rendering agent with a controller interface. Through web sockets, we can use effective communication in the form of events and callback functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Updating the client
Currently the client is updated 60 times a second through an update event in web sockets. The update also contains a delta of the state of the map in JSON format. This delta allows the client to update what the user sees.
The biggest bandwidth consumer is the delta state. We can reduce bandwidth by using the map to our advantage. Since we assume the map is of fixed width (Think 5km by 5km), we can partition the whole map into fixed width cells and give the player a respective update to current and surrounding cells. I call this a “Difference Grid”, it might be called something else in the game industry. The best part is that retrieval from the difference grid is O(1). We will be retrieving a lot.
The following is a highly condensed DiffGrid ADT example with most comments removed for brevity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
This is really great when you have 200 tanks on the battlefield. You don’t want to pass 1MB of JSON every 60th of a second.
We can still improve bandwidth futher; the update event will be reduced to 30 times a second by using client-side lag compensation. However, this is not implemented yet.
For the map, I decided that randomly generated terrain would be adequate for gameplay. To generate this map, I used Simplex Noise.
1 2 3 4 5 6 7 8 9 10 11
At server startup, the terrain is generated and stored. When a client connects, they emit a ‘need_map’ event, and the server sends the 2MB map.
I chose to compute the map each time rather than having a cold map stored in the client for extensibility: I might want to have more maps one day, or custom user ones.
This is what I have so far, there will be more in the future.
I am really enjoying the work I am doing on tankgl, as the challenges will only get tougher. I feel that writing 3D games tend to get you thrown at harder problems quicker compared to writing apps. The networking, performance, and mathematical problems you face are useful in becoming a better Computer Scientist.