neon-sprawl/client/scripts/interaction_radius_indicato...

45 lines
1.5 KiB
GDScript

extends Node3D
## NS-18 / NEO-25: **Client preview only** — glow per interactable when [CharacterBody3D] is within
## horizontal radius (X/Z, inclusive). Data comes from [method setup_glow_groups] after
## `GET /game/world/interactables`. Server `POST …/interact` remains authoritative.
const EMISSION_DIM := 0.12
const EMISSION_BRIGHT := 7.0
var _player: CharacterBody3D
## Each element: [code]anchor[/code] [Vector3], [code]radius[/code] [float],
## [code]material[/code] [StandardMaterial3D], [code]markers[/code] [Array] of [MeshInstance3D]
## (optional; emission driven via material).
var _glow_groups: Array = []
func setup_player(player: CharacterBody3D) -> void:
_player = player
func setup_glow_groups(groups: Array) -> void:
_glow_groups = groups
func _process(_delta: float) -> void:
if _player == null or _glow_groups.is_empty():
return
var px: float = _player.global_position.x
var pz: float = _player.global_position.z
for g in _glow_groups:
if not g is Dictionary:
continue
var d: Dictionary = g
var anchor: Variant = d.get("anchor", null)
var mat: Variant = d.get("material", null)
if not anchor is Vector3 or not mat is StandardMaterial3D:
continue
var a: Vector3 = anchor
var m: StandardMaterial3D = mat
var r: float = float(d.get("radius", 0.0))
var dx: float = px - a.x
var dz: float = pz - a.z
var in_range: bool = (dx * dx + dz * dz) <= r * r
m.emission_energy_multiplier = EMISSION_BRIGHT if in_range else EMISSION_DIM