diff --git a/nodes/combat_map.gd b/nodes/combat_map.gd index 1dca244..75674fe 100644 --- a/nodes/combat_map.gd +++ b/nodes/combat_map.gd @@ -5,6 +5,7 @@ extends Node2D @export var map_layout: MapLayout @onready var tile_map: TileMapLayer = %TerrainLayer @onready var highlight_map: GridOverlay = %OverlayLayer +@onready var wall_renderer: WallRenderer = %WallRenderer const TILE_SIZE := 100.0 const SOURCE_ID: int = 0 @@ -108,21 +109,7 @@ func is_tile_valid(coords: Vector2i) -> bool: func draw_room_walls() -> void: if not map_layout: return - var walls := map_layout.get_walls() - for wall in walls: - var from_world := coords_to_world(wall[0]) + Vector2(TILE_SIZE / 2, TILE_SIZE / 2) - var to_world := coords_to_world(wall[1]) + Vector2(TILE_SIZE / 2, TILE_SIZE / 2) - var midpoint := (from_world + to_world) / 2 - var diff := to_world - from_world - var wall_dir := Vector2(-diff.y, diff.x).normalized() - var half_len := TILE_SIZE / 2 - - var line := Line2D.new() - line.add_point(midpoint - wall_dir * half_len) - line.add_point(midpoint + wall_dir * half_len) - line.width = 4.0 - line.default_color = Color(0.6, 0.5, 0.4) - add_child(line) + wall_renderer.draw_walls_for_layout(map_layout) func load_from_layout() -> void: diff --git a/nodes/wall_renderer.gd b/nodes/wall_renderer.gd new file mode 100644 index 0000000..720d2c6 --- /dev/null +++ b/nodes/wall_renderer.gd @@ -0,0 +1,182 @@ +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. + +const TILE_SIZE := 100.0 + +## 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) + +## Wall thickness in game pixels (how far the border extends into the tile) +const WALL_THICKNESS := 20.0 +## Half the tile edge length +const HALF_EDGE := TILE_SIZE / 2.0 + +@export var atlas_texture: Texture2D + + +func draw_walls_for_layout(map_layout: MapLayout) -> void: + _clear_walls() + if not map_layout or not atlas_texture: + return + + var tile_edges := _collect_tile_edges(map_layout) + for tile in tile_edges: + var edges: Array = tile_edges[tile] + _draw_tile_walls(tile, edges) + + +func _clear_walls() -> void: + for child in get_children(): + child.queue_free() + + +func _collect_tile_edges(map_layout: MapLayout) -> Dictionary: + ## Returns {Vector2i: Array[StringName]} mapping each tile to its wall edge directions. + var tile_edges: Dictionary = {} + var walls := map_layout.get_walls() + + for wall in walls: + var tile_a: Vector2i = wall[0] + var tile_b: Vector2i = wall[1] + var diff: Vector2i = tile_b - tile_a + + # Determine which edge of tile_a faces the wall + 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) + + # Determine which edge of tile_b faces the wall (opposite direction) + 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) + + return tile_edges + + +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 _draw_tile_walls(tile: Vector2i, edges: Array) -> void: + var tile_origin := Vector2(tile) * TILE_SIZE + + for edge in edges: + match edge: + &"left": + _draw_edge_segments(tile_origin, edge) + &"right": + _draw_edge_segments(tile_origin, edge) + &"top": + _draw_edge_segments(tile_origin, edge) + &"bottom": + _draw_edge_segments(tile_origin, edge) + + # TODO: Outer corner segments + _draw_outer_corners(tile, tile_origin, edges) + + # TODO: Inner corner segments (for non-rectangular room support) + _draw_inner_corners(tile, tile_origin, edges) + + +func _draw_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, HALF_EDGE) + seg_b_offset = Vector2(0, 0) + &"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(TILE_SIZE - WALL_THICKNESS, HALF_EDGE) + seg_b_offset = Vector2(TILE_SIZE - WALL_THICKNESS, 0) + &"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(HALF_EDGE, 0) + seg_b_offset = Vector2(0, 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(HALF_EDGE, TILE_SIZE - WALL_THICKNESS) + seg_b_offset = Vector2(0, TILE_SIZE - WALL_THICKNESS) + + _create_segment_sprite(tile_origin + seg_a_offset, seg_a_size, seg_a_rect) + _create_segment_sprite(tile_origin + seg_b_offset, seg_b_size, seg_b_rect) + + +func _create_segment_sprite(pos: Vector2, target_size: Vector2, source_rect: Rect2) -> void: + var atlas := AtlasTexture.new() + atlas.atlas = atlas_texture + atlas.region = source_rect + + var sprite := Sprite2D.new() + sprite.texture = atlas + sprite.centered = false + sprite.position = pos + sprite.scale = Vector2( + target_size.x / source_rect.size.x, + target_size.y / source_rect.size.y + ) + add_child(sprite) + + +func _draw_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 _draw_inner_corners(_tile: Vector2i, _tile_origin: Vector2, _edges: Array) -> void: + # TODO: Implement inner corner segments for non-rectangular rooms + # Check diagonal neighbors where both adjacent cardinal neighbors are floor + # but the diagonal is a wall/void. + pass diff --git a/nodes/wall_renderer.gd.uid b/nodes/wall_renderer.gd.uid new file mode 100644 index 0000000..bcba096 --- /dev/null +++ b/nodes/wall_renderer.gd.uid @@ -0,0 +1 @@ +uid://c4f1vflwd81b8 diff --git a/prefabs/combat_map.tscn b/prefabs/combat_map.tscn index 07a9bda..c74b48e 100644 --- a/prefabs/combat_map.tscn +++ b/prefabs/combat_map.tscn @@ -6,6 +6,8 @@ [ext_resource type="Script" uid="uid://cxl38x2m6sj3w" path="res://scripts/battle/grid_overlay.gd" id="4_jelju"] [ext_resource type="Texture2D" uid="uid://b1ks72fiesfrm" path="res://assets/sprites/combat_map_ui.BMP" id="5_mycp7"] [ext_resource type="Texture2D" uid="uid://65rmoynep5hy" path="res://assets/sprites/MP000A.BMP" id="6_muxvo"] +[ext_resource type="Script" path="res://nodes/wall_renderer.gd" id="7_wallr"] +[ext_resource type="Texture2D" uid="uid://b20mhn7ca5xyo" path="res://assets/sprites/aux_terrain.BMP" id="8_auxtr"] [sub_resource type="Resource" id="Resource_vcj5e"] script = ExtResource("2_8rn0j") @@ -83,3 +85,9 @@ offset = Vector2(50, 50) [node name="TerrainLayer" type="TileMapLayer" parent="." unique_id=1201875024] unique_name_in_owner = true tile_set = SubResource("TileSet_e2u25") + +[node name="WallRenderer" type="Node2D" parent="."] +unique_name_in_owner = true +z_index = 1 +script = ExtResource("7_wallr") +atlas_texture = ExtResource("8_auxtr")