class_name WorldManager extends Node ## Owns "where is the player and what stays centered on them": ## recenters scenery in the follow_focus group, and shifts the origin ## (teleporting the shift_with_origin group) before float precision degrades. @export var focus: Node3D # the boat @export var ocean: Ocean ## Distance from origin that triggers an origin shift. @export var shift_threshold := 2048.0 ## Default recenter step; nodes can override with a follow_step metadata. ## Keep it a multiple of the ocean's vertex_spacing. @export var follow_step := 16.0 ## True world position of the current local origin (grows over a long voyage). var origin_offset := Vector3.ZERO func true_position(node: Node3D) -> Vector3: return node.global_position + origin_offset func _physics_process(_delta: float) -> void: if focus == null: return _maybe_shift_origin() _recenter_followers() func _maybe_shift_origin() -> void: var p := focus.global_position if Vector2(p.x, p.z).length() < shift_threshold: return var shift := Vector3(snappedf(p.x, follow_step), 0.0, snappedf(p.z, follow_step)) origin_offset += shift for node in get_tree().get_nodes_in_group("shift_with_origin"): node.global_position -= shift node.reset_physics_interpolation() ocean.shift_origin(shift) func _recenter_followers() -> void: for node in get_tree().get_nodes_in_group("follow_focus"): var step: float = node.get_meta("follow_step", follow_step) var new_x := snappedf(focus.global_position.x, step) var new_z := snappedf(focus.global_position.z, step) if new_x != node.global_position.x or new_z != node.global_position.z: node.global_position.x = new_x node.global_position.z = new_z node.reset_physics_interpolation()