Demoing the dash booster

I know, I know: a “run faster” item is probably the single most hackneyed power up in the history of Metroidvanias. What can I say? I just really like how a nice dash adds to the control mechanics of a platformer. And of course it can break a certain kind of block. See it in action below:

This is a true dash, activated with a double-tap of the run button. This is in contrast to Super Metroid’s similar powerup, which just automatically kicks on once you hit a certain ground speed. I think the latter is actually better for Metroidvania planning purposes (since it requires a long runway), but a true dash adds a lot more to game play.

I’m not sure about whether this item will level up, so that each level-up you find makes it faster — or if it can be activated multiple times to get faster and faster boost speeds (similar to the “long runway” lock and key semantics of Super Metroid’s dash booster). I have it implemented as the “long runway” option at the moment, but I’m still mulling this one over.

On an implementation note, this is the first time I have had a reason to use Box2D’s broad-phase collision event. In theory it’s for exactly this kind of thing: warning you about an upcoming collision event before it actually takes place. In my case it looks like this:

private void OnBroadphaseDashCollision(ref FixtureProxy a, ref FixtureProxy b) {
    if ( _isDashing
            && (a.Fixture.GetUserData().IsPlayer || b.Fixture.GetUserData().IsPlayer)
            && (a.Fixture.GetUserData().IsDestructibleRegion || b.Fixture.GetUserData().IsDestructibleRegion) ) {
        Fixture f = a.Fixture.GetUserData().IsDestructibleRegion ? a.Fixture : b.Fixture;
        if ( (f.GetUserData().Destruction.DestroyedBy(EnceladusGame.DashDestructionFlag)) ) {
            Tile tile = TileLevel.CurrentLevel.GetTile(f.Body.Position);
            if ( tile != null ) {
                TileLevel.CurrentLevel.DestroyTile(tile);
            }
        }
    }
}

But of course that’s not good enough. Once you get moving fast enough, you stop getting warned about the receding edge of the wall that’s being chewed up and run smack into it on the same frame it was broken apart. This isn’t really Box2D’s fault, just a natural effect of how I’ve implemented the terrain in the game. To patch that up, I add an actual collision handler that ignores collision events that will result in a dash-booster-vulnerable block breaking:

private bool DashCollisionHandler(Fixture a, Fixture b, Contact contact) {
    if ( _isDashing ) {
        if ( b.GetUserData().IsTerrain && contact.GetPlayerNormal(_body).Y == 0 ) {
            FixedArray2 points;
            Vector2 normal;
            contact.GetWorldManifold(out normal, out points);
            var tile = TileLevel.CurrentLevel.GetCollidedTile(points[0], normal);
            if ( tile != null && TileLevel.CurrentLevel.IsTileDestroyedBy(tile, EnceladusGame.DashDestructionFlag) ) {
                TileLevel.CurrentLevel.DestroyTile(tile);
                return false;
            }
        }
    }
    return true;
}

Not the most straightforward feature to cram into Box2D, but definitely a long way from the hardest.

One thought on “Demoing the dash booster

  1. Maybe make a level that’s completely dark, requiring an infrared visor upgrade to see it. Since it’s dark, it could be populated by enemies that use echolocation. The dash could be upgraded to a point where it appears to teleport you forward, though in fact it is just exceeding the speed of sound. The resulting brief sonic boom could “deafen” nearby echolocation-dependent enemies, causing their movement and attacks to be random.

Leave a Reply