feat: embed tile height placeholder inside arena .tscn files and bake terrain transform shifts natively instead of using code hacks

This commit is contained in:
2026-07-06 18:08:06 +08:00
parent c114dd5175
commit 4fd46af3c0
4 changed files with 59 additions and 36 deletions
+16 -4
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://bx5a31fqhw8h8"] [gd_scene format=3]
[ext_resource type="PackedScene" uid="uid://h84tka1n1alg" path="res://assets/models/arena/candy_survival/candy_survival_terrain.gltf" id="1_86fyc"] [ext_resource type="PackedScene" path="res://assets/models/arena/candy_survival/candy_survival_terrain.gltf" id="1_86fyc"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_floor"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_floor"]
albedo_color = Color(0.2, 0.2, 0.2, 1) albedo_color = Color(0.2, 0.2, 0.2, 1)
@@ -24,10 +24,18 @@ albedo_color = Color(0.4973, 0.6, 0.12599999, 1)
material = SubResource("StandardMaterial3D_86fyc") material = SubResource("StandardMaterial3D_86fyc")
size = Vector2(50, 50) size = Vector2(50, 50)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_q8eld"]
transparency = 1
albedo_color = Color(1, 0, 1, 0.5)
[sub_resource type="BoxMesh" id="BoxMesh_l6h1c"]
material = SubResource("StandardMaterial3D_q8eld")
size = Vector3(1, 0.05, 1)
[node name="Candy Survival" type="Node3D" unique_id=1063002869] [node name="Candy Survival" type="Node3D" unique_id=1063002869]
[node name="PlaceholderFloor" type="MeshInstance3D" parent="." unique_id=932640085] [node name="PlaceholderFloor" type="MeshInstance3D" parent="." unique_id=932640085]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0, 10) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, -0.3, 10)
visible = false visible = false
mesh = SubResource("PlaneMesh_floor") mesh = SubResource("PlaneMesh_floor")
@@ -36,8 +44,12 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.5, 0.5, 9.5)
visible = false visible = false
mesh = SubResource("BoxMesh_cannon") mesh = SubResource("BoxMesh_cannon")
[node name="Candy Survival terrain" parent="." unique_id=193457353 instance=ExtResource("1_86fyc")] [node name="Candy Survival terrain" type="Node3D" parent="." unique_id=193457353 instance=ExtResource("1_86fyc")]
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1749367969] [node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1749367969]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.192932, 0, 9.441385) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.192932, 0, 9.441385)
mesh = SubResource("PlaneMesh_ugtui") mesh = SubResource("PlaneMesh_ugtui")
[node name="EditorTileReference" type="MeshInstance3D" parent="." unique_id=1116403213]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0)
mesh = SubResource("BoxMesh_l6h1c")
+27 -15
View File
@@ -1,15 +1,15 @@
[gd_scene format=4 uid="uid://nwpaqt6drdkr"] [gd_scene format=4]
[ext_resource type="Texture2D" uid="uid://dvgyv04f08v3q" path="res://assets/models/arena/free_mode/river_decoration_3_tex.png" id="1_c6je8"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/river_decoration_3_tex.png" id="1_c6je8"]
[ext_resource type="Texture2D" uid="uid://c2wpbdg11iqsa" path="res://assets/models/arena/free_mode/river_decoration_1_tex.png" id="2_1o174"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/river_decoration_1_tex.png" id="2_1o174"]
[ext_resource type="Material" uid="uid://xifgjdr8285d" path="res://assets/models/arena/free_mode/water_shader.tres" id="2_bw67x"] [ext_resource type="Material" path="res://assets/models/arena/free_mode/water_shader.tres" id="2_bw67x"]
[ext_resource type="Texture2D" uid="uid://dep1ng3aqb2jw" path="res://assets/models/arena/free_mode/sky_sea_01.png" id="3_8esiu"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/sky_sea_01.png" id="3_8esiu"]
[ext_resource type="Texture2D" uid="uid://drhycvc6qmm1a" path="res://assets/models/arena/free_mode/river_flower_1_tex.png" id="3_b3dsj"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/river_flower_1_tex.png" id="3_b3dsj"]
[ext_resource type="Texture2D" uid="uid://btt267mvogm6k" path="res://assets/models/arena/free_mode/stone_arch_1_tex.png" id="4_wto06"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/stone_arch_1_tex.png" id="4_wto06"]
[ext_resource type="PackedScene" uid="uid://cuporokvsp4ml" path="res://assets/characters/tektons/tekton_fishing_animation.glb" id="4_xj13a"] [ext_resource type="PackedScene" path="res://assets/characters/tektons/tekton_fishing_animation.glb" id="4_xj13a"]
[ext_resource type="Texture2D" uid="uid://cgr5hfccinmlh" path="res://assets/models/arena/free_mode/totem_stone_tex.png" id="5_2mpye"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/totem_stone_tex.png" id="5_2mpye"]
[ext_resource type="Script" uid="uid://dcnuf06soevte" path="res://scripts/tekton_fishing_autoplay.gd" id="5_fish"] [ext_resource type="Script" path="res://scripts/tekton_fishing_autoplay.gd" id="5_fish"]
[ext_resource type="Texture2D" uid="uid://bgq2k6khfe051" path="res://assets/models/arena/free_mode/river_boat_tex.png" id="6_yxfuw"] [ext_resource type="Texture2D" path="res://assets/models/arena/free_mode/river_boat_tex.png" id="6_yxfuw"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2g017"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2g017"]
resource_name = "river_decoration_3_tex.002" resource_name = "river_decoration_3_tex.002"
@@ -4623,11 +4623,19 @@ ambient_light_color = Color(1, 1, 1, 1)
ambient_light_sky_contribution = 0.5 ambient_light_sky_contribution = 0.5
reflected_light_source = 2 reflected_light_source = 2
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_c6je8"]
transparency = 1
albedo_color = Color(1, 0, 1, 0.5)
[sub_resource type="BoxMesh" id="BoxMesh_1o174"]
material = SubResource("StandardMaterial3D_c6je8")
size = Vector3(1, 0.05, 1)
[node name="Freemode" type="Node3D" unique_id=355029811] [node name="Freemode" type="Node3D" unique_id=355029811]
transform = Transform3D(100, 0, 0, 0, 100, 0, 0, 0, 100, 10.565, -0.57, 8.139) transform = Transform3D(100, 0, 0, 0, 100, 0, 0, 0, 100, 10.565, -0.57, 8.139)
[node name="Terrainv2" type="Node3D" parent="." unique_id=1519605696] [node name="Terrainv2" type="Node3D" parent="." unique_id=1519605696]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.005855293, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.3, 0)
[node name="river_decoration_3" type="MeshInstance3D" parent="Terrainv2" unique_id=653338190] [node name="river_decoration_3" type="MeshInstance3D" parent="Terrainv2" unique_id=653338190]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.011060472, 0.006291245, 0.07573756) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.011060472, 0.006291245, 0.07573756)
@@ -5208,14 +5216,18 @@ shadow_normal_bias = 5.0
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=936572897] [node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=936572897]
environment = SubResource("Environment_8v6kw") environment = SubResource("Environment_8v6kw")
[node name="tekton_fishing_animation1" parent="." unique_id=1803834250 instance=ExtResource("4_xj13a")] [node name="tekton_fishing_animation1" type="Node3D" parent="." unique_id=1803834250 instance=ExtResource("4_xj13a")]
transform = Transform3D(-0.0012733411, 0, 0.0015422717, 0, 0.002, 0, -0.0015422717, 0, -0.0012733411, 0.04044947, 0.024172742, -0.05992417) transform = Transform3D(-0.0012733411, 0, 0.0015422717, 0, 0.002, 0, -0.0015422717, 0, -0.0012733411, 0.04044947, 0.024172742, -0.05992417)
script = ExtResource("5_fish") script = ExtResource("5_fish")
[node name="tekton_fishing_animation2" parent="." unique_id=376449997 instance=ExtResource("4_xj13a")] [node name="tekton_fishing_animation2" type="Node3D" parent="." unique_id=376449997 instance=ExtResource("4_xj13a")]
transform = Transform3D(-0.0017457078, 0, 0.0009759627, 0, 0.0019999999, 0, -0.0009759627, 0, -0.0017457078, -0.117699884, -0.00031990372, 0.039631918) transform = Transform3D(-0.0017457078, 0, 0.0009759627, 0, 0.0019999999, 0, -0.0009759627, 0, -0.0017457078, -0.117699884, -0.00031990372, 0.039631918)
script = ExtResource("5_fish") script = ExtResource("5_fish")
[node name="tekton_fishing_animation3" parent="." unique_id=1696737351 instance=ExtResource("4_xj13a")] [node name="tekton_fishing_animation3" type="Node3D" parent="." unique_id=1696737351 instance=ExtResource("4_xj13a")]
transform = Transform3D(-0.0012249037, 0, 0.0015810153, 0, 0.002, 0, -0.0015810153, 0, -0.0012249037, 0.035826474, 0.0029043811, 0.0059019253) transform = Transform3D(-0.0012249037, 0, 0.0015810153, 0, 0.002, 0, -0.0015810153, 0, -0.0012249037, 0.035826474, 0.0029043811, 0.0059019253)
script = ExtResource("5_fish") script = ExtResource("5_fish")
[node name="EditorTileReference" type="MeshInstance3D" parent="." unique_id=1796024900]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0)
mesh = SubResource("BoxMesh_1o174")
Binary file not shown.
+16 -17
View File
@@ -166,13 +166,17 @@ func _instantiate_3d_arena(scene_path: String):
var arena_instance = arena_scene.instantiate() var arena_instance = arena_scene.instantiate()
arena_instance.name = "ArenaEnvironment3D" arena_instance.name = "ArenaEnvironment3D"
if "freemode" in scene_path or "stop_n_go" in scene_path: # Note: We no longer shift the arena via code (e.g., position.y = -0.22)
# The Terrainv2.gltf (and related arenas) have their floor physically modeled around Y=0.22. # The physical shifts have been baked directly into the .tscn files using EditorTileReference.
# Shift it down so the visual floor aligns properly with gridmap items.
arena_instance.position.y = -0.22
add_child(arena_instance) add_child(arena_instance)
move_child(arena_instance, 0) move_child(arena_instance, 0)
# Clean up the EditorTileReference if it was left in the scene
var editor_ref = arena_instance.get_node_or_null("EditorTileReference")
if editor_ref:
editor_ref.queue_free()
print("Instantiated 3D Arena: ", scene_path) print("Instantiated 3D Arena: ", scene_path)
func _hide_ground_tiles(): func _hide_ground_tiles():
@@ -194,21 +198,16 @@ func _setup_effect_elevation():
if em and em.mesh_library: if em and em.mesh_library:
var ml = em.mesh_library.duplicate() var ml = em.mesh_library.duplicate()
# Only lift tiles for modes that use the shifted Terrainv2.gltf (-0.22 offset) # Now that terrain heights are perfectly aligned inside the .tscn files,
# we no longer need to dynamically lift all tiles by 0.08.
# However, we still need to slightly drop TILE_SAFE (id 2) so it
# renders strictly as a floor decal without clipping.
if LobbyManager.game_mode in ["Stop n Go", "Freemode"]: if LobbyManager.game_mode in ["Stop n Go", "Freemode"]:
var lift_transform = Transform3D().translated(Vector3(0, 0.08, 0)) if ml.find_item_by_name("safe_zone") != -1 or 2 in ml.get_item_list():
for id in ml.get_item_list(): var id = 2
if id == 4: continue # Skip hidden non-walkable blocks
var apply_transform = lift_transform
# TILE_SAFE (2) is painted on Layer 2 (Y=0.10).
# We want it below all grid tiles (Layer 0 is at 0.08) but above the terrain (0.06).
# We set it to 0.07 by applying a -0.03 offset (0.10 - 0.03 = 0.07).
if id == 2:
apply_transform = Transform3D().translated(Vector3(0, -0.03, 0))
var current_transform = ml.get_item_mesh_transform(id) var current_transform = ml.get_item_mesh_transform(id)
ml.set_item_mesh_transform(id, apply_transform * current_transform) # Push it down by -0.02 so it sits perfectly between terrain and tiles
ml.set_item_mesh_transform(id, Transform3D().translated(Vector3(0, -0.02, 0)) * current_transform)
em.mesh_library = ml em.mesh_library = ml