snake5 icon

collision grid

snake5 | PRO | 11/17/14 10:34:55 PM UTC | 0 ⭐ | 840 👁️ | Never ⏰ | []
JavaScript |

3.58 KB

|

None

|

0 👍

/

0 👎

/*
    Collision grid, 16x16 tiles
    
    - create
    + set( x16, y16 )
    + unset( x16, y16 )
    + test( x, y )
    + raycast( x1, y1, x2, y2, notestfirst ) => null / dt, isp_x, isp_y
    + aabbtest( x1, y1, x2, y2 ) => null / true, xnrm, ynrm, push
*/
 
global ColGrid = {};
 
function ColGrid.create()
{
    data =
    {
        tiles = map(),
    };
    return class( data, ColGrid );
}
 
function ColGrid._getkey( x16, y16 )
{
    return ((x16&0xffff)<<16) | (y16&0xffff);
}
 
function ColGrid.set( x16, y16 )
{
    this.tiles[ this._getkey( x16, y16 ) ] = true;
}
 
function ColGrid.unset( x16, y16 )
{
    unset( this.tiles, this._getkey( x16, y16 ) );
}
 
function ColGrid.test( x, y )
{
    x16 = toint( floor( x / 16 ) );
    y16 = toint( floor( y / 16 ) );
    return isset( this.tiles, this._getkey( x16, y16 ) );
}
 
function ColGrid.raycast( x1, y1, x2, y2, notestfirst )
{
    x1_16 = toint( floor( x1 / 16 ) );
    y1_16 = toint( floor( y1 / 16 ) );
    x2_16 = toint( floor( x2 / 16 ) );
    y2_16 = toint( floor( y2 / 16 ) );
    
    if( !notestfirst && isset( this.tiles, this._getkey( x1_16, y1_16 ) ) )
        return 0, x1, y1;
    if( x1_16 == x2_16 && y1_16 == y2_16 )
        return null;
    
    x16 = x1_16;
    y16 = y1_16;
    xdist = x2 - x1;
    ydist = y2 - y1;
    stepX = if( xdist >= 0, 1, -1 );
    stepY = if( ydist >= 0, 1, -1 );
    len = sqrt( xdist * xdist + ydist * ydist );
    if( xdist == 0 )
    {
        tMaxX = 3.8e+10;
        tDeltaX = 0;
    }
    else
    {
        tMaxX = ( floor( x1_16 + ( xdist > 0 ) ) * 16 - x1 ) * len / xdist; // should be +
        tDeltaX = 16 * len / abs( xdist );
    }
    if( ydist == 0 )
    {
        tMaxY = 3.8e+10;
        tDeltaY = 0;
    }
    else
    {
        tMaxY = ( floor( y1_16 + ( ydist > 0 ) ) * 16 - y1 ) * len / ydist; // should be +
        tDeltaY = 16 * len / abs( ydist );
    }
    t = if( tMaxX < tMaxY, tMaxX, tMaxY );
    
    while( x16 != x2_16 || y16 != y2_16 )
    {
        if( tMaxX < tMaxY )
        {
            t += tMaxX;
            tMaxX += tDeltaX;
            x16 += stepX;
        }
        else
        {
            t = tMaxY;
            tMaxY += tDeltaY;
            y16 += stepY;
        }
        
        if( isset( this.tiles, this._getkey( x16, y16 ) ) )
        {
            q = t / len;
            q1 = 1 - q;
            return q, x1 * q1 + x2 * q, y1 * q1 + y2 * q;
        }
    }
    
    return null;
}
 
function _aabb_aabb_resolve( ax1, ay1, ax2, ay2, bx1, by1, bx2, by2 )
{
    // in an intersection all of these are non-negative
    dx1 = ax2 - bx1;
    dx2 = bx2 - ax1;
    dy1 = ay2 - by1;
    dy2 = by2 - ay1;
    
    // find smallest of those and resolve assuming BB1 is to be moved
    if( dx1 < dx2 )
    {
        if( dx1 < dy1 )
        {
            if( dx1 < dy2 )
                return -dx1, 0;
            else // dy2
                return 0, dy2;
        }
        else // dy1
        {
            if( dy1 < dy2 )
                return 0, -dy1;
            else // dy2
                return 0, dy2;
        }
    }
    else // dx2
    {
        if( dx2 < dy1 )
        {
            if( dx2 < dy2 )
                return dx2, 0;
            else
                return 0, dy2;
        }
        else // dy1
        {
            if( dy1 < dy2 )
                return 0, -dy1;
            else // dy2
                return 0, dy2;
        }
    }
}
 
function ColGrid.aabbtest( x1, y1, x2, y2 )
{
    x1_16 = toint( floor( x1 / 16 ) );
    y1_16 = toint( floor( y1 / 16 ) );
    x2_16 = toint( floor( x2 / 16 ) );
    y2_16 = toint( floor( y2 / 16 ) );
    
    nx = 0;
    ny = 0;
    isc = 0;
    
    for( y16 = y1_16; y16 <= y2_16; ++y16 )
    {
        for( x16 = x1_16; x16 <= x2_16; ++x16 )
        {
            if( isset( this.tiles, this._getkey( x16, y16 ) ) )
            {
                (cx,cy) = _aabb_aabb_resolve( x1, y1, x2, y2, x16 * 16, y16 * 16, x16 * 16 + 16, y16 * 16 + 16 );
                nx += cx;
                ny += cy;
                isc++;
            }
        }
    }
    
    if( isc )
    {
        nx /= isc;
        ny /= isc;
    }
    
    if( nx != 0 || ny != 0 )
    {
        nd = sqrt( nx * nx + ny * ny );
        nx /= nd;
        ny /= nd;
        return true, nx, ny, nd;
    }
}

Comments