##[br] A Node designed to hold and manage up to 2 DisplayLayer children. ##[br] See DisplayLayer.gd for details. class_name Display extends Node2D ## See TerrainDual.gd var terrain: TerrainDual ## See TileSetWatcher.gd var _tileset_watcher: TileSetWatcher ## The parent TileMapDual to base the terrains off of. @export var world: TileMapDual ## Creates a new Display that updates when the TileSet updates. func _init(world: TileMapDual, tileset_watcher: TileSetWatcher) -> void: #print('initializing Display...') self.world = world _tileset_watcher = tileset_watcher terrain = TerrainDual.new(tileset_watcher) terrain.changed.connect(_terrain_changed, 1) world_tiles_changed.connect(_world_tiles_changed, 1) # let parent materal through to the displaylayers use_parent_material = true ## Activates when the TerrainDual changes. func _terrain_changed() -> void: cached_cells.update(world) _delete_layers() if _tileset_watcher.tile_set != null: _create_layers() ## Emitted when the tiles in the map have been edited. signal world_tiles_changed(changed: Array) func _world_tiles_changed(changed: Array) -> void: #print('SIGNAL EMITTED: world_tiles_changed(%s)' % {'changed': changed}) for child in get_children(true): child.update_tiles(cached_cells, changed) ## Initializes and configures new DisplayLayers according to the grid shape. func _create_layers() -> void: #print('GRID SHAPE: %s' % _tileset_watcher.grid_shape) var grid: Array = GRIDS[_tileset_watcher.grid_shape] for i in grid.size(): var layer_config: Dictionary = grid[i] #print('layer_config: %s' % layer_config) var layer := DisplayLayer.new(world, _tileset_watcher, layer_config, terrain.layers[i]) add_child(layer) layer.update_tiles_all(cached_cells) ## Deletes all of the DisplayLayers. func _delete_layers() -> void: for child in get_children(true): child.queue_free() ## The TileCache computed from the last time update() was called. var cached_cells := TileCache.new() ## Updates the display based on the cells changed in the world TileMapDual. func update(updated: Array) -> void: if _tileset_watcher.tile_set == null: return _update_properties() if not updated.is_empty(): cached_cells.update(world, updated) world_tiles_changed.emit(updated) ## Activates when the properties of the parent TileMapDual have been edited. func _update_properties() -> void: for child in get_children(true): child.update_properties(world) # TODO: phase out GridShape and simply transpose everything when the offset axis is vertical ##[br] Returns what kind of grid a TileSet is. ##[br] Will default to SQUARE if Godot decides to add a new TileShape. static func tileset_gridshape(tile_set: TileSet) -> GridShape: var hori: bool = tile_set.tile_offset_axis == TileSet.TILE_OFFSET_AXIS_HORIZONTAL match tile_set.tile_shape: TileSet.TileShape.TILE_SHAPE_SQUARE: return GridShape.SQUARE TileSet.TileShape.TILE_SHAPE_ISOMETRIC: return GridShape.ISO TileSet.TileShape.TILE_SHAPE_HALF_OFFSET_SQUARE: return GridShape.HALF_OFF_HORI if hori else GridShape.HALF_OFF_VERT TileSet.TileShape.TILE_SHAPE_HEXAGON: return GridShape.HEX_HORI if hori else GridShape.HEX_VERT _: return GridShape.SQUARE ## Every meaningfully different TileSet.tile_shape * TileSet.tile_offset_axis combination. enum GridShape { SQUARE, ISO, HALF_OFF_HORI, HALF_OFF_VERT, HEX_HORI, HEX_VERT, } ##[br] How to deal with every available GridShape. ##[br] See DisplayLayer.gd for more information about these fields. const GRIDS: Dictionary = { GridShape.SQUARE: [ { # [] 'offset': Vector2(-0.5, -0.5), } ], GridShape.ISO: [ { # <> 'offset': Vector2(0, -0.5), } ], GridShape.HALF_OFF_HORI: [ { # v 'offset': Vector2(0.0, -0.5), }, { # ^ 'offset': Vector2(-0.5, -0.5), }, ], GridShape.HALF_OFF_VERT: [ { # > 'offset': Vector2(-0.5, 0.0), }, { # < 'offset': Vector2(-0.5, -0.5), }, ], GridShape.HEX_HORI: [ { # v 'offset': Vector2(0.0, -3.0 / 8.0), }, { # ^ 'offset': Vector2(-0.5, -3.0 / 8.0), }, ], GridShape.HEX_VERT: [ { # > 'offset': Vector2(-3.0 / 8.0, 0.0), }, { # < 'offset': Vector2(-3.0 / 8.0, -0.5), }, ], }