My raycaster is putting out strange results, how do I fix it?

Posted by JamesK89 on Game Development See other posts from Game Development or by JamesK89
Published on 2011-03-04T23:04:06Z Indexed on 2011/03/04 23:33 UTC
Read the original article Hit count: 428

Filed under:
|
|
|
|

I'm working on a raycaster in ActionScript 3.0 for the fun of it, and as a learning experience.
I've got it up and running and its displaying me output as expected however I'm getting this strange bug where rays go through corners of blocks and the edges of blocks appear through walls.
Maybe somebody with more experience can point out what I'm doing wrong or maybe a fresh pair of eyes can spot a tiny bug I haven't noticed.

Thank you so much for your help!

Screenshots:

http://i55.tinypic.com/25koebm.jpg

http://i51.tinypic.com/zx5jq9.jpg

Relevant code:

function drawScene()
{

    rays.graphics.clear();
    rays.graphics.lineStyle(1, rgba(0x00,0x66,0x00));

    var halfFov = (player.fov/2);

    var numRays:int = ( stage.stageWidth / COLUMN_SIZE );
    var prjDist = ( stage.stageWidth / 2 ) / Math.tan(toRad( halfFov ));
    var angStep = ( player.fov / numRays );

    for( var i:int = 0; i < numRays; i++ ) {

        var rAng = ( ( player.angle - halfFov ) + ( angStep * i ) ) % 360;
        if( rAng < 0 ) rAng += 360;

        var ray:Object = castRay(player.position, rAng);
        drawRaySlice(i*COLUMN_SIZE, prjDist, player.angle, ray);

    }

}

function drawRaySlice(sx:int, prjDist, angle, ray:Object)
{

    if( ray.distance >= MAX_DIST )
        return;

    var height:int = int(( TILE_SIZE / (ray.distance * Math.cos(toRad(angle-ray.angle))) ) * prjDist);

    if( !height )
        return;

    var yTop = int(( stage.stageHeight / 2 ) - ( height / 2 ));
    if( yTop < 0 ) yTop = 0;

    var yBot = int(( stage.stageHeight / 2 ) + ( height / 2 ));
    if( yBot > stage.stageHeight ) yBot = stage.stageHeight;

    rays.graphics.moveTo(
        (ray.origin.x / TILE_SIZE) * MINI_SIZE,
        (ray.origin.y / TILE_SIZE) * MINI_SIZE
    );

    rays.graphics.lineTo(
        (ray.hit.x / TILE_SIZE) * MINI_SIZE,
        (ray.hit.y / TILE_SIZE) * MINI_SIZE
    );

    for( var x:int = 0; x < COLUMN_SIZE; x++ ) {
        for( var y:int = yTop; y < yBot; y++ ) {
            buffer.setPixel(sx+x, y, clrTable[ray.tile-1] >> ( ray.horz ? 1 : 0 ));
        }
    }

}

function castRay(origin:Point, angle):Object
{

    // Return values

    var rTexel = 0;
    var rHorz = false;
    var rTile = 0;
    var rDist = MAX_DIST + 1;
    var rMap:Point = new Point();
    var rHit:Point = new Point();

    // Ray angle and slope

    var ra = toRad(angle) % ANGLE_360;
    if( ra < ANGLE_0 ) ra += ANGLE_360;

    var rs = Math.tan(ra);

    var rUp = ( ra > ANGLE_0 && ra < ANGLE_180 );
    var rRight = ( ra < ANGLE_90 || ra > ANGLE_270 );

    // Ray position

    var rx = 0;
    var ry = 0;

    // Ray step values

    var xa = 0;
    var ya = 0;

    // Ray position, in map coordinates

    var mx:int = 0;
    var my:int = 0;
    var mt:int = 0;

    // Distance

    var dx = 0;
    var dy = 0;
    var ds = MAX_DIST + 1;

    // Horizontal intersection

    if( ra != ANGLE_180 && ra != ANGLE_0 && ra != ANGLE_360 ) {

        ya = ( rUp ? TILE_SIZE : -TILE_SIZE );
        xa = ya / rs;

        ry = int( origin.y / TILE_SIZE ) * ( TILE_SIZE ) + ( rUp ? TILE_SIZE : -1 );
        rx = origin.x + ( ry - origin.y ) / rs;

        mx = 0;
        my = 0;

        while( mx >= 0 && my >= 0 && mx < world.size.x && my < world.size.y ) {

            mx = int( rx / TILE_SIZE );
            my = int( ry / TILE_SIZE );

            mt = getMapTile(mx,my);

            if( mt > 0 && mt < 9 ) {

                dx = rx - origin.x;
                dy = ry - origin.y;

                ds = ( dx * dx ) + ( dy * dy );

                if( rDist >= MAX_DIST || ds < rDist ) {

                    rDist = ds;

                    rTile = mt;

                    rMap.x = mx;
                    rMap.y = my;

                    rHit.x = rx;
                    rHit.y = ry;

                    rHorz = true;

                    rTexel = int(rx % TILE_SIZE)

                }

                break;

            }

            rx += xa;
            ry += ya;

        }

    }

    // Vertical intersection

    if( ra != ANGLE_90 && ra != ANGLE_270 ) {

        xa = ( rRight ? TILE_SIZE : -TILE_SIZE );
        ya = xa * rs;

        rx = int( origin.x / TILE_SIZE ) * ( TILE_SIZE ) + ( rRight ? TILE_SIZE : -1 );
        ry = origin.y + ( rx - origin.x ) * rs;

        mx = 0;
        my = 0;

        while( mx >= 0 && my >= 0 && mx < world.size.x && my < world.size.y ) {

            mx = int( rx / TILE_SIZE );
            my = int( ry / TILE_SIZE );

            mt = getMapTile(mx,my);

            if( mt > 0 && mt < 9 ) {

                dx = rx - origin.x;
                dy = ry - origin.y;

                ds = ( dx * dx ) + ( dy * dy );

                if( rDist >= MAX_DIST || ds < rDist ) {

                    rDist = ds;

                    rTile = mt;

                    rMap.x = mx;
                    rMap.y = my;

                    rHit.x = rx;
                    rHit.y = ry;

                    rHorz = false;

                    rTexel = int(ry % TILE_SIZE);

                }

                break;

            }

            rx += xa;
            ry += ya;

        }

    }

    return {
        angle: angle,
        distance: Math.sqrt(rDist),
        hit: rHit,
        map: rMap,
        tile: rTile,
        horz: rHorz,
        origin: origin,
        texel: rTexel
    };

}

© Game Development or respective owner

Related posts about 3d

Related posts about graphics