167 lines
5.9 KiB
GDScript
167 lines
5.9 KiB
GDScript
extends Node3D
|
|
## Sparse office props and bounded fire animation; Web/Compatibility safe.
|
|
const FIRE_MIN := 1.9
|
|
const FIRE_MAX := 2.8
|
|
var fire_light: OmniLight3D
|
|
var _time := 0.0
|
|
|
|
func _ready() -> void:
|
|
name = "OfficeAtmosphere"
|
|
_desk(Vector3(-5, 0, -4))
|
|
_desk(Vector3(5, 0, 4))
|
|
_chair(Vector3(-5, 0, -2.6), 0)
|
|
_chair(Vector3(5, 0, 5.4), PI)
|
|
_chair(Vector3(6.8, 0, -4), -0.35)
|
|
_barrel(Vector3(-4, 0, 4))
|
|
|
|
func _material(color: Color, metallic: float = 0.0) -> StandardMaterial3D:
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = color
|
|
mat.roughness = 0.85
|
|
mat.metallic = metallic
|
|
return mat
|
|
|
|
func _box(parent: Node3D, pos: Vector3, size: Vector3, mat: Material) -> MeshInstance3D:
|
|
var mesh := BoxMesh.new()
|
|
mesh.size = size
|
|
mesh.material = mat
|
|
var node := MeshInstance3D.new()
|
|
node.mesh = mesh
|
|
node.position = pos
|
|
parent.add_child(node)
|
|
return node
|
|
|
|
func _body(pos: Vector3, label: String) -> StaticBody3D:
|
|
var body := StaticBody3D.new()
|
|
body.name = label
|
|
body.position = pos
|
|
body.collision_layer = 1
|
|
body.collision_mask = 0
|
|
body.add_to_group("office_props")
|
|
add_child(body, true)
|
|
return body
|
|
|
|
func _collision(body: StaticBody3D, center: Vector3, size: Vector3) -> void:
|
|
var shape := BoxShape3D.new()
|
|
shape.size = size
|
|
var collider := CollisionShape3D.new()
|
|
collider.shape = shape
|
|
collider.position = center
|
|
body.add_child(collider)
|
|
|
|
func _desk(pos: Vector3) -> void:
|
|
var desk := _body(pos, "OfficeDesk")
|
|
var wood := _material(Color(0.19, 0.12, 0.07))
|
|
var metal := _material(Color(0.12, 0.15, 0.14), 0.5)
|
|
_box(desk, Vector3(0, 0.84, 0), Vector3(2.5, 0.12, 1.15), wood)
|
|
for x in [-1.05, 1.05]:
|
|
for z in [-0.43, 0.43]:
|
|
_box(desk, Vector3(x, 0.4, z), Vector3(0.08, 0.8, 0.08), metal)
|
|
_box(desk, Vector3(-0.82, 0.53, 0), Vector3(0.48, 0.5, 0.94), metal)
|
|
for y in [0.4, 0.62]:
|
|
_box(desk, Vector3(-0.82, y, 0.49), Vector3(0.23, 0.025, 0.035), wood)
|
|
_box(desk, Vector3(0.3, 0.91, 0.05), Vector3(0.48, 0.015, 0.35), _material(Color(0.45, 0.43, 0.32)))
|
|
_collision(desk, Vector3(0, 0.45, 0), Vector3(2.5, 0.9, 1.15))
|
|
_lamp(desk, Vector3(0.84, 0.91, -0.23))
|
|
|
|
func _chair(pos: Vector3, yaw: float) -> void:
|
|
var chair := _body(pos, "OfficeChair")
|
|
chair.rotation.y = yaw
|
|
var metal := _material(Color(0.12, 0.12, 0.13), 0.6)
|
|
var fabric := _material(Color(0.1, 0.14, 0.12))
|
|
_box(chair, Vector3(0, 0.48, 0), Vector3(0.58, 0.12, 0.56), fabric)
|
|
_box(chair, Vector3(0, 0.84, 0.25), Vector3(0.58, 0.64, 0.09), fabric)
|
|
for x in [-0.23, 0.23]:
|
|
for z in [-0.22, 0.22]:
|
|
_box(chair, Vector3(x, 0.21, z), Vector3(0.045, 0.42, 0.045), metal)
|
|
_collision(chair, Vector3(0, 0.53, 0), Vector3(0.6, 1.06, 0.6))
|
|
|
|
func _cylinder(parent: Node3D, pos: Vector3, radius: float, height: float, mat: Material) -> void:
|
|
var mesh := CylinderMesh.new()
|
|
mesh.top_radius = radius
|
|
mesh.bottom_radius = radius
|
|
mesh.height = height
|
|
mesh.radial_segments = 24
|
|
mesh.material = mat
|
|
var node := MeshInstance3D.new()
|
|
node.mesh = mesh
|
|
node.position = pos
|
|
parent.add_child(node)
|
|
|
|
func _lamp(parent: Node3D, pos: Vector3) -> void:
|
|
var lamp := Node3D.new()
|
|
lamp.name = "DeskLamp"
|
|
lamp.position = pos
|
|
parent.add_child(lamp)
|
|
var metal := _material(Color(0.13, 0.19, 0.15), 0.5)
|
|
_cylinder(lamp, Vector3(0, 0.035, 0), 0.16, 0.07, metal)
|
|
_box(lamp, Vector3(0, 0.24, 0), Vector3(0.04, 0.4, 0.04), metal)
|
|
_box(lamp, Vector3(0, 0.44, 0), Vector3(0.4, 0.12, 0.24), metal)
|
|
var bulb := _material(Color(0.8, 0.63, 0.3))
|
|
bulb.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
_box(lamp, Vector3(0, 0.375, 0), Vector3(0.32, 0.012, 0.18), bulb)
|
|
var light := OmniLight3D.new()
|
|
light.name = "DeskLampLight"
|
|
light.position = Vector3(0, 0.31, 0)
|
|
light.light_color = Color(1.0, 0.7, 0.35)
|
|
light.light_energy = 1.2
|
|
light.omni_range = 5.5
|
|
light.shadow_enabled = false
|
|
lamp.add_child(light)
|
|
|
|
func _barrel(pos: Vector3) -> void:
|
|
var barrel := _body(pos, "FireBarrel")
|
|
var metal := _material(Color(0.15, 0.1, 0.075), 0.65)
|
|
_cylinder(barrel, Vector3(0, 0.5, 0), 0.43, 1.0, metal)
|
|
for y in [0.12, 0.78, 1.01]:
|
|
_cylinder(barrel, Vector3(0, y, 0), 0.46, 0.055, metal)
|
|
_cylinder(barrel, Vector3(0, 1.045, 0), 0.39, 0.015, _material(Color(0.025, 0.012, 0.005)))
|
|
_collision(barrel, Vector3(0, 0.52, 0), Vector3(0.92, 1.04, 0.92))
|
|
var fire := CPUParticles3D.new()
|
|
fire.name = "BarrelFlames"
|
|
fire.position = Vector3(0, 1.08, 0)
|
|
fire.amount = 28
|
|
fire.lifetime = 0.85
|
|
fire.preprocess = 1.0
|
|
fire.emission_shape = CPUParticles3D.EMISSION_SHAPE_SPHERE
|
|
fire.emission_sphere_radius = 0.23
|
|
fire.direction = Vector3.UP
|
|
fire.spread = 12
|
|
fire.gravity = Vector3(0, 0.6, 0)
|
|
fire.initial_velocity_min = 0.5
|
|
fire.initial_velocity_max = 1.15
|
|
fire.scale_amount_min = 0.5
|
|
fire.scale_amount_max = 1.0
|
|
var gradient := Gradient.new()
|
|
gradient.set_color(0, Color(1, 0.65, 0.12, 0.8))
|
|
gradient.set_color(1, Color(0.6, 0.04, 0.005, 0))
|
|
fire.color_ramp = gradient
|
|
var quad := QuadMesh.new()
|
|
quad.size = Vector2(0.48, 0.8)
|
|
var flame := StandardMaterial3D.new()
|
|
flame.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
flame.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
flame.blend_mode = BaseMaterial3D.BLEND_MODE_ADD
|
|
flame.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES
|
|
flame.albedo_texture = load("res://assets/effects/flame.png")
|
|
flame.vertex_color_use_as_albedo = true
|
|
flame.cull_mode = BaseMaterial3D.CULL_DISABLED
|
|
quad.material = flame
|
|
fire.mesh = quad
|
|
fire.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
|
barrel.add_child(fire)
|
|
fire_light = OmniLight3D.new()
|
|
fire_light.name = "BarrelFireLight"
|
|
fire_light.position = Vector3(0, 1.5, 0)
|
|
fire_light.light_color = Color(1, 0.36, 0.07)
|
|
fire_light.light_energy = (FIRE_MIN + FIRE_MAX) * 0.5
|
|
fire_light.omni_range = 10
|
|
fire_light.shadow_enabled = true
|
|
barrel.add_child(fire_light)
|
|
|
|
func _process(dt: float) -> void:
|
|
_time += dt
|
|
# Smooth, deterministic, bounded flicker: no per-frame random flashes.
|
|
var wave := 0.5 + 0.3 * sin(_time * 7.1) + 0.2 * sin(_time * 11.7 + 1.2)
|
|
fire_light.light_energy = lerpf(FIRE_MIN, FIRE_MAX, wave)
|