Monday 25 April 2016

Fun With Physics

A riff on Fun With Flags, which is a complete in-joke if I ever wrote one. Most techie friends I have really dislike the Big Bang Theory, so it's likely to be a dud regardless.

But yes, physics. To be accurate, modelling some kind of approximation of physics in a 2D environment. Two planes of movement (x and y-axes), but only ever one at a time. Left or right or up or down. Not necessarily in that order, Your Mileage May Vary, etc. Well, as I'm about to explain, Your Mileage Will Definitely Vary And I Hope You Brought Alcohol.

This is, again, more of an exercise in catharsis and "i hope i have a eureka moment writing this blog post which allows me to solve all my problems" than an attempt at writing some kind of genius physics games development thingy. Go and read Kerbal blogs for that. All my maths friends play Kerbals, which is an indication that that game definitely got stuff right. Not 100% accurate to the science, no. But right enough to be fun for them.



So I have a game, right? Ish. A game-ish kind of game. I have a lot of the building blocks of a game, and physics is kinda That Last One I have to get right before stuff really starts working quite nicely. Before I start making a batshit amount of pixel art, at the very least. I've been very successful at putting that off.

And most of the physics is actually working! I have a wonderful little acceleration bit that, well, accelerates stuff. I have it hooked up to movement. I have force and mass, I have the gravity constant (which will allow me to do Fun Things™ later on). Everything your average high schooler could name in terms of basic physics, this 27 year old adult has completely sorted. Only took me a few months of dredging up knowledge I've spent a decade forgetting (I hate physics, if that wasn't obvious. Hate it). I have all the art hooks in place; units play timed animation cycles (or don't, if they're something like a house), sprites have facings for the four movement directions, the keybinds all move those along nicely. It's really very smooth. I could mock up something really not bad-looking if I spent some time on some artwork. But I really want the basic mechanics in before I even start on that. Which brings us back to the code, specifically the code that isn't working.

Collision detection.


Two words that strike fear even into the hearts of veteran programmers, if Twitter is to be believed. A lot of engines sensibly come with this kind of stuff baked-in, and given how much trouble I'm having with the 2D stuff I would never want to come within a million miles of handling 3D collision detection by hand. The basic principles are very easy.

  1. Figure out if the vague space surrounding object A (known as its bounding box) overlaps ( / intersects) with the vague space surrounding object B.
  2. If the first step results in "false", you can pack up here and happily move on with your life.
  3. If the first step results in "true", you go more in-depth and work out both the direction of the overlap and the depth.
  4. You use the depth to reverse the point of impact to a point where A and B don't overlap.

Now obviously there are some problems here. Firstly, assuming this is real-time (and neat animations aside, there isn't a huge point in being super-good with your collision detection if you're not actually doing anything in real-time), offsetting the objects so they're not going to collide will produce a rather ugly zig-zaggy effect of "move forwards, be automatically moved back" a bajillion times per second. Or 60 - 72 depending on your monitor's refresh rate.

Secondly, because this is real-time, you have to manage a queue of input commands that stem from the time the relevant key on the keyboard is pressed from the point in the physics calculations that the collision is being detected. This stacks up, believe me. Which is why physics in more complicated games is a real performance hit that you have to sometimes make sacrifices for. You have to be able to run the entire frame's worth of objects through the collider checks before the frame cycle is complete.

So performance is one of those ever-present concerns even in "get it working" situations where you're not meant to care about performance. Because performance can make or break the bugs you might see. Which is why you see people complaining about physics not being decoupled from the render cycle and how all of this is a Sin and so forth. Because if you speed up the display (in terms of frames per second) you end up speeding up the physics and this kinda breaks things badly. Hence the need for it to be separate. Which I'm not sure if I've managed yet but it's kinda hard to benchmark things when your home PC can cycle a billion frames per second running my code. Not because it's amazingly efficient, but because it doesn't do a whole lot yet.

I think my issue is somewhere around that last paragraph. I'm processing the movement queue, but there appears to be an overlap in the processing of queue items which is causing supposedly-forbidden movement commands (i.e. "we've found a collision, nullify the forwards momentum so the object doesn't move") to go ahead. Which causes us to get stuck.

But that "stuck-ness" isn't even the problem. It's a combination of that, and attempting to move along an opposite axis while being locked against one axis. So, say, I'm trying to move up or down, but I'm touching a building to my right. That's when things get a bit screwy. And by a bit I mean hoboy do things get weird.

In short, writing this article hasn't helped me. But I've got some notes down on how to fix my odd physics bugs, and with any luck I'll kill the bug before it kills me. So here's a parting GIF where you can kinda see the issue in action. GIF playback is capped at aboue 35FPS; the actual render runs at a silky-smooth rate that matches your monitor's refresh rate. V-Sync, in a way. Ain't that neat!


 Enjoy laughing at my art, as an additional bonus

 

2 comments :

  1. Reading this reminds me how I fought the same issue myself at some point :)
    I dont really understand the point about the input-queue.
    The input handling should be separate from physics. On key down you would just start to apply force to your body, on key up you stop.

    Collision responses then can be implemented in two ways: (Well I know of two)
    - Via real physics formulas. So you do all the math to directly figure out the change in velocity on the object once you moved it to the last valid position. The object then will move away from the obstacle. If the player continues to press the keys to move towards the obstacle they will start to slow down and accelerate at the obstacle again.
    - Via a particle based simulation that uses verlet integration. This paper explains that: http://www.pagines.ma1.upc.edu/~susin/files/AdvancedCharacterPhysics.pdf

    Ive never managed to get the first approach working, my physics-foo is just too bad. The second approach magically creates things like rotation by itself and I got it working in combination with the Separating Axis Theorem to find the necessary collision information.

    So:
    - Try to decouple input from physics. All input does is apply a force.
    - verlet integrated particles can get rid of a lot of physics-formulas while still giving pretty good looking results.

    And last: While writing your own physics stuff is a lot of fun, libs like box2d/liquidfun are better than what you or me can write within reasonable time :)

    ReplyDelete
    Replies
    1. Wow, it is two years too late and I never saw this comment for some reason. Blogger keeps doing odd things.

      Anyhow, great advice, and well appreciated. The first approach is exactly what I'm doing. Gravity constant, acceleration, decelleration, physics affects world model and the view simply renders the data of the model. The issue seems to be in detecting the input itself and applying the force; the ticks don't seem to be being distributed evenly. Either that or the mapping between the model and the view are off. Or both!

      I haven't looked at the project in a long time, the physics issues combined with RL commitments just killed my motivation. But thanks for the poke :)

      Delete