Files
Ransom-s-wake/game/world/sites/vehicle_test_environment.gd
T

154 lines
4.5 KiB
GDScript

class_name VehicleTestEnvironment
extends Node3D
const TERRAIN_COLUMNS := 61
const TERRAIN_ROWS := 69
const TERRAIN_WIDTH_M := 180.0
const TERRAIN_LENGTH_M := 200.0
const TERRAIN_NEAR_Z := 28.0
func _ready() -> void:
_add_bathymetric_terrain()
_place_calibration_target()
_add_suspended_particles()
func _add_suspended_particles() -> void:
var particles := GPUParticles3D.new()
particles.name = "SuspendedParticles"
particles.position = Vector3(0.0, -34.0, -42.0)
particles.amount = 360
particles.lifetime = 14.0
particles.preprocess = 14.0
particles.visibility_aabb = AABB(
Vector3(-50.0, -35.0, -78.0),
Vector3(100.0, 70.0, 156.0)
)
var motion := ParticleProcessMaterial.new()
motion.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
motion.emission_box_extents = Vector3(45.0, 28.0, 70.0)
motion.direction = Vector3(0.1, 0.04, 0.0)
motion.spread = 180.0
motion.initial_velocity_min = 0.02
motion.initial_velocity_max = 0.09
motion.gravity = Vector3.ZERO
motion.scale_min = 0.025
motion.scale_max = 0.08
particles.process_material = motion
var particle_mesh := SphereMesh.new()
particle_mesh.radius = 0.035
particle_mesh.height = 0.07
particles.draw_pass_1 = particle_mesh
add_child(particles)
func _add_bathymetric_terrain() -> void:
var surface := SurfaceTool.new()
surface.begin(Mesh.PRIMITIVE_TRIANGLES)
for row in range(TERRAIN_ROWS - 1):
for column in range(TERRAIN_COLUMNS - 1):
var top_left := _terrain_vertex(row, column)
var top_right := _terrain_vertex(row, column + 1)
var bottom_left := _terrain_vertex(row + 1, column)
var bottom_right := _terrain_vertex(row + 1, column + 1)
_add_terrain_triangle(surface, top_left, top_right, bottom_left)
_add_terrain_triangle(surface, top_right, bottom_right, bottom_left)
surface.generate_normals()
var mesh := surface.commit()
var body := StaticBody3D.new()
body.name = "BathymetricTerrain"
body.set_meta("sonar_material", 1)
body.set_meta("sonar_reflectivity", 0.72)
var mesh_instance := MeshInstance3D.new()
mesh_instance.name = "Mesh"
mesh_instance.mesh = mesh
var material := StandardMaterial3D.new()
material.albedo_color = Color(0.075, 0.19, 0.19)
material.roughness = 0.92
mesh_instance.material_override = material
body.add_child(mesh_instance)
var collision := CollisionShape3D.new()
collision.name = "Collision"
var height_map := HeightMapShape3D.new()
height_map.map_width = TERRAIN_COLUMNS
height_map.map_depth = TERRAIN_ROWS
var height_data := PackedFloat32Array()
height_data.resize(TERRAIN_COLUMNS * TERRAIN_ROWS)
for row in TERRAIN_ROWS:
for column in TERRAIN_COLUMNS:
var vertex := _terrain_vertex(row, column)
height_data[row * TERRAIN_COLUMNS + column] = vertex.y
height_map.map_data = height_data
collision.shape = height_map
collision.position = Vector3(
0.0,
0.0,
TERRAIN_NEAR_Z - TERRAIN_LENGTH_M * 0.5
)
collision.scale = Vector3(
TERRAIN_WIDTH_M / float(TERRAIN_COLUMNS - 1),
1.0,
TERRAIN_LENGTH_M / float(TERRAIN_ROWS - 1)
)
body.add_child(collision)
add_child(body)
func _terrain_vertex(row: int, column: int) -> Vector3:
var x := lerpf(
-TERRAIN_WIDTH_M * 0.5,
TERRAIN_WIDTH_M * 0.5,
float(column) / float(TERRAIN_COLUMNS - 1)
)
var z := TERRAIN_NEAR_Z - (
TERRAIN_LENGTH_M * float(row) / float(TERRAIN_ROWS - 1)
)
return Vector3(x, _terrain_height(x, z), z)
func _terrain_height(x: float, z: float) -> float:
var distance_ratio := clampf(
(TERRAIN_NEAR_Z - z) / TERRAIN_LENGTH_M,
0.0,
1.0
)
var base := lerpf(-40.0, -78.0, distance_ratio)
var left_ridge := 13.0 * exp(
-(pow(x + 24.0, 2.0) / 210.0 + pow(z + 48.0, 2.0) / 980.0)
)
var right_ridge := 15.0 * exp(
-(pow(x - 25.0, 2.0) / 250.0 + pow(z + 58.0, 2.0) / 1150.0)
)
var channel := -8.5 * exp(
-(pow(x, 2.0) / 120.0 + pow(z + 66.0, 2.0) / 2500.0)
)
var rear_rise := 8.0 * exp(
-(pow(x + 5.0, 2.0) / 900.0 + pow(z + 125.0, 2.0) / 620.0)
)
var undulation := 1.8 * sin(x * 0.075) * cos(z * 0.048)
return base + left_ridge + right_ridge + channel + rear_rise + undulation
func _add_terrain_triangle(
surface: SurfaceTool,
a: Vector3,
b: Vector3,
c: Vector3
) -> void:
surface.set_uv(Vector2(a.x, a.z) * 0.02)
surface.add_vertex(a)
surface.set_uv(Vector2(b.x, b.z) * 0.02)
surface.add_vertex(b)
surface.set_uv(Vector2(c.x, c.z) * 0.02)
surface.add_vertex(c)
func _place_calibration_target() -> void:
var target := get_node_or_null("SonarCalibrationTarget") as Node3D
if target != null:
target.position.y = _terrain_height(target.position.x, target.position.z) + 2.5