feat(props): integrate Blender GLB props into movement map

- Replace primitive _crate(), _barrel(), _pillar() with GLB scene instances
- Add 7 prop preloads: crate, barrel, pillar, ramp, weapon_pickup, health_pack, ammo_pack
- Add _load_props() and _place_prop() helpers with null guards
- Add pickup placements: weapon (center), health (east/west), ammo (center/NW/SE)
- Props load at runtime via load() - appear once Godot editor imports the GLB files
- Null guard prevents crashes in headless mode before import
This commit is contained in:
2026-06-21 22:28:41 -04:00
parent 718a1477bf
commit 3584a7e6c5
+46 -21
View File
@@ -21,6 +21,7 @@ var _debug_ui_panel: PanelContainer
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
_load_props()
_build_materials()
_build_geometry()
_build_hud()
@@ -102,6 +103,40 @@ func _ramp_static(pos: Vector3, size: Vector3, rot_deg: Vector3, color: Color, n
return body
# ── GLB Prop Scenes (generated via Blender headless) ──────────────────────────
var prop_crate: PackedScene
var prop_barrel: PackedScene
var prop_pillar: PackedScene
var prop_ramp: PackedScene
var prop_weapon_pickup: PackedScene
var prop_health_pack: PackedScene
var prop_ammo_pack: PackedScene
func _load_props() -> void:
prop_crate = load("res://assets/props/crate.glb")
prop_barrel = load("res://assets/props/barrel.glb")
prop_pillar = load("res://assets/props/pillar.glb")
prop_ramp = load("res://assets/props/ramp.glb")
prop_weapon_pickup = load("res://assets/props/weapon_pickup.glb")
prop_health_pack = load("res://assets/props/health_pack.glb")
prop_ammo_pack = load("res://assets/props/ammo_pack.glb")
# Log which props loaded
if prop_crate: print("Prop loaded: crate")
else: print("WARN: crate.glb not imported yet - run Godot editor once to import")
if prop_barrel: print("Prop loaded: barrel")
if prop_pillar: print("Prop loaded: pillar")
func _place_prop(scene: PackedScene, pos: Vector3, name: String = "") -> void:
if not scene:
return # Skip if not imported yet
var inst = scene.instantiate()
if inst:
inst.name = name if not name.is_empty() else scene.resource_path.get_file().get_basename()
inst.position = pos
add_child(inst)
# ── Color Palette ─────────────────────────────────────────────────────────────
var C_FLOOR: Color = Color(0.22, 0.22, 0.25)
@@ -422,11 +457,11 @@ func _build_cover_system() -> void:
func _crate(pos: Vector3) -> void:
_box_static(pos, Vector3(1.2, 1.2, 1.2), C_CRATE, "Crate")
_place_prop(prop_crate, pos, "Crate")
func _pillar(pos: Vector3) -> void:
_box_static(pos, Vector3(0.8, 7.0, 0.8), C_METAL, "Pillar")
_place_prop(prop_pillar, pos, "Pillar")
# ── Speed Corridor ────────────────────────────────────────────────────────────
@@ -538,6 +573,14 @@ func _build_decorations() -> void:
_barrel(Vector3(-25, 0.5, 25))
_barrel(Vector3(25, 0.5, -25))
# Pickup props (GLB)
_place_prop(prop_weapon_pickup, Vector3(0, 0.05, -25), "WeaponPickup_Center")
_place_prop(prop_health_pack, Vector3(-20, 0.05, 0), "HealthPack_West")
_place_prop(prop_health_pack, Vector3(20, 0.05, 0), "HealthPack_East")
_place_prop(prop_ammo_pack, Vector3(0, 0.05, 25), "AmmoPack_Center")
_place_prop(prop_ammo_pack, Vector3(-35, 0.05, -35), "AmmoPack_NW")
_place_prop(prop_ammo_pack, Vector3(35, 0.05, 35), "AmmoPack_SE")
# Spawn area lights
_spawn_area_light(Vector3(-42, 3, -42), C_ACCENT_WARM, 6.0, 0.8)
_spawn_area_light(Vector3(-42, 3, 42), C_ACCENT_WARM, 6.0, 0.8)
@@ -548,25 +591,7 @@ func _build_decorations() -> void:
func _barrel(pos: Vector3) -> void:
var body := StaticBody3D.new()
body.name = "Barrel"
body.position = pos
add_child(body)
var mesh := MeshInstance3D.new()
mesh.mesh = CylinderMesh.new()
mesh.mesh.top_radius = 0.4
mesh.mesh.bottom_radius = 0.4
mesh.mesh.height = 1.0
var mat := StandardMaterial3D.new()
mat.albedo_color = Color(0.50, 0.45, 0.30)
mat.roughness = 0.6
mesh.mesh.surface_set_material(0, mat)
body.add_child(mesh)
var shape := CollisionShape3D.new()
shape.shape = CylinderShape3D.new()
shape.shape.radius = 0.4
shape.shape.height = 1.0
body.add_child(shape)
_place_prop(prop_barrel, pos, "Barrel")
func _spawn_area_light(pos: Vector3, color: Color, radius: float, energy: float) -> void: