That's right, kiddies. Gather around old grandpa Steve and listen to his recounted tales of the implementation of player physics.
Today was another marvellous day for productivity and progress. Note that I've had this whole week off of work so far (until Thursday), so the majority of my free time is going into Skirmish Online's development.
Each game instance now has a Player associated with it, which the main camera is fondly centered on. This player can be controlled by the user (via customizable keys (lacking a customization interface :P)), and features the standard fare player physics: velocity, friction, 360-degree rotation, and all of that fun stuff. The movement animation cycles relative to the magnitude of the player's velocity, so it's neat to give him a high TopSpeed and have him zip around like he's Bicycle Repair Man or something.
Whack! Watch out for that crate!
After the player was politely waltzing around my screen, it was then time to tackle collisions. Skirmish requires two flavours: map collisions (with wall tiles), and sprite collisions (with map objects, bullets, cheese-burgers, etc).
This required a rewrite of how I was previously handling the sprite lists (full list, and a list of collidable sprites). I was using std::vector originally, which was as slow as beans in terms of sequential access. std::list was a bit faster, but my framerate was still plummetting. Now I beefed it up to a quasi-dynamic array which zips along with sufficient speed, all contained within a SpriteArray class that manages addition, removal, sequential access, and data-clearing.
Map collisions were a cinch. Since tiles are arranged evenly in 32x32 blocks, it's just a matter of dividing the points on the player's hitbox by 32, and checking the hit-type of that tile. I devised both CanWalkOver() and CanShootOver() helper functions to ease the (likely) future pains of managing the collision possibilities between the various sprite types and tiles.
Pixels, my friend?
Sprite->Sprite collisions are a huge pain. Mainly because I insist upon having pixel-perfect collision detection. [smile] Stubborn me. For those of you just tuning in, I'm using OpenGL, which means that direct pixel access -- in terms of speed -- is a lot like cutting the front lawn with a frog. Not very fast. So how am I to get this working without killing my performance?
At first the plan was to render just the sprite in question, and then read just one pixel (at the player's centre) to determine if it's a hit or not (!black). I couldn't get any logical results from glReadPixels(), so a few tutorials off Google later, some milling around on GD.NET, and I canned it. That approach would just plain take too long.
The other resort was to bite the bullet and do it how I did in the previous writing of Skirmish: access the surface pixel data and check from there. That's as easy as locking a surface to a texture and reading it in Direct3D, but I'm in OpenGL-land now, and it doesn't seem that simple. So I had to settle for storing the pixel data into each created Texture object when I loaded the data in initially at startup-time. This means a bit of a bigger memory footprint, but the tradeoff is that I get direct pixel-reading access (virtually) for free. Woot.
So I implemented this, and got the player bouncing off of non-rotated objects. Those crates and chairs didn't even know what hit them. Next up was to get rotated map objects colliding properly too. This sounds simple, but you must remember that the pixel data is stored in a manner equivalent to Rotation=0. Luckily I had faced this exact problem with the previous Skirmish, and solved it by instead inversely rotating the point on the bitmap I was checking. I doubt I'm sounding too clear, but a long story short: it worked. There was a big bug that took me about 2 hours to figure out, but this is getting pretty nitty-gritty. I don't think most readers really care about that. [smile]
After that, I finished by checking the X and Y directions seperately, allowing the player to 'slide' across the edges of most objects, rather than bumping off or getting stuck. It'll need some tweaking down the line, but the game -- yes, I called it a game now :P -- is starting to feel stable and closer to being playable!
Oh, and I tossed in a few more little things, like a gfx_utils.cpp/h file-set to handle quickly drawing rectangles, lines, and that sort of jargon. Mainly so I could enable/disable drawing sprite hitboxes for easier debugging. Also implemented sprite layering via the ever-handy z-buffer. Now you can officially hide under trees again! [grin]
(Er, how do I show a screenshot of collision detection?)
Tomorrow will hopefully see the final tweaking of the player physics, and then the beginnings of networking. And I've got to say that I'm thrilled at how fast things are coming together. I can only hope that this time it sees success! [smile]