Tuesday, February 4, 2014

Physics Force Accumulation

I've been working on a solar system simulation.

It went okay. The basics are all in place, I can add bodies, and add gravitational forces per-body. (Right now things are only attracted to the sun, because those are the only non-negligible forces in the system, but multiple forces are fully supported.)

The devil's in the details, though.

The numbers involved are too large and require too much precision for my Vector data type, which uses floats. I've done what I can in that department by choosing good units, my distances are in Light Minutes, my masses are in 10^24 Grams. However, my gravitational constant is wrong, and no amount of tinkering to compensate for errors makes it work right. I can find values where planets in a certain size range orbit more or less properly, but lighter planets than that range take off into space, and heavier planets develop super-elliptical slingshot orbits that would destroy a real planet. (As you see in the video, Jupiter's orbit takes it through the surface of the sun at four or five times intended heliocentric velocity.) I almost think there's a formula wrong somewhere, but I can't find it, and fortunately this one problem is in a very minor part of the spec. 

All my auxiliary features are in place; I can zoom on planets, and dynamically add planets, and display particle trails for orbits. I can draw debug info, although I can't figure out how to draw it at a planet's location, or at any size smaller than 48pt. I can reset the simulation freely.

Here's a video of it in action, although Youtube mangled it pretty badly, so you'll have to squint at the smaller planets.


Monday, September 30, 2013

SpaceWar Jam

Boyd and I were told to make a copy of an old game called SpaceWar in an an afternoon.

Boyd basically had it done for a past project, so it went pretty smoothly. Most of the code I wrote was pretty trivial, but I'm proud of how my starfield generator ended up looking.

I can't think of anything I'd do differently next time. This project went almost perfectly smoothly.
http://boydpellettproduction.blogspot.com/ is my partner's blog.
http:prof.johnpile.com is my professor's website.

Monday, September 2, 2013

Networking in Source

The Source Engine, and by extension Team Fortress 2 and company, handle networking over UDP.

There is an authoritative server that handles all game logic, physics simulation, etc. It runs at a fixed rate of either 30 or 66 ticks per second, although this number can be changed. Not every tick is sent to clients as a snapshot, each client has setting to keep the data sent to them within their bandwidth restrictions to avoid dropped packets. In practice, this means that a client gets about 20 updates per second, which is clearly a good bit lower than the frame rate of the client. To avoid the game looking choppy, the client doesn't render in real-time. Instead, it renders at a (configurable) 100ms delay behind the game state it has actually received, and interpolates between the two snapshots on either side of that delay point. (100ms allows for one dropped snapshot at 20 snapshots per second without a stutter, but doesn't introduce input lag that is noticeable to most players.)

Clients send input to the server in smaller snapshots containing only player input, at a higher rate. Latency, or Ping, is the amount of time it takes for a client to take an input snapshot, send it to the server, and receive a game snapshot with that input taken into account. Ping delays are inevitable, and there is nothing that can really be done to prevent them. However, the engine has a simple trick to disguise them from the client, greatly increasing playability. Each client machine runs the game simulation for the player and things they control in real-time, letting players move with zero latency. Of course, the server is still authoritative, and that means that sometimes the local player position is wrong. Every time a new snapshot is received, the local simulation is corrected, either instantly or over the course of a few frames.

This isn't good enough to do quality hit detection, though. Because it's so important, the server keeps a log of player positions for one second, and whenever a hit is called for (i.e. a weapon is shot) it estimates what time the shot actually occurred, based on the client's specific latency and interpolation, and 'rewinds' the server to check the hit, then applies it retroactively to the current gamestate. Essentially, this means that you don't have to lead an enemy with a hitscan weapon if you have high ping.