From 31b0a5b8087a73766613b73fa2a2b2e53f56df3f Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sat, 25 Apr 2026 18:02:32 +0200 Subject: [PATCH] Implement line-of-sight checks for target visibility --- src/runtime-three/runtime-host.ts | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/runtime-three/runtime-host.ts b/src/runtime-three/runtime-host.ts index f098b3ee..bec3a6dd 100644 --- a/src/runtime-three/runtime-host.ts +++ b/src/runtime-three/runtime-host.ts @@ -5545,6 +5545,49 @@ export class RuntimeHost { this.runtimeTargetSwitchInputHeld = false; } + private isRuntimeTargetVisibleFrom( + origin: { x: number; y: number; z: number }, + target: { center: { x: number; y: number; z: number }; range: number } + ): boolean { + if (this.collisionWorld === null) { + return true; + } + + return this.collisionWorld.isLineSegmentClear(origin, target.center, { + targetClearance: Math.min( + TARGETING_VISIBILITY_TARGET_CLEARANCE, + Math.max(0.15, target.range * 0.35) + ) + }); + } + + private isRuntimeTargetCameraVisible(target: { + center: { x: number; y: number; z: number }; + range: number; + }): boolean { + return this.isRuntimeTargetVisibleFrom( + { + x: this.camera.position.x, + y: this.camera.position.y, + z: this.camera.position.z + }, + target + ); + } + + private isRuntimeTargetPlayerVisible(target: { + center: { x: number; y: number; z: number }; + range: number; + }): boolean { + const playerEyePosition = this.currentPlayerControllerTelemetry?.eyePosition; + + if (playerEyePosition === undefined) { + return false; + } + + return this.isRuntimeTargetVisibleFrom(playerEyePosition, target); + } + private refreshRuntimeTargetingState() { if ( this.runtimeScene === null ||