Search code examples
javacollision-detection

Minicraft Collision Detection


I'm trying to understand how this code works for collision detection. I can tell the goal is a bounding box, and that we are testing each possible point for the entity, but I am uncertain of the purpose of the signed shift operator in this instance. In fact I don't even understand why it would ever be useful, just what it does. Can anyone elaborate?

protected boolean move2(int xa, int ya) {
    if (xa != 0 && ya != 0) throw new IllegalArgumentException("Move2 can only move along one axis at a time!");

    int xto0 = ((x) - xr) >> 4;
    int yto0 = ((y) - yr) >> 4;
    int xto1 = ((x) + xr) >> 4;
    int yto1 = ((y) + yr) >> 4;

    int xt0 = ((x + xa) - xr) >> 4;
    int yt0 = ((y + ya) - yr) >> 4;
    int xt1 = ((x + xa) + xr) >> 4;
    int yt1 = ((y + ya) + yr) >> 4;
    boolean blocked = false;
    for (int yt = yt0; yt <= yt1; yt++)
        for (int xt = xt0; xt <= xt1; xt++) {
            if (xt >= xto0 && xt <= xto1 && yt >= yto0 && yt <= yto1) continue;
            level.getTile(xt, yt).bumpedInto(level, xt, yt, this);
            if (!level.getTile(xt, yt).mayPass(level, xt, yt, this)) {
                blocked = true;
                return false;
            }
        }
    if (blocked) return false;

    List<Entity> wasInside = level.getEntities(x - xr, y - yr, x + xr, y + yr);
    List<Entity> isInside = level.getEntities(x + xa - xr, y + ya - yr, x + xa + xr, y + ya + yr);
    for (int i = 0; i < isInside.size(); i++) {
        Entity e = isInside.get(i);
        if (e == this) continue;

        e.touchedBy(this);
    }
    isInside.removeAll(wasInside);
    for (int i = 0; i < isInside.size(); i++) {
        Entity e = isInside.get(i);
        if (e == this) continue;

        if (e.blocks(this)) {
            return false;
        }
    }

    x += xa;
    y += ya;
    return true;
}

It may be worth noting that the Entity knows its exact x and y position by pixel, but a tile doesn't know its position at all. The world has an array of tiles, but only knows its tile position... so when it comes time to do collision detection the function must have to determine which tile position to get from the player position.

The full source is available here: http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&uid=398

Note that tiles are 16x16


Solution

  • Dividing by a power of two is often expressed as a right-shift n bits where n is the power.

    Used to be when writing C or assembly you did that because it was MUCH faster than doing an actual divide. Left shift is the same as multiplying by the equivalent power of two and is also MUCH faster than hardware multiply. Nowadays most compilers will special-case this and emit shifts instead of multiply/divide for powers of 2.

    Of course if your tile size is not a power of 2 you have to divide instead.