Tuesday, July 19, 2011

Wow, a month and a half since my last update. It hasn't been due to lack of work on the game, though.

I've been putting almost all of my effort into the code and almost none into the assets, so I still don't have much to show you. I can tell you where I currently am in the project, though

Up until recently, most of my work has been on a generalized engine that I can hopefully use for a variety of 3D games. Granted, it's not going to be the next Unreal engine, but most of the big stuff (object management, low-level network code, collision system, etc.) should be usable across a number of different games. At some point in the future, I'll have to see just how good a job I did. =P

Anyway, now I'm mostly working on stuff relating to a (still generalized) multiplayer FPS. This means network code, and a lot of it. My current goal is to get the game to be awesome over LAN, and at least decent over the Internet. The latter is actually the harder part, since now you have to deal with higher latencies and all sorts of bad connections. To that end, you have to put in a lot of code to smooth things out. The two big ones are interpolation and prediction.

Interpolation means smoothing out an object's transition between two states. There's not nearly enough bandwidth to send an object's state over the network every frame. Currently, I only send an object's state every 50 ms (that's 20 states per second). But if your game's running at 60 FPS, objects' movement will appear to be choppy. So you have to smooth it out. When a client receives an object's state, instead of immediately updating the object, it waits for the next state, then linearly moves between the two. Naturally, your code must also count on states never arriving, or arriving off-beat.

Prediction allows instant reaction to player input. You don't want to have to wait 200 ms after the player presses forward before they actually move forward. They want to move forward NOW. Prediction allows the player to see response to his actions before the server acknowledges it. This means that you're going to have times when the server and client disagree on what's happening. For example, the client may move forward normally when he presses forward, but the server comes up with a different figure because of that big ol' rocket that sent the player flying server-side. So you're going to need code that corrects prediction errors on the client based on states sent by the server. This correction code must also compensate for latency, since that will make the state the server sends reflect some point in the past.

So that and other high-level network stuff has been where most of my time has been going. I'm only now working on main game logic (like the rules of a Deathmatch game). This may seem like an awfully late point in the project to be implementing something like this, but it was necessary to achieve the kind of generalization I was looking for. What I mean by this is the separation (for the most part) of low-level network code, high-level network code, and game logic.

The low-level network code's only job is to send and receive messages, and maintain connections; it can therefore work with pretty much any game. The high-level network code's a little more specific - it contains code necessary to update the world of a multiplayer FPS. This means clients send their inputs to the server, and the server sends states to the clients here. Interpolation and prediction code also goes here. Finally, at the top we have game logic - code that (ideally) works only off the game state, and doesn't touch any network code. So if I wanted to add a CTF game type, I would only have to do three things: make a flag object, give players the ability to pick up flags, and make a new game logic module. None of that involves changing the network code. That's the ideal I'm shooting for.

Players can currently shoot and kill each other, and on the server side the score updates appropriately. I just have to replicate the changed score to clients, and add in some logic for ending the game, and I have a FPS deathmatch.