Files
project-hood/addons/TileMapDual/DisplayLayer.gd

103 lines
3.6 KiB
GDScript

##[br] A single TileMapLayer whose purpose is to display tiles to maintain the Dual Grid illusion.
##[br] Its contents are automatically computed and updated based on:
##[br] - the contents of the parent TileMapDual
##[br] - the rules set in its assigned TerrainLayer
class_name DisplayLayer
extends TileMapLayer
##[br] How much to offset this DisplayLayer relative to the main TileMapDual grid.
##[br] This is independent of tile size.
var offset: Vector2
## See TileSetWatcher.gd
var _tileset_watcher: TileSetWatcher
## See TerrainDual.gd
var _terrain: TerrainLayer
func _init(
world: TileMapDual,
tileset_watcher: TileSetWatcher,
fields: Dictionary,
layer: TerrainLayer
) -> void:
#print('initializing Layer...')
update_properties(world)
offset = fields.offset
_tileset_watcher = tileset_watcher
_terrain = layer
tile_set = tileset_watcher.tile_set
tileset_watcher.tileset_resized.connect(reposition, 1)
reposition()
## Adjusts the position of this DisplayLayer based on the tile set's tile_size
func reposition() -> void:
position = offset * Vector2(_tileset_watcher.tile_size)
## Copies properties from parent TileMapDual to child display tilemap
func update_properties(parent: TileMapDual) -> void:
# Both tilemaps must be the same, so we copy all relevant properties
# Tilemap
# already covered by parent._tileset_watcher
# Rendering
self.y_sort_origin = parent.y_sort_origin
self.x_draw_order_reversed = parent.x_draw_order_reversed
self.rendering_quadrant_size = parent.rendering_quadrant_size
# Physics
self.collision_enabled = parent.collision_enabled
self.use_kinematic_bodies = parent.use_kinematic_bodies
self.collision_visibility_mode = parent.collision_visibility_mode
# Navigation
self.navigation_enabled = parent.navigation_enabled
self.navigation_visibility_mode = parent.navigation_visibility_mode
# Canvas item properties
self.show_behind_parent = parent.show_behind_parent
self.top_level = parent.top_level
self.light_mask = parent.light_mask
self.visibility_layer = parent.visibility_layer
self.y_sort_enabled = parent.y_sort_enabled
self.modulate = parent.modulate
self.self_modulate = parent.self_modulate
# NOTE: parent material takes priority over the current shaders, causing the world tiles to show up
self.use_parent_material = parent.use_parent_material
# Save any manually introduced Material change:
self.material = parent.display_material
## Updates all display tiles to reflect the current changes.
func update_tiles_all(cache: TileCache) -> void:
update_tiles(cache, cache.cells.keys())
## Update all display tiles affected by the world cells
func update_tiles(cache: TileCache, updated_world_cells: Array) -> void:
#push_warning('updating tiles')
var already_updated := Set.new()
for path: Array in _terrain.display_to_world_neighborhood:
path = path.map(Util.reverse_neighbor)
for world_cell: Vector2i in updated_world_cells:
var display_cell := follow_path(world_cell, path)
if already_updated.insert(display_cell):
update_tile(cache, display_cell)
## Updates a specific world cell.
func update_tile(cache: TileCache, cell: Vector2i) -> void:
var get_cell_at_path := func(path): return cache.get_terrain_at(follow_path(cell, path))
var terrain_neighbors := _terrain.display_to_world_neighborhood.map(get_cell_at_path)
var mapping: Dictionary = _terrain.apply_rule(terrain_neighbors, cell)
var sid: int = mapping.sid
var tile: Vector2i = mapping.tile
set_cell(cell, sid, tile)
## Finds the neighbor of a given cell by following a path of CellNeighbors
func follow_path(cell: Vector2i, path: Array) -> Vector2i:
for neighbor: TileSet.CellNeighbor in path:
cell = get_neighbor_cell(cell, neighbor)
return cell