/* 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; } }