Line data Source code
1 : /** 2 : * Class that can be tagged to any tile. Can be used to constrain placers and entity placement to given areas. 3 : */ 4 : class TileClass { 5 : 6 : constructor(size) 7 : { 8 4 : this.size = size; 9 4 : this.width = Math.ceil(size / 16); // Need one entry per 16 tiles as each tile takes a single bit 10 4 : this.inclusionGrid = new Uint16Array(this.size * this.width); 11 : } 12 : 13 : /** 14 : * Returns true if the given position is part of the tileclass. 15 : */ 16 : has(position) 17 : { 18 8 : if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size) 19 3 : return 0; 20 : // x >> 4 == Math.floor(x / 16); used to find the integer this x is included in 21 : // x & 0xF == x % 16; used to find the bit position of the given x 22 5 : return this.inclusionGrid[position.y * this.width + (position.x >> 4)] & (1 << (position.x & 0xF)); 23 : } 24 : 25 : /** 26 : * Adds the given position to the tileclass. 27 : */ 28 : add(position) 29 : { 30 4 : if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size) 31 0 : return; 32 4 : this.inclusionGrid[position.y * this.width + (position.x >> 4)] |= 1 << (position.x & 0xF); 33 : } 34 : 35 : /** 36 : * Removes the given position to the tileclass. 37 : */ 38 : remove(position) 39 : { 40 0 : if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size) 41 0 : return; 42 0 : this.inclusionGrid[position.y * this.width + (position.x >> 4)] &= ~(1 << (position.x & 0xF)); 43 : } 44 : 45 : /** 46 : * Count the number of tiles in the tileclass within the given radius of the given position. 47 : * Can return either the total number of members or nonmembers. 48 : */ 49 : countInRadius(position, radius, returnMembers) 50 : { 51 15 : let members = 0; 52 15 : let total = 0; 53 15 : const radius2 = radius * radius; 54 15 : const [x, y] = [position.x, position.y]; 55 : 56 15 : const yMin = Math.max(Math.ceil(y - radius), 0); 57 15 : const yMax = Math.min(Math.floor(y + radius), this.size - 1); 58 15 : for (let iy = yMin; iy <= yMax; ++iy) 59 : { 60 162 : const dy = iy - y; 61 162 : const dy2 = dy * dy; 62 162 : const delta = Math.sqrt(radius2 - dy2); 63 162 : const xMin = Math.max(Math.ceil(x - delta), 0); 64 162 : const xMax = Math.min(Math.floor(x + delta), this.size - 1); 65 : 66 162 : const indexXMin = xMin >> 4; 67 162 : const indexXMax = xMax >> 4; 68 162 : const indexY = iy * this.width; 69 162 : for (let indexX = indexXMin; indexX <= indexXMax; ++indexX) 70 : { 71 597 : const imin = indexX == indexXMin ? xMin & 0xF : 0; 72 597 : const imax = indexX == indexXMax ? xMax & 0xF : 15; 73 597 : total += imax - imin + 1; 74 597 : if (this.inclusionGrid[indexY + indexX]) 75 16 : for (let i = imin; i <= imax; ++i) 76 98 : if (this.inclusionGrid[indexY + indexX] & (1 << i)) 77 14 : ++members; 78 : } 79 : } 80 : 81 15 : return returnMembers ? members : total - members; 82 : } 83 : 84 : /** 85 : * Counts the number of tiles marked in the tileclass within the given radius of the given position. 86 : */ 87 : countMembersInRadius(position, radius) 88 : { 89 9 : return this.countInRadius(position, radius, true); 90 : } 91 : 92 : /** 93 : * Counts the number of tiles not marked in the tileclass within the given radius of the given position. 94 : */ 95 : countNonMembersInRadius(position, radius) 96 : { 97 6 : return this.countInRadius(position, radius, false); 98 : } 99 : }