114 lines
3.4 KiB
GDScript
114 lines
3.4 KiB
GDScript
class_name DiveSite
|
|
extends Node3D
|
|
|
|
const SonarMaterial = preload("res://game/domain/sonar/sonar_material.gd")
|
|
const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd")
|
|
const SitePlacement = preload("res://game/domain/sites/site_placement.gd")
|
|
const BathymetricTerrainActor = preload(
|
|
"res://game/world/sites/bathymetric_terrain_actor.gd"
|
|
)
|
|
|
|
const METAL_REFLECTIVITY := 1.0
|
|
const BEACON_COLOR := Color(0.2, 0.78, 0.9)
|
|
|
|
@onready var _terrain: BathymetricTerrainActor = %Terrain
|
|
@onready var _placements_root: Node3D = %Placements
|
|
|
|
var _definition: DiveSiteDefinition
|
|
var _placeholder_count := 0
|
|
|
|
|
|
func configure(definition: DiveSiteDefinition) -> String:
|
|
if definition == null:
|
|
return "dive site definition is missing"
|
|
var error := definition.validation_error()
|
|
if not error.is_empty():
|
|
return error
|
|
var terrain_error := _terrain.configure(definition.height_field())
|
|
if not terrain_error.is_empty():
|
|
return terrain_error
|
|
_definition = definition
|
|
for child in _placements_root.get_children():
|
|
_placements_root.remove_child(child)
|
|
child.free()
|
|
_placeholder_count = 0
|
|
for placement: SitePlacement in definition.placements:
|
|
_place(placement)
|
|
return ""
|
|
|
|
|
|
func definition() -> DiveSiteDefinition:
|
|
return _definition
|
|
|
|
|
|
func terrain() -> BathymetricTerrainActor:
|
|
return _terrain
|
|
|
|
|
|
func spawn_transform() -> Transform3D:
|
|
return _definition.spawn_transform() if _definition != null else Transform3D.IDENTITY
|
|
|
|
|
|
func placeholder_count() -> int:
|
|
return _placeholder_count
|
|
|
|
|
|
func _place(placement: SitePlacement) -> void:
|
|
if placement.is_sonar_metal():
|
|
_placements_root.add_child(_metal_placeholder(placement))
|
|
_placeholder_count += 1
|
|
elif placement.kind == SitePlacement.Kind.VESSEL_ANCHOR:
|
|
_placements_root.add_child(_beacon(placement))
|
|
_placeholder_count += 1
|
|
|
|
|
|
func _metal_placeholder(placement: SitePlacement) -> StaticBody3D:
|
|
var body := StaticBody3D.new()
|
|
body.name = String(placement.placement_id)
|
|
body.position = placement.position_m
|
|
body.rotation.y = placement.yaw_radians
|
|
body.set_meta("sonar_material", SonarMaterial.Value.METAL)
|
|
body.set_meta("sonar_reflectivity", METAL_REFLECTIVITY)
|
|
var mesh := BoxMesh.new()
|
|
mesh.size = placement.footprint_m
|
|
var mesh_instance := MeshInstance3D.new()
|
|
mesh_instance.name = "Mesh"
|
|
mesh_instance.mesh = mesh
|
|
var material := StandardMaterial3D.new()
|
|
material.albedo_color = Color(0.24, 0.18, 0.08)
|
|
material.metallic = 0.88
|
|
material.roughness = 0.27
|
|
mesh_instance.material_override = material
|
|
body.add_child(mesh_instance)
|
|
var shape := BoxShape3D.new()
|
|
shape.size = placement.footprint_m
|
|
var collision := CollisionShape3D.new()
|
|
collision.name = "Collision"
|
|
collision.shape = shape
|
|
body.add_child(collision)
|
|
return body
|
|
|
|
|
|
func _beacon(placement: SitePlacement) -> MeshInstance3D:
|
|
var mesh := SphereMesh.new()
|
|
mesh.radius = 0.55
|
|
mesh.height = 1.1
|
|
var beacon := MeshInstance3D.new()
|
|
beacon.name = String(placement.placement_id)
|
|
beacon.mesh = mesh
|
|
beacon.position = placement.position_m
|
|
var material := StandardMaterial3D.new()
|
|
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
material.albedo_color = BEACON_COLOR
|
|
material.emission_enabled = true
|
|
material.emission = BEACON_COLOR
|
|
material.emission_energy_multiplier = 5.0
|
|
beacon.material_override = material
|
|
var light := OmniLight3D.new()
|
|
light.name = "BeaconLight"
|
|
light.omni_range = 12.0
|
|
light.light_color = BEACON_COLOR
|
|
light.light_energy = 4.0
|
|
beacon.add_child(light)
|
|
return beacon
|