# Weather (P9) —— 雪 / 雨 环境粒子。跟随相机,在其上方一片区域内下落。 # # var w := preload("res://fx/weather.gd").new() # add_child(w) # w.setup(camera) # camera: Camera3D / Node3D # w.set_weather("snow") # "snow" | "rain" | "none" # # 用 GPUParticles3D + ParticleProcessMaterial 的盒子发射体,粒子朝下。 # 由地图属性或调试驱动;没有专门封包。 extends Node3D var _cam: Node3D var _p: GPUParticles3D var _kind := "none" func setup(camera: Node3D) -> void: _cam = camera _p = GPUParticles3D.new() _p.amount = 800 _p.lifetime = 3.0 _p.visibility_aabb = AABB(Vector3(-30, -30, -30), Vector3(60, 60, 60)) _p.local_coords = false _p.emitting = false add_child(_p) _build_material() set_weather("none") func kind() -> String: return _kind func set_weather(k: String) -> void: _kind = k if _p == null: return if k == "none": _p.emitting = false return _p.emitting = true var m: ParticleProcessMaterial = _p.process_material if k == "snow": _p.amount = 700 _p.lifetime = 6.0 m.gravity = Vector3(0, -2.0, 0) m.initial_velocity_min = 0.5 m.initial_velocity_max = 1.5 m.scale_min = 0.03 m.scale_max = 0.08 m.color = Color(1, 1, 1, 0.9) m.turbulence_enabled = true m.turbulence_noise_strength = 0.6 elif k == "rain": _p.amount = 1200 _p.lifetime = 1.2 m.gravity = Vector3(0, -30.0, 0) m.initial_velocity_min = 12.0 m.initial_velocity_max = 18.0 m.scale_min = 0.015 m.scale_max = 0.03 m.color = Color(0.7, 0.8, 0.95, 0.5) m.turbulence_enabled = false func _build_material() -> void: var m := ParticleProcessMaterial.new() m.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX m.emission_box_extents = Vector3(25, 1, 25) m.direction = Vector3(0, -1, 0) m.spread = 8.0 m.gravity = Vector3(0, -2.0, 0) _p.process_material = m var mesh := QuadMesh.new() mesh.size = Vector2(0.1, 0.1) var mat := StandardMaterial3D.new() mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA mat.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED mat.albedo_color = Color(1, 1, 1, 0.85) mesh.material = mat _p.draw_pass_1 = mesh func _process(_dt: float) -> void: if _cam and _p: # 发射体盒子锚在相机上方 20m _p.global_position = _cam.global_position + Vector3(0, 20, 0)