From a88839b396c6e06f33012f19ef45cb305733d377 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Tue, 31 Mar 2026 22:08:57 +0800 Subject: [PATCH] feat: implement core game scene, player logic, and modular manager architecture for Tekton Dash --- scenes/main.gd | 26 ++++----- scenes/player.gd | 9 +-- scripts/managers/player_movement_manager.gd | 2 +- scripts/managers/static_tekton_manager.gd | 62 +++++++++------------ 4 files changed, 38 insertions(+), 61 deletions(-) diff --git a/scenes/main.gd b/scenes/main.gd index 2595216..95404f0 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -1171,7 +1171,7 @@ func _precalculate_static_positions(): # Calculate 3 spots and STORE them var points: Array[Vector2i] = [] - points = static_tekton_manager.calculate_spawn_points(3, enhanced_gridmap) + points = static_tekton_manager.calculate_spawn_points(5, enhanced_gridmap) reserved_static_positions = points print("[Main] Pre-calculated Static Tekton Positions: %s" % str(reserved_static_positions)) @@ -1193,22 +1193,16 @@ func spawn_static_tektons(): # Use pre-calculated points if available var spawn_points: Array[Vector2i] = [] if not reserved_static_positions.is_empty(): - spawn_points = reserved_static_positions + # Pick exactly 3 from the 5 reserved potential spots as requested + var possible_points = reserved_static_positions.duplicate() + possible_points.shuffle() + spawn_points = possible_points.slice(0, 3) else: - # If pre-calculation failed, we MUST check for player overlaps now - var raw_points = static_tekton_manager.calculate_spawn_points(3, enhanced_gridmap) - var all_players = get_tree().get_nodes_in_group("Players") - - for p_spot in raw_points: - var is_overlapping = false - for player in all_players: - if abs(p_spot.x - player.current_position.x) <= 2 and abs(p_spot.y - player.current_position.y) <= 2: - is_overlapping = true - break - if not is_overlapping: - spawn_points.append(p_spot) - - reserved_static_positions = spawn_points # Save them + # Fallback if not pre-calculated + var raw_points = static_tekton_manager.calculate_spawn_points(5, enhanced_gridmap) + raw_points.shuffle() + spawn_points = raw_points.slice(0, 3) + reserved_static_positions = raw_points # Save all 5 for player avoidance print("[Main] Spawning Static Tektons at: %s" % str(spawn_points)) diff --git a/scenes/player.gd b/scenes/player.gd index 3c5c414..f4c0efe 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -1345,20 +1345,13 @@ func is_position_occupied(pos: Vector2i) -> bool: if p.is_player_moving and p.target_position == pos: return true - # Prevent overlap with Static Tekton Stands (Exactly the 3x3 area) - if enhanced_gridmap: + # Prevent overlap with Static Tekton Stands (Exactly the 3x3 area) using the actual spawned nodes for stand in get_tree().get_nodes_in_group("StaticTektonStands"): var local_pos = enhanced_gridmap.to_local(stand.global_position) var stand_map_pos = enhanced_gridmap.local_to_map(local_pos) if abs(pos.x - stand_map_pos.x) <= 1 and abs(pos.y - stand_map_pos.z) <= 1: return true - var main_node = get_tree().get_root().get_node_or_null("Main") - if main_node and "reserved_static_positions" in main_node: - for reserved in main_node.reserved_static_positions: - if abs(pos.x - reserved.x) <= 1 and abs(pos.y - reserved.y) <= 1: - return true - return false func find_valid_starting_position() -> Vector2i: diff --git a/scripts/managers/player_movement_manager.gd b/scripts/managers/player_movement_manager.gd index 7fe11b2..1107a8d 100644 --- a/scripts/managers/player_movement_manager.gd +++ b/scripts/managers/player_movement_manager.gd @@ -95,7 +95,7 @@ func simple_move_to(grid_position: Vector2i) -> bool: if is_wall_passable: var impenetrable_coords = [ Vector2i(0,0), Vector2i(1,0), Vector2i(2,0), Vector2i(3,0), Vector2i(4,0), Vector2i(5,0), Vector2i(6,0), Vector2i(7,0), Vector2i(8,0), Vector2i(9,0), Vector2i(10,0), Vector2i(13,0), Vector2i(19,0), Vector2i(20,0), Vector2i(21,0), Vector2i(22,0), - Vector2i(0,1), Vector2i(1,1), Vector2i(2,1), Vector2i(3,1), Vector2i(6,1), + Vector2i(0,1), Vector2i(2,1), Vector2i(3,1), Vector2i(6,1), Vector2i(0,2), Vector2i(1,2), Vector2i(2,2), Vector2i(3,2), Vector2i(17,9), Vector2i(18,9), Vector2i(19,9), Vector2i(20,9), Vector2i(21,9), Vector2i(22,9), Vector2i(11,10), Vector2i(12,10), Vector2i(13,10), Vector2i(15,10), Vector2i(16,10), Vector2i(17,10), Vector2i(18,10), Vector2i(19,10), Vector2i(20,10), Vector2i(21,10), Vector2i(22,10), diff --git a/scripts/managers/static_tekton_manager.gd b/scripts/managers/static_tekton_manager.gd index 827a75a..3f97dd5 100644 --- a/scripts/managers/static_tekton_manager.gd +++ b/scripts/managers/static_tekton_manager.gd @@ -13,48 +13,38 @@ const STATIC_CONTROLLER_SCRIPT = "res://scripts/static_tekton_controller.gd" # Mid-Left, Mid-Mid, Mid-Right # Bot-Left, Bot-Mid, Bot-Right -func calculate_spawn_points(count: int, gridmap: Node) -> Array[Vector2i]: +func calculate_spawn_points(_count: int, gridmap: Node) -> Array[Vector2i]: """ - Calculates random spawn positions for static tektons. - Returns an Array of Vector2i positions. + Calculates the 5 fixed potential spawn positions for static tektons. + Corners: (1,1), (W-2,1), (1,H-2), (W-2,H-2) + Center: (W/2, H/2) + Returns exactly 5 spots if possible. """ - if count <= 0 or not gridmap: return [] + if not gridmap: return [] - print("[StaticTektonManager] Calculating static tekton positions (Fixed 5-Zone + Center)...") - - # 1. Define Zones (3x3 Grid) var width = gridmap.columns - var depth = gridmap.rows - var zone_w = width / 3 - var zone_d = depth / 3 + var height = gridmap.rows - var zones = [] - for z in range(3): - for x in range(3): - zones.append(Rect2i(x * zone_w, z * zone_d, zone_w, zone_d)) + print("[StaticTektonManager] Calculating static tekton positions (Fixed 5-Spots)...") + + # Fixed Spots + var spots: Array[Vector2i] = [ + Vector2i(1, 1), # Top-Left + Vector2i(width - 2, 1), # Top-Right + Vector2i(1, height - 2), # Bottom-Left + Vector2i(width - 2, height - 2), # Bottom-Right + Vector2i(width / 2, height / 2) # Center + ] + + # Validate spots (ensure they are walkable and have room) + var valid_spots: Array[Vector2i] = [] + for spot in spots: + if _is_valid_3x3(spot, gridmap): + valid_spots.append(spot) + else: + print("[StaticTektonManager] Warning: Spot %s is not a valid 3x3 walkable area!" % str(spot)) - # 2. Select Fixed Targets: TL(0), TR(2), Center(4), BL(6), BR(8) - # This ensures they are never adjacent (always separated by a middle zone) - var target_indices = [0, 2, 6, 8, 4] - target_indices.shuffle() # Randomize which of the 5 zones we pick - - # If count < 5, we prioritize corners then center - # If count > 5, we only return 5 because that's the max safe non-adjacent set in 3x3 - var spawn_points: Array[Vector2i] = [] - - for zone_idx in target_indices: - if spawn_points.size() >= count: - break - var zone = zones[zone_idx] - - # Determine Position Type for Bias - # 0:TL, 1:TR, 2:BL, 3:BR, 4:Center - # We pass zone_idx to _pick_spot_in_zone to snap corners - var pos = _pick_spot_in_zone(zone, gridmap, zone_idx) - if pos != Vector2i(-1, -1): - spawn_points.append(pos) - - return spawn_points + return valid_spots func _pick_spot_in_zone_biased(zone: Rect2i, gridmap: Node, type: int) -> Vector2i: # type: 0=TL, 1=TR, 2=BL, 3=BR, 4=Center