Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e33b91d976 | |||
| fdc43bd5f1 | |||
| 3f7acf857c | |||
| 6648b2bba5 | |||
| 7f753cb1b8 |
@@ -0,0 +1,120 @@
|
|||||||
|
[gd_scene load_steps=1 format=3 uid="uid://c49a36fc7db_test_level"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_ground"]
|
||||||
|
size = Vector3(40, 1, 40)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ground"]
|
||||||
|
size = Vector3(40, 1, 40)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_prop1"]
|
||||||
|
size = Vector3(2, 3, 2)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_prop1"]
|
||||||
|
size = Vector3(2, 3, 2)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_prop2"]
|
||||||
|
size = Vector3(3, 1, 3)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_prop2"]
|
||||||
|
size = Vector3(3, 1, 3)
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_prop3"]
|
||||||
|
top_radius = 1.0
|
||||||
|
height = 4.0
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_prop3"]
|
||||||
|
top_radius = 1.0
|
||||||
|
bottom_radius = 1.0
|
||||||
|
height = 4.0
|
||||||
|
subdivisions_top_radius = 8
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_prop4"]
|
||||||
|
radius = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_prop4"]
|
||||||
|
radius = 1.0
|
||||||
|
subdivisions_ring = 12
|
||||||
|
subdivisions_height = 12
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_prop5"]
|
||||||
|
radius = 0.5
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_prop5"]
|
||||||
|
radius = 0.5
|
||||||
|
subdivisions_ring = 8
|
||||||
|
subdivisions_height = 8
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="WorldEnvironment_env"]
|
||||||
|
background_mode = 1
|
||||||
|
background_color = Color(0.4, 0.6, 0.8, 1)
|
||||||
|
ambient_light_source = 1
|
||||||
|
ambient_light_energy = 0.4
|
||||||
|
ambient_light_sky_energy = 1.0
|
||||||
|
|
||||||
|
[node name="TestLevel" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Ground" type="StaticBody3D" parent="."]
|
||||||
|
position = Vector3(0, -0.5, 0)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
|
||||||
|
shape = SubResource("BoxShape3D_ground")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
|
||||||
|
mesh = SubResource("BoxMesh_ground")
|
||||||
|
|
||||||
|
[node name="Props" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Prop1_Box" type="StaticBody3D" parent="Props"]
|
||||||
|
position = Vector3(8, 1.5, 8)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Props/Prop1_Box"]
|
||||||
|
shape = SubResource("BoxShape3D_prop1")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Props/Prop1_Box"]
|
||||||
|
mesh = SubResource("BoxMesh_prop1")
|
||||||
|
|
||||||
|
[node name="Prop2_Pedestal" type="StaticBody3D" parent="Props"]
|
||||||
|
position = Vector3(-8, 0.5, 6)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Props/Prop2_Pedestal"]
|
||||||
|
shape = SubResource("BoxShape3D_prop2")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Props/Prop2_Pedestal"]
|
||||||
|
mesh = SubResource("BoxMesh_prop2")
|
||||||
|
|
||||||
|
[node name="Prop3_Column" type="StaticBody3D" parent="Props"]
|
||||||
|
position = Vector3(6, 2.0, -8)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Props/Prop3_Column"]
|
||||||
|
shape = SubResource("CylinderShape3D_prop3")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Props/Prop3_Column"]
|
||||||
|
mesh = SubResource("CylinderMesh_prop3")
|
||||||
|
|
||||||
|
[node name="Prop4_Sphere" type="StaticBody3D" parent="Props"]
|
||||||
|
position = Vector3(-6, 1.0, -6)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Props/Prop4_Sphere"]
|
||||||
|
shape = SubResource("SphereShape3D_prop4")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Props/Prop4_Sphere"]
|
||||||
|
mesh = SubResource("SphereMesh_prop4")
|
||||||
|
|
||||||
|
[node name="Prop5_SmallSphere" type="StaticBody3D" parent="Props"]
|
||||||
|
position = Vector3(0, 0.5, 12)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Props/Prop5_SmallSphere"]
|
||||||
|
shape = SubResource("SphereShape3D_prop5")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Props/Prop5_SmallSphere"]
|
||||||
|
mesh = SubResource("SphereMesh_prop5")
|
||||||
|
|
||||||
|
[node name="Sun" type="DirectionalLight3D" parent="."]
|
||||||
|
rotation = Vector3(-0.785398, 0, 0)
|
||||||
|
shadow_enabled = true
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
|
environment = SubResource("WorldEnvironment_env")
|
||||||
|
|
||||||
|
[node name="PlayerSpawn" type="Marker3D" parent="."]
|
||||||
|
position = Vector3(0, 1.5, 0)
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
extends SceneTree
|
||||||
|
## Headless smoke test for the PC2 test level scene.
|
||||||
|
##
|
||||||
|
## Run with:
|
||||||
|
## godot --headless --path . --script res://scripts/smoke_test_test_level.gd
|
||||||
|
##
|
||||||
|
## Loads the test level scene, asserts:
|
||||||
|
## (a) it loads without error,
|
||||||
|
## (b) it contains a Marker3D named "PlayerSpawn",
|
||||||
|
## (c) PlayerSpawn is positioned >= 1.0 m above the ground top surface.
|
||||||
|
## Exits 0 on success, 1 on failure.
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
_run()
|
||||||
|
|
||||||
|
|
||||||
|
func _run() -> void:
|
||||||
|
var level_path: String = "res://scenes/worlds/test_level.tscn"
|
||||||
|
|
||||||
|
# Load the scene file
|
||||||
|
var level_resource: PackedScene = load(level_path)
|
||||||
|
if level_resource == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 could not load ", level_path)
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
print("SMOKE: test_level.tscn loaded successfully")
|
||||||
|
|
||||||
|
# Change the running scene to our test level
|
||||||
|
var err: int = change_scene_to_packed(level_resource)
|
||||||
|
if err != OK:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 change_scene_to_packed returned ", err)
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Wait for the scene_changed signal so current_scene is set
|
||||||
|
await scene_changed
|
||||||
|
|
||||||
|
var level_instance: Node3D = current_scene as Node3D
|
||||||
|
if level_instance == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 current_scene is not Node3D")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Give the tree one frame to fully initialize
|
||||||
|
await process_frame
|
||||||
|
|
||||||
|
# (b) Find the PlayerSpawn marker
|
||||||
|
var spawn_marker: Node3D = level_instance.find_child("PlayerSpawn", true, false) as Node3D
|
||||||
|
if spawn_marker == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 no Node3D named 'PlayerSpawn' found in test level")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
print("SMOKE: found PlayerSpawn at ", spawn_marker.global_position)
|
||||||
|
|
||||||
|
# (c) Verify PlayerSpawn is >= 1.0 m above ground top
|
||||||
|
# The ground top surface is at y = 0 (Ground StaticBody3D centered at y = -0.5
|
||||||
|
# with height 1.0, so top face is at y = 0).
|
||||||
|
var spawn_y: float = spawn_marker.global_position.y
|
||||||
|
if spawn_y < 1.0:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 PlayerSpawn y = ", spawn_y,
|
||||||
|
" is below the required minimum of 1.0 m above ground top (y=0)")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
print("SMOKE: PlayerSpawn y = ", spawn_y, " >= 1.0 m \u2014 PASS")
|
||||||
|
|
||||||
|
# Additional check: verify Ground StaticBody3D exists
|
||||||
|
var ground: StaticBody3D = level_instance.find_child("Ground", true, false) as StaticBody3D
|
||||||
|
if ground == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 no StaticBody3D named 'Ground' found")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
print("SMOKE: found Ground StaticBody3D")
|
||||||
|
|
||||||
|
# Verify Ground top face is at y = 0
|
||||||
|
var ground_shape: CollisionShape3D = ground.find_child("CollisionShape3D", true, false) as CollisionShape3D
|
||||||
|
if ground_shape != null and ground_shape.shape is BoxShape3D:
|
||||||
|
var box_shape: BoxShape3D = ground_shape.shape as BoxShape3D
|
||||||
|
var ground_top: float = ground.global_position.y + box_shape.size.y / 2.0
|
||||||
|
if abs(ground_top - 0.0) > 0.01:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 Ground top face at y = ", ground_top, " expected ~0.0")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
print("SMOKE: Ground top face at y = ", ground_top, " \u2014 PASS")
|
||||||
|
|
||||||
|
# Verify props exist (3-5 StaticBody3D children under Props node)
|
||||||
|
var props_node: Node3D = level_instance.find_child("Props", true, false) as Node3D
|
||||||
|
if props_node != null:
|
||||||
|
var prop_count: int = 0
|
||||||
|
for child in props_node.get_children():
|
||||||
|
if child is StaticBody3D:
|
||||||
|
prop_count += 1
|
||||||
|
if prop_count < 3:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 only ", prop_count, " props found, need >= 3")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
print("SMOKE: found ", prop_count, " props \u2014 PASS")
|
||||||
|
else:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 no 'Props' Node3D found")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Verify lighting exists
|
||||||
|
var sun: DirectionalLight3D = level_instance.find_child("Sun", true, false) as DirectionalLight3D
|
||||||
|
if sun == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 no DirectionalLight3D named 'Sun' found")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
print("SMOKE: found Sun DirectionalLight3D")
|
||||||
|
|
||||||
|
# Verify WorldEnvironment exists
|
||||||
|
var env: WorldEnvironment = level_instance.find_child("WorldEnvironment", true, false) as WorldEnvironment
|
||||||
|
if env == null:
|
||||||
|
printerr("SMOKE RESULT: FAIL \u2014 no WorldEnvironment named 'WorldEnvironment' found")
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
print("SMOKE: found WorldEnvironment")
|
||||||
|
|
||||||
|
# All checks passed
|
||||||
|
print("SMOKE RESULT: PASS")
|
||||||
|
quit(0)
|
||||||
Reference in New Issue
Block a user