fix: empty out all gridmap layers under candy pump and use precise duration timer for projectile destruction
Build and Release Patch PCK / build-and-deploy-patch (push) Failing after 2m22s
Automated Testing / test (push) Failing after 57s

This commit is contained in:
2026-06-29 21:13:44 +08:00
parent a5595dbd6b
commit 5466f0bf36
3 changed files with 52 additions and 45 deletions
+10 -11
View File
@@ -1,6 +1,6 @@
[gd_scene load_steps=10 format=3 uid="uid://ddy2r7xto80gq"] [gd_scene format=3 uid="uid://ddy2r7xto80gq"]
[ext_resource type="Script" path="res://scripts/controllers/candy_cannon_controller.gd" id="1_canon"] [ext_resource type="Script" uid="uid://du7cne5070ia0" path="res://scripts/controllers/candy_cannon_controller.gd" id="1_canon"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_base"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_base"]
albedo_color = Color(0.15, 0.15, 0.2, 1) albedo_color = Color(0.15, 0.15, 0.2, 1)
@@ -42,36 +42,35 @@ material = SubResource("StandardMaterial3D_pipe")
inner_radius = 0.95 inner_radius = 0.95
outer_radius = 1.15 outer_radius = 1.15
rings = 32 rings = 32
tube_segments = 12
[node name="CandyCannon" type="Node3D"] [node name="CandyCannon" type="Node3D" unique_id=1515964905]
script = ExtResource("1_canon") script = ExtResource("1_canon")
[node name="Base" type="MeshInstance3D" parent="."] [node name="Base" type="MeshInstance3D" parent="." unique_id=867716100]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0)
mesh = SubResource("CylinderMesh_base") mesh = SubResource("CylinderMesh_base")
[node name="Tank" type="MeshInstance3D" parent="."] [node name="Tank" type="MeshInstance3D" parent="." unique_id=2051786234]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, 0)
mesh = SubResource("SphereMesh_tank") mesh = SubResource("SphereMesh_tank")
[node name="Pipe" type="MeshInstance3D" parent="."] [node name="Pipe" type="MeshInstance3D" parent="." unique_id=491265631]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.7, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.7, 0)
mesh = SubResource("CylinderMesh_pipe") mesh = SubResource("CylinderMesh_pipe")
[node name="Ring1" type="MeshInstance3D" parent="."] [node name="Ring1" type="MeshInstance3D" parent="." unique_id=1607309179]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, 0)
mesh = SubResource("TorusMesh_ring") mesh = SubResource("TorusMesh_ring")
[node name="Ring2" type="MeshInstance3D" parent="."] [node name="Ring2" type="MeshInstance3D" parent="." unique_id=850923213]
transform = Transform3D(0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 0, 0, 1, 0, 1.4, 0) transform = Transform3D(0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 0, 0, 1, 0, 1.4, 0)
mesh = SubResource("TorusMesh_ring") mesh = SubResource("TorusMesh_ring")
[node name="Ring3" type="MeshInstance3D" parent="."] [node name="Ring3" type="MeshInstance3D" parent="." unique_id=677024967]
transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 0, 1.4, 0) transform = Transform3D(0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 0, 1.4, 0)
mesh = SubResource("TorusMesh_ring") mesh = SubResource("TorusMesh_ring")
[node name="OmniLight3D" type="OmniLight3D" parent="."] [node name="OmniLight3D" type="OmniLight3D" parent="." unique_id=1751121483]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8, 0)
light_color = Color(1, 0.4, 0.8, 1) light_color = Color(1, 0.4, 0.8, 1)
light_energy = 3.0 light_energy = 3.0
@@ -115,17 +115,21 @@ func spawn_projectile(target_world_pos: Vector3, duration: float) -> void:
var mid_y = max(global_position.y, target_world_pos.y) + 4.0 var mid_y = max(global_position.y, target_world_pos.y) + 4.0
var tween_y = create_tween() var tween_y = create_tween()
# Important: Make sure both halves of the y-tween together equal `duration`
tween_y.tween_property(projectile, "global_position:y", mid_y, duration / 2.0).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT) tween_y.tween_property(projectile, "global_position:y", mid_y, duration / 2.0).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
tween_y.tween_property(projectile, "global_position:y", target_world_pos.y, duration / 2.0).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN).set_delay(duration / 2.0) tween_y.tween_property(projectile, "global_position:y", target_world_pos.y, duration / 2.0).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
# Add some spin to the projectile # Add some spin to the projectile
var spin_tween = create_tween() var spin_tween = create_tween()
spin_tween.set_loops() spin_tween.set_loops()
spin_tween.tween_property(projectile, "rotation", Vector3(PI*2, PI*2, PI*2), 0.5).as_relative() spin_tween.tween_property(projectile, "rotation", Vector3(PI*2, PI*2, PI*2), 0.5).as_relative()
tween.chain().tween_callback(func(): # We need to wait for the X/Z tween to finish, but since it's parallel we can just use a separate timer or tween
spin_tween.kill() # to kill the projectile exactly when duration is reached, ensuring it doesn't get killed early by X/Z finishing 1 frame earlier than Y
projectile.queue_free() get_tree().create_timer(duration).timeout.connect(func():
if is_instance_valid(spin_tween): spin_tween.kill()
if is_instance_valid(projectile): projectile.queue_free()
) )
func can_rpc() -> bool: func can_rpc() -> bool:
+34 -30
View File
@@ -391,43 +391,47 @@ func sync_arena_setup() -> void:
print("[Gauntlet] Client: Syncing Arena Setup (%dx%d)..." % [ARENA_COLUMNS, ARENA_ROWS]) print("[Gauntlet] Client: Syncing Arena Setup (%dx%d)..." % [ARENA_COLUMNS, ARENA_ROWS])
_apply_arena_setup() _apply_arena_setup()
func _apply_arena_setup() -> void: func _apply_arena_setup() -> void:
"""Shared arena layout logic for host + clients.""" """Shared arena layout logic for host + clients."""
if not gridmap: if not gridmap:
gridmap = get_parent().get_node_or_null("EnhancedGridMap") gridmap = get_parent().get_node_or_null("EnhancedGridMap")
if not gridmap: if not gridmap:
gridmap = get_node_or_null("/root/Main/EnhancedGridMap") gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
if not gridmap: return if not gridmap: return
# Resize grid (bypass setters that wipe the map) # Resize grid (bypass setters that wipe the map)
gridmap.set("columns", ARENA_COLUMNS) gridmap.set("columns", ARENA_COLUMNS)
gridmap.set("rows", ARENA_ROWS) gridmap.set("rows", ARENA_ROWS)
# Clear all # Clear all
gridmap.clear() gridmap.clear()
# Build the 20x20 arena # Build the 20x20 arena
for x in range(ARENA_COLUMNS): for x in range(ARENA_COLUMNS):
for z in range(ARENA_ROWS): for z in range(ARENA_ROWS):
var pos = Vector2i(x, z) var pos = Vector2i(x, z)
# Center 3x3 block: NPC obstacle (Candy Pump) # Center 3x3 block: NPC obstacle (Candy Pump)
if _is_npc_zone(pos): if _is_npc_zone(pos):
# Make the floor empty (-1) beneath the Candy Pump # Make the floor empty (-1) beneath the Candy Pump
# We need to clear all possible layers just in case
gridmap.set_cell_item(Vector3i(x, 0, z), -1) gridmap.set_cell_item(Vector3i(x, 0, z), -1)
gridmap.set_cell_item(Vector3i(x, 1, z), -1) gridmap.set_cell_item(Vector3i(x, 1, z), -1)
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
continue continue
# Boundary walls: perimeter (row 0, row 19, col 0, col 19) # Boundary walls: perimeter (row 0, row 19, col 0, col 19)
if x == 0 or x == ARENA_COLUMNS - 1 or z == 0 or z == ARENA_ROWS - 1: if x == 0 or x == ARENA_COLUMNS - 1 or z == 0 or z == ARENA_ROWS - 1:
# Also make border walls visually walkable floors instead of red blocks # Also make border walls visually walkable floors instead of red blocks
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
continue
# Interior: walkable floor
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE) gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
gridmap.set_cell_item(Vector3i(x, 1, z), -1) gridmap.set_cell_item(Vector3i(x, 1, z), -1)
continue gridmap.set_cell_item(Vector3i(x, 2, z), -1)
# Interior: walkable floor
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
gridmap.diagonal_movement = true gridmap.diagonal_movement = true
gridmap.update_grid_data() gridmap.update_grid_data()