Files
CosmicClash/Game/scripts/ball.gd
T
2026-08-07 22:31:17 +01:00

80 lines
2.8 KiB
GDScript

class_name Ball
extends RigidBody3D
# Physics ball. Floor gravity is untouched (gravity_scale in ball.tscn); this
# only adds the wall/ceiling "surface pull" (see ArenaBoundary.get_surface_pull)
# so the ball can cling near a wall for dribbling or hang against the ceiling
# for ceiling shots, plus a safety speed clamp (the ball previously had none).
@export_group("Surface Pull")
@export var wall_pull_strength = 4.0 # Weaker than the ship's — assist, not adherence
@export var wall_pull_range = 2.0
@export var ceiling_pull_strength = 5.5 # Stays below the ball's effective gravity (0.8 * 9.8)
@export var ceiling_pull_range = 2.0
# Kept close to ship_observations.gd's BALL_SPEED_SCALE (30.0) so this feature
# doesn't push ball velocity further out of the range trained policies expect.
const MAX_SPEED := 32.0
var _boundary: ArenaBoundary
var _trail: GPUParticles3D
func _ready() -> void:
_boundary = get_tree().get_first_node_in_group("arena_boundary")
if DisplayServer.get_name() == "headless":
# _integrate_forces remains active; only the render-side trail updater is
# disabled across the many parallel RL environments.
set_physics_process(false)
else:
_build_trail()
func _physics_process(_delta: float) -> void:
if _trail:
var speed_ratio := clampf(linear_velocity.length() / MAX_SPEED, 0.0, 1.0)
_trail.emitting = speed_ratio > 0.12
_trail.amount_ratio = smoothstep(0.12, 1.0, speed_ratio)
func _build_trail() -> void:
var mat := StandardMaterial3D.new()
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
mat.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED
mat.albedo_color = Color(0.55, 0.85, 1.0, 0.42)
mat.emission_enabled = true
mat.emission = Color(0.35, 0.72, 1.0)
mat.emission_energy_multiplier = 1.8
var quad := QuadMesh.new()
quad.size = Vector2(0.22, 0.22)
quad.material = mat
var process := ParticleProcessMaterial.new()
process.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
process.emission_sphere_radius = 0.35
process.gravity = Vector3.ZERO
process.scale_min = 0.35
process.scale_max = 1.0
_trail = GPUParticles3D.new()
_trail.name = "BallTrail"
_trail.amount = 48
_trail.lifetime = 0.48
_trail.local_coords = false
_trail.process_material = process
_trail.draw_pass_1 = quad
_trail.visibility_aabb = AABB(Vector3(-18, -18, -18), Vector3(36, 36, 36))
_trail.emitting = false
add_child(_trail)
func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
if _boundary:
var pull := _boundary.get_surface_pull(
global_position, wall_pull_strength, wall_pull_range,
ceiling_pull_strength, ceiling_pull_range
)
state.apply_central_force(pull * mass)
if state.linear_velocity.length() > MAX_SPEED:
state.linear_velocity = state.linear_velocity.normalized() * MAX_SPEED