AgarIO has been all the rage for the past month now. It's been featured on countless major Youtube channels, has at least 100,000 users playing at any given time and seems to have been acquired or partnered with Miniclip.
I had the excellent idea to develop an AgarIO clone, which would allows friends to join each other easier and to have a more efficient rendering engine.
Things Go Wrong
Soon after starting, I realized I'd made a number of serious mistakes, but I've learned a lot along the way.
The first mistake was cloning a game without providing any true benefit because AgarIO actually has a gamemode where you can join your friends and seems to be improving its rendering engine over time.
The second mistake I made was assuming such a game would be easy to develop and a game engine would not be necessary. I could have never been further off from reality; collision handling and rendering efficiently [ to name a few] are hard.
Nonetheless, I keep pushing onwards because I get to learn a ton of stuff.
Collision Detection and Handling
Detecting a collision between to circles is not hard. Find the distance between the position of two circles, if that distance is greater than the radii added, there is a collision.
Handling a collision similar to AgarIO does it is much harder and I'll save that for a post in the future because I haven't completely ironed out my algorithm.
Client and Server Communication
I used SocketsIO, NodeJS, and ExpressJS for the backend of this project. I encode and decode requests using binary JSON.
When a client connects to the server, they receive information about the entire map state (players, viruses, and food). After that, they send input events (mousemove, w keypress, and space keypress). The server uses this input to simulate the map at some number of ticks per second.
Say a client sends a mousemove event, this means they've changed the direction their cells are moving towards. The server will receive this and updates its cell objects for this client accordingly and will send the new velocity to the other players.
The clients do not compute any important logic (collisions with viruses, other players' cells, splitting, shooting, etc.), they just interpolate from the velocity and position received from the server. This prevents cheating, but retains responsiveness on the frontend.
I'm still working out how to determine exactly what data the server should be sending the clients and when/ how often.
The way I render currently has become a bit of a monstrosity.
Players' cells are rendered in the DOM and animated with the top and left styles so they do not have to be redrawn to a canvas every time they move.
Viruses and food are rendered on separate canvases and are only re-rendered when a food or viruses moves, is added, or is removed. There is potential for improvement by using a quadtree. I haven't quite gotten around to that.
- My render and logic loops are separate. I try to keep track of state changes made by the logic loop so rendering can be performed as efficiently as possible, but this introduces a lot of complexity that I haven't figured out how to eliminate
- Similarly, determining how to track and send state changes to the client from the server while using the least bandwidth possible is difficult
- Collision handling will require me to do a bit more vector math on paper
I'll continue to update as I solve each of these issues. If you have any questions or would like me to expand more on any of these topics, I'd be glad to do it.
tl;dr Use a game engine.