It’s been a while since I cocked something up this badly

I’m sure it was something at work that’s getting someone paged as we speak.

First, the good news: I’ve gotten the contour-following algorithm for enemy creatures working with the most complicated terrain I can throw at it. They run fine in both directions, clockwise and counter-clockwise.

I had a hard time getting this working correctly in all cases, and I made things even harder on myself with general ignorance of my libraries and by choosing a poor paradigm upfront. The issue is that I decided early on to keep track of the current direction of the critter with an enum. This wasn’t a bad idea on its own, but it led to me writing lots and lots of switch statements like the following:

switch ( _direction ) {
    case Direction.Right:
        if ( currRotation > 3 * Projectile.PiOverTwo ) {
            EndRotation(3 * Projectile.PiOverTwo);
        }
        break;
    case Direction.Left:
        if ( currRotation > Projectile.PiOverTwo ) {
            EndRotation(Projectile.PiOverTwo);
        }
        break;
    case Direction.Up:
        if ( currRotation > Math.PI ) {
            EndRotation((float) Math.PI);
        }
        break;
    case Direction.Down:
        if ( currRotation <= Math.Abs(rotationDelta) || currRotation >= Math.PI * 2 - Math.Abs(rotationDelta) ) {
            EndRotation(0);
        }
        break;
}

The above block handles stopping the creature’s cornering when it’s making a concave turn going counter-clockwise. I have very similar chunks of code to handle a convex turn, and for both concave and convex turns in the clockwise direction. Each chunk is very similar, but subtly different, and required me to perform mental rotations for every case — and I got quite a few of them wrong. This difficulty was compounded by needing to fix subtle errors more than once, and sometimes forgetting to update near-identical code.

What I finally realized, after banging my head against this wall for a good long time, is that it would be much easier to just add or subtract 90 degrees from the character’s current rotation, then set that as a target and interpolate to that angle over several frames. This is such a drastically simpler solution that I’m going to go back and rewrite the algorithm to use it, even though I got it working the exhaustive, stupid way. I’m 100% certain I will regret not fixing it if I put it off.

Similarly, I was doing a lot of unnecessary work to locate particular points on the Box2D Body in world space. Remember all those switch statements I mentioned?

switch ( _direction ) {
    case Direction.Left:
        if ( _clockwise ) {
            frontEdge = _body.Position +
                        new Vector2(0, -Height / 2f);
            rayDest = frontEdge + new Vector2(0, -Height / 2f);
        } else {
            frontEdge = _body.Position +
                        new Vector2(0, Height / 2f);
            rayDest = frontEdge + new Vector2(0, Height / 2f);
        }
        break;
...

Well, Box2D has solved this issue for me, which I would have known if only I had bothered to research the problem a little more. You can just ask a Body where a particular point in its local coordinate system is in world space, like so:

Vector2 frontBumper = _body.GetWorldPoint(new Vector2(Width / 2, Height / 2));

I’m not actually upset that I made so many mistakes on my first pass implementing this — I set out to develop this game the hard way, so I enjoy taking this kind of beating as long as I learn from it.

Leave a Reply

Your email address will not be published. Required fields are marked *