class_name WallRenderer extends Node2D ## Renders wall textures by sampling segments from the aux_terrain texture atlas ## and compositing them onto tile edges. Each edge is made of two half-segments. ## Source atlas rects (x, y, w, h) from aux_terrain.BMP ## Each edge has two half-segments that together span the full tile edge. # -- Left edge -- const LEFT_UPPER_RECT := Rect2(0, 103, 20, 50) const LEFT_LOWER_RECT := Rect2(0, 53, 20, 50) # -- Right edge -- const RIGHT_UPPER_RECT := Rect2(186, 103, 20, 50) const RIGHT_LOWER_RECT := Rect2(186, 53, 20, 50) # -- Top edge -- const TOP_LEFT_RECT := Rect2(103, 0, 50, 20) const TOP_RIGHT_RECT := Rect2(53, 0, 50, 20) # -- Bottom edge -- const BOTTOM_LEFT_RECT := Rect2(103, 186, 50, 20) const BOTTOM_RIGHT_RECT := Rect2(53, 186, 50, 20) # -- Inner corners (drawn where two perpendicular wall edges meet) -- const INNER_CORNER_UPPER_LEFT_RECT := Rect2(0, 0, 50, 50) const INNER_CORNER_UPPER_RIGHT_RECT := Rect2(156, 0, 50, 50) const INNER_CORNER_LOWER_LEFT_RECT := Rect2(0, 156, 50, 50) const INNER_CORNER_LOWER_RIGHT_RECT := Rect2(156, 156, 50, 50) # -- Openings (drawn on top of wall segments at doorway edges) -- ## Vertical opening: tiles separated on y-axis (north-south doorway through a horizontal wall) const VERTICAL_OPENING_RECT := Rect2(206, 36, 36, 42) ## Horizontal opening: tiles separated on x-axis (east-west doorway through a vertical wall) const HORIZONTAL_OPENING_RECT := Rect2(210, 0, 41, 32) ## Wall thickness in game pixels (how far the border extends into the tile) const WALL_THICKNESS := 20.0 ## Inner corner piece size in game pixels (quarter of a tile) const CORNER_SIZE := 50.0 ## Half the tile edge length var HALF_EDGE: float: get: return BattleMapHelper.TILE_SIZE / 2.0 @export var atlas_texture: Texture2D # Each entry is [dest_rect: Rect2, source_rect: Rect2] var _segments: Array = [] func draw_walls_for_layout(map_layout: MapLayout) -> void: _segments.clear() if not map_layout or not atlas_texture: queue_redraw() return var tile_edges := _collect_tile_edges(map_layout) for tile in tile_edges: var edges: Array = tile_edges[tile] _build_tile_walls(tile, edges) _build_opening_sprites(map_layout) queue_redraw() func _draw() -> void: if not atlas_texture: return for seg in _segments: draw_texture_rect_region(atlas_texture, seg[0], seg[1]) func _collect_tile_edges(map_layout: MapLayout) -> Dictionary: ## Returns {Vector2i: Array[StringName]} mapping each tile to its wall edge directions. ## Includes both true walls and opening edges, so wall sprites are drawn underneath openings. var tile_edges: Dictionary = {} for edge_pair in map_layout.get_walls(): _add_edge_pair(tile_edges, edge_pair, map_layout) for edge_pair in map_layout.get_openings(): _add_edge_pair(tile_edges, edge_pair, map_layout) return tile_edges func _add_edge_pair(tile_edges: Dictionary, edge_pair: Array, map_layout: MapLayout) -> void: var tile_a: Vector2i = edge_pair[0] var tile_b: Vector2i = edge_pair[1] var diff: Vector2i = tile_b - tile_a var edge_a := _direction_to_edge(diff) if edge_a != &"": if not tile_edges.has(tile_a): tile_edges[tile_a] = [] tile_edges[tile_a].append(edge_a) var edge_b := _direction_to_edge(-diff) if edge_b != &"" and map_layout.is_tile_valid(tile_b): if not tile_edges.has(tile_b): tile_edges[tile_b] = [] tile_edges[tile_b].append(edge_b) func _direction_to_edge(dir: Vector2i) -> StringName: match dir: Vector2i.RIGHT: return &"right" Vector2i.LEFT: return &"left" Vector2i.UP: return &"top" Vector2i.DOWN: return &"bottom" return &"" func _build_tile_walls(tile: Vector2i, edges: Array) -> void: var tile_origin := Vector2(tile) * BattleMapHelper.TILE_SIZE for edge in edges: _build_edge_segments(tile_origin, edge) # TODO: Outer corner segments _build_outer_corners(tile, tile_origin, edges) # Inner corner segments (for non-rectangular room support) _build_inner_corners(tile, tile_origin, edges) func _build_edge_segments(tile_origin: Vector2, edge: StringName) -> void: var seg_a_rect: Rect2 var seg_b_rect: Rect2 var seg_a_offset: Vector2 var seg_b_offset: Vector2 var seg_a_size: Vector2 var seg_b_size: Vector2 match edge: &"left": seg_a_rect = LEFT_UPPER_RECT seg_b_rect = LEFT_LOWER_RECT seg_a_size = Vector2(WALL_THICKNESS, HALF_EDGE) seg_b_size = Vector2(WALL_THICKNESS, HALF_EDGE) seg_a_offset = Vector2(0, 0) seg_b_offset = Vector2(0, HALF_EDGE) &"right": seg_a_rect = RIGHT_UPPER_RECT seg_b_rect = RIGHT_LOWER_RECT seg_a_size = Vector2(WALL_THICKNESS, HALF_EDGE) seg_b_size = Vector2(WALL_THICKNESS, HALF_EDGE) seg_a_offset = Vector2(BattleMapHelper.TILE_SIZE - WALL_THICKNESS, 0) seg_b_offset = Vector2(BattleMapHelper.TILE_SIZE - WALL_THICKNESS, HALF_EDGE) &"top": seg_a_rect = TOP_LEFT_RECT seg_b_rect = TOP_RIGHT_RECT seg_a_size = Vector2(HALF_EDGE, WALL_THICKNESS) seg_b_size = Vector2(HALF_EDGE, WALL_THICKNESS) seg_a_offset = Vector2(0, 0) seg_b_offset = Vector2(HALF_EDGE, 0) &"bottom": seg_a_rect = BOTTOM_LEFT_RECT seg_b_rect = BOTTOM_RIGHT_RECT seg_a_size = Vector2(HALF_EDGE, WALL_THICKNESS) seg_b_size = Vector2(HALF_EDGE, WALL_THICKNESS) seg_a_offset = Vector2(0, BattleMapHelper.TILE_SIZE - WALL_THICKNESS) seg_b_offset = Vector2(HALF_EDGE, BattleMapHelper.TILE_SIZE - WALL_THICKNESS) _queue_segment(tile_origin + seg_a_offset, seg_a_size, seg_a_rect) _queue_segment(tile_origin + seg_b_offset, seg_b_size, seg_b_rect) func _queue_segment(pos: Vector2, target_size: Vector2, source_rect: Rect2) -> void: _segments.append([Rect2(pos, target_size), source_rect]) func _build_opening_sprites(map_layout: MapLayout) -> void: ## Composites opening (doorway) sprites on top of the wall segments at opening edges. ## Each opening is split in half across the shared edge, half drawn on each tile. for opening in map_layout.get_openings(): var tile_a: Vector2i = opening[0] var tile_b: Vector2i = opening[1] var diff: Vector2i = tile_b - tile_a # Normalize so the pair is ordered along the positive axis (tile_a < tile_b). if diff == Vector2i.LEFT or diff == Vector2i.UP: var swap := tile_a tile_a = tile_b tile_b = swap diff = -diff var origin_a := Vector2(tile_a) * BattleMapHelper.TILE_SIZE var origin_b := Vector2(tile_b) * BattleMapHelper.TILE_SIZE if diff == Vector2i.DOWN: _queue_vertical_opening(origin_a, origin_b) elif diff == Vector2i.RIGHT: _queue_horizontal_opening(origin_a, origin_b) func _queue_vertical_opening(origin_upper: Vector2, origin_lower: Vector2) -> void: # Vertical opening: tiles vertically adjacent; horizontal wall edge between them. var src := VERTICAL_OPENING_RECT var w: float = src.size.x var h_total: float = src.size.y var h_upper: float = floorf(h_total / 2.0) # 14 var h_lower: float = h_total - h_upper # 15 var x_offset := (BattleMapHelper.TILE_SIZE - w) / 2.0 var src_upper := Rect2(src.position, Vector2(w, h_upper)) var src_lower := Rect2(src.position + Vector2(0, h_upper), Vector2(w, h_lower)) _queue_segment(origin_upper + Vector2(x_offset, BattleMapHelper.TILE_SIZE - h_upper), Vector2(w, h_upper), src_upper) _queue_segment(origin_lower + Vector2(x_offset, 0), Vector2(w, h_lower), src_lower) func _queue_horizontal_opening(origin_left: Vector2, origin_right: Vector2) -> void: # Horizontal opening: tiles horizontally adjacent; vertical wall edge between them. var src := HORIZONTAL_OPENING_RECT var w_total: float = src.size.x var h: float = src.size.y var w_left: float = floorf(w_total / 2.0) # 14 var w_right: float = w_total - w_left # 14 var y_offset := (BattleMapHelper.TILE_SIZE - h) / 2.0 var src_left := Rect2(src.position, Vector2(w_left, h)) var src_right := Rect2(src.position + Vector2(w_left, 0), Vector2(w_right, h)) _queue_segment(origin_left + Vector2(BattleMapHelper.TILE_SIZE - w_left, y_offset), Vector2(w_left, h), src_left) _queue_segment(origin_right + Vector2(0, y_offset), Vector2(w_right, h), src_right) func _build_outer_corners(_tile: Vector2i, _tile_origin: Vector2, _edges: Array) -> void: # TODO: Implement outer corner segments # Check pairs of adjacent edges (e.g., "top" + "left" → top-left outer corner) # and draw the corner piece from the atlas. pass func _build_inner_corners(_tile: Vector2i, tile_origin: Vector2, edges: Array) -> void: ## Draws decorative corner pieces wherever two perpendicular wall edges meet ## on the same tile (e.g., a top wall + left wall produces an upper-left corner). var has_top := edges.has(&"top") var has_bottom := edges.has(&"bottom") var has_left := edges.has(&"left") var has_right := edges.has(&"right") var corner_size := Vector2(CORNER_SIZE, CORNER_SIZE) if has_top and has_left: _queue_segment( tile_origin + Vector2(0, 0), corner_size, INNER_CORNER_UPPER_LEFT_RECT ) if has_top and has_right: _queue_segment( tile_origin + Vector2(BattleMapHelper.TILE_SIZE - CORNER_SIZE, 0), corner_size, INNER_CORNER_UPPER_RIGHT_RECT ) if has_bottom and has_left: _queue_segment( tile_origin + Vector2(0, BattleMapHelper.TILE_SIZE - CORNER_SIZE), corner_size, INNER_CORNER_LOWER_LEFT_RECT ) if has_bottom and has_right: _queue_segment( tile_origin + Vector2(BattleMapHelper.TILE_SIZE - CORNER_SIZE, BattleMapHelper.TILE_SIZE - CORNER_SIZE), corner_size, INNER_CORNER_LOWER_RIGHT_RECT )