class_name TileShape extends RefCounted ## Neighbourhoods on the tile grid, so that a style can draw each tile to fit ## the tiles around it, and a stable number per tile for small variations. ## Bits of a neighbour mask, clockwise from north. const N := 1 const NE := 2 const E := 4 const SE := 8 const S := 16 const SW := 32 const W := 64 const NW := 128 ## Where the neighbour of each bit lies, in the order of the bits. const OFFSETS: Array[Vector2i] = [ Vector2i(0, -1), Vector2i(1, -1), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1), Vector2i(-1, 1), Vector2i(-1, 0), Vector2i(-1, -1), ] ## One byte per tile of `codes`: 1 if `members` holds its code, else 0. static func flags(codes: PackedByteArray, members: Array[int]) -> PackedByteArray: var result := PackedByteArray() result.resize(codes.size()) for index in codes.size(): result[index] = 1 if members.has(codes[index]) else 0 return result ## The neighbours of `tile` whose flag is 1, as a mask of the bits above, on ## a map of `width` by `height` tiles. Beyond the edge of the map, every ## neighbour counts as set if `outside_set` is true. static func mask(tile_flags: PackedByteArray, width: int, height: int, tile: Vector2i, outside_set: bool) -> int: var result := 0 for bit in 8: var at := tile + OFFSETS[bit] var inside := at.x >= 0 and at.y >= 0 and at.x < width and at.y < height if (inside and tile_flags[at.y * width + at.x] == 1) or (not inside and outside_set): result |= 1 << bit return result ## A number from 0 to 2147483647 that is the same for `tile` every time and ## looks random from one tile to the next. static func variant(tile: Vector2i) -> int: var h := (tile.x * 374761393 + tile.y * 668265263) & 0x7fffffff h = ((h ^ (h >> 13)) * 1274126177) & 0x7fffffff return h ^ (h >> 16)