diff --git a/addons/enhanced_gridmap/meshlibrary/default.tres b/addons/enhanced_gridmap/meshlibrary/default.tres index 360534f..f86b4d4 100644 --- a/addons/enhanced_gridmap/meshlibrary/default.tres +++ b/addons/enhanced_gridmap/meshlibrary/default.tres @@ -180,7 +180,7 @@ item/15/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, item/15/navigation_layers = 1 item/16/name = "wall" item/16/mesh = ExtResource("9_uwjsj") -item/16/mesh_transform = Transform3D(2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.5) +item/16/mesh_transform = Transform3D(1.68, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) item/16/mesh_cast_shadow = 1 item/16/shapes = [] item/16/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) diff --git a/scenes/safe_zone_wall.tscn b/scenes/safe_zone_wall.tscn new file mode 100644 index 0000000..7bdc17f --- /dev/null +++ b/scenes/safe_zone_wall.tscn @@ -0,0 +1,24 @@ +[gd_scene format=3 uid="uid://b8yqx5v3n8u1p"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_wall"] +size = Vector3(1, 2, 0.1) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wall"] +albedo_color = Color(0.8, 0.2, 0.2, 0.8) +emission_enabled = true +emission = Color(1, 0, 0, 1) +emission_energy_multiplier = 0.5 + +[sub_resource type="BoxMesh" id="BoxMesh_wall"] +material = SubResource("StandardMaterial3D_wall") +size = Vector3(1, 2, 0.1) + +[node name="SafeZoneWall" type="StaticBody3D"] +collision_layer = 1 +collision_mask = 0 + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_wall") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("BoxShape3D_wall") diff --git a/scenes/wall_3d.tscn b/scenes/wall_3d.tscn new file mode 100644 index 0000000..9beaa03 --- /dev/null +++ b/scenes/wall_3d.tscn @@ -0,0 +1,18 @@ +[gd_scene format=3 uid="uid://cggmcgvdj6wxt"] + +[ext_resource type="ArrayMesh" uid="uid://dtr46jmckif0p" path="res://assets/models/meshes/block.res" id="1_block"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_wall"] +size = Vector3(1, 1.5, 1) + +[node name="Wall3D" type="StaticBody3D" unique_id=992511920] +collision_mask = 0 + +[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1405008923] +transform = Transform3D(1.68, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +mesh = ExtResource("1_block") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1446599023] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.35764623, 0) +shape = SubResource("BoxShape3D_wall") +debug_color = Color(0.94447005, 0.20628157, 0.3074098, 0.41960785) diff --git a/scripts/managers/player_movement_manager.gd b/scripts/managers/player_movement_manager.gd index a65b101..25143a8 100644 --- a/scripts/managers/player_movement_manager.gd +++ b/scripts/managers/player_movement_manager.gd @@ -100,9 +100,9 @@ func simple_move_to(grid_position: Vector2i) -> bool: print("[Move] Failed: Blocked by Item %d on Floor 1" % cell_item) return false - # PHYSICS CHECK: Ensure no static obstacles (like Stands) are blocking the path - if _is_position_blocked_by_physics(grid_position): - print("[Move] Failed: Blocked by physics raycast at %s" % grid_position) + # PHYSICS CHECK: Ensure no static obstacles (like Wall blocks or Stands) are blocking the path + if _is_path_blocked_by_physics(player.current_position, grid_position): + print("[Move] Failed: Path blocked by physics at %s" % grid_position) return false if player.is_position_occupied(grid_position): @@ -512,30 +512,42 @@ func _can_push_to(pos: Vector2i) -> bool: if _is_position_in_static_stand_area(pos): return false - if _is_position_blocked_by_physics(pos): + if _is_path_blocked_by_physics(player.current_position, pos): return false return true -func _is_position_blocked_by_physics(target_pos: Vector2i) -> bool: +func _is_path_blocked_by_physics(from_grid: Vector2i, to_grid: Vector2i) -> bool: if not player.is_inside_tree(): return false var space_state = player.get_world_3d().direct_space_state - var center_x = target_pos.x + 0.5 - var center_z = target_pos.y + 0.5 - var from = Vector3(center_x, 1.0, center_z) - var to = Vector3(center_x, 0.1, center_z) - var query = PhysicsRayQueryParameters3D.create(from, to) - query.collide_with_areas = false - query.collide_with_bodies = true + # 1. Path check: Block movement if a wall exists between the current and target tile + var from_v3 = Vector3(from_grid.x + 0.5, 0.5, from_grid.y + 0.5) + var to_v3 = Vector3(to_grid.x + 0.5, 0.5, to_grid.y + 0.5) - var result = space_state.intersect_ray(query) - if result: - if result.collider != player: - # ONLY block if it's a Static Tekton Stand - # Ignore GridMap floors/walls, which are handled by get_cell_item rules - if result.collider.name.find("StaticTektonStand") != -1 or result.collider.is_in_group("StaticTektonStands") or result.collider.has_method("is_stand"): - return true + var path_query = PhysicsRayQueryParameters3D.create(from_v3, to_v3) + path_query.collide_with_areas = false + path_query.collide_with_bodies = true + + var path_result = space_state.intersect_ray(path_query) + if path_result: + if path_result.collider != player: + # This correctly hits thin walls placed on tile boundaries + return true + + # 2. Target tile occupancy check: Block if a static object is in the middle of the tile + var target_from = Vector3(to_grid.x + 0.5, 1.0, to_grid.y + 0.5) + var target_to = Vector3(to_grid.x + 0.5, 0.1, to_grid.y + 0.5) + + var target_query = PhysicsRayQueryParameters3D.create(target_from, target_to) + target_query.collide_with_areas = false + target_query.collide_with_bodies = true + + var target_result = space_state.intersect_ray(target_query) + if target_result: + if target_result.collider != player: + # This hits objects like Stands that sit in the center of the tile + return true return false diff --git a/scripts/managers/stop_n_go_manager.gd b/scripts/managers/stop_n_go_manager.gd index 1ae8572..2822de0 100644 --- a/scripts/managers/stop_n_go_manager.gd +++ b/scripts/managers/stop_n_go_manager.gd @@ -21,6 +21,8 @@ const POWERUP_SPAWN_COUNT: int = 5 # Number of power-up tiles to spawn var powerups_spawned: bool = false var stop_phase_occurred: bool = false +var safe_zone_wall_scene = preload("res://scenes/wall_3d.tscn") + const PERMANENT_POWERUP_LOCATIONS: Array[Vector2i] = [ Vector2i(4, 3), # Area 1 Vector2i(8, 7), # Area 2 @@ -657,45 +659,18 @@ func sync_safe_zone(centers: Array, radius: int): if gridmap.get_cell_item(Vector3i(x, 0, z)) == TILE_WALKABLE: gridmap.set_cell_item(Vector3i(x, 0, z), TILE_SAFE) - # 2. Paint the walls (item ID 16) ON LAYER 1 to block movement - # We scan from -3 to +3 to handle symmetric wall indices around the 5x5 zone - for dx in range(-radius - 1, radius + 2): - for dz in range(-radius - 1, radius + 2): - var x = center.x + dx - var z = center.y + dz - - if x >= 0 and x < gridmap.columns and z >= 0 and z < gridmap.rows: - # big room logic: 5x5 span (Indices -2 to 2) - # North/West use -radius/-radius-1, South/East use radius/radius+1 - var is_north = dz == -radius - 1 and dx >= -radius and dx <= radius - var is_south = dz == radius and dx >= -radius and dx <= radius - var is_west = dx == -radius and dz >= -radius and dz <= radius - var is_east = dx == radius + 1 and dz >= -radius and dz <= radius - - var orientation = 0 - var is_wall = false - - if is_north: - orientation = 0 - is_wall = true - elif is_south: - orientation = 0 - is_wall = true - elif is_west: - orientation = 22 - is_wall = true - elif is_east: - orientation = 22 - is_wall = true - - if is_wall: - # Door logic: Skip center (0) on the respective border line - var is_door = (is_north and dx == 0) or (is_south and dx == 0) or \ - (is_west and dz == 0) or (is_east and dz == 0) - if is_door: - continue - - gridmap.set_cell_item(Vector3i(x, 1, z), 16, orientation) + # 2. Instantiate North and South walls (Horizontal) + for dx in range(-radius, radius + 1): + if dx == 0: continue # Opening + _instantiate_safe_zone_wall(Vector3(center.x + dx + 0.5, 0.0, center.y - radius), 0) + _instantiate_safe_zone_wall(Vector3(center.x + dx + 0.5, 0.0, center.y + radius + 1), 0) + + # 3. Instantiate East and West walls (Vertical - 4 walls each) + # From -2 to 2 (radius), with center opening = 4 walls per side + for dz in range(-radius, radius + 1): + if dz == 0: continue # Opening + _instantiate_safe_zone_wall(Vector3(center.x - radius, 0.0, center.y + dz + 0.5), 90) + _instantiate_safe_zone_wall(Vector3(center.x + radius + 1, 0.0, center.y + dz + 0.5), 90) # Update pathfinding for bots and movement checks gridmap.initialize_astar() @@ -728,16 +703,9 @@ func sync_clear_safe_zone(centers_to_clear: Array): if current == TILE_SAFE: gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE) - # Also clean up walls ON LAYER 1 - # Scan -3 to +3 range to ensure all shifted walls are cleared - for dx in range(-SAFE_ZONE_RADIUS - 1, SAFE_ZONE_RADIUS + 2): - for dz in range(-SAFE_ZONE_RADIUS - 1, SAFE_ZONE_RADIUS + 2): - var x = center.x + dx - var z = center.y + dz - if x >= 0 and x < gridmap.columns and z >= 0 and z < gridmap.rows: - # Clear any wall items on Floor 1 - if gridmap.get_cell_item(Vector3i(x, 1, z)) != -1: - gridmap.set_cell_item(Vector3i(x, 1, z), -1) + # Also clean up walls + for wall in get_tree().get_nodes_in_group("SafeZoneWalls"): + wall.queue_free() # Clear local state safe_zone_centers = [] @@ -751,6 +719,15 @@ func sync_clear_safe_zone(centers_to_clear: Array): safe_zone_centers = [] safe_zone_spawned = false +func _instantiate_safe_zone_wall(pos: Vector3, rotation_deg: float): + if not safe_zone_wall_scene: return + + var wall = safe_zone_wall_scene.instantiate() + add_child(wall) + wall.add_to_group("SafeZoneWalls") + wall.position = pos + wall.rotation_degrees.y = rotation_deg + # ============================================================================= # Power-Up Tile Spawning (Speed & Ghost) # =============================================================================