@@ -3,12 +3,15 @@ import { Bounds } from '../types/Bounds';
33
44export class Screen {
55 /**
6- * Checks if a pointer event happened on the left half of a given element.
7- * @param {PointerEvent } event
8- * @param {HTMLElement } element
9- * @param {number } targetCenterX center position (in px, relative to the element) of the target to exclude
10- * @param {number } targetWidth width (in px) of the target to exclude
11- * @returns {boolean | null } true if left side, false if right side, null if inside the exclusion zone
6+ * Determines whether a pointer event occurred on the left half of an element,
7+ * with an optional exclusion zone around a central target.
8+ *
9+ * @param {PointerEvent } event - The pointer event to evaluate.
10+ * @param {HTMLElement } element - The element used as reference for relative coordinates.
11+ * @param {number } targetCenterX - X coordinate (in px, relative to the element) of the exclusion area's center.
12+ * @param {number } targetWidth - Width (in px) of the exclusion area.
13+ * @returns {boolean | null } Returns `true` if the event is on the left half, `false` if on the right half,
14+ * or `null` if the event falls within the exclusion zone.
1215 */
1316 public static isLeftHalf (
1417 event : PointerEvent ,
@@ -31,7 +34,14 @@ export class Screen {
3134 }
3235
3336 /**
34- * Projects a 3D object's bounding box to screen space and returns its horizontal bounds.
37+ * Projects a 3D object's bounding box to screen space and returns its horizontal bounds in pixels.
38+ *
39+ * Note: This projection only considers the object's X-Z extents (Y set to 0) for horizontal bounds.
40+ *
41+ * @param {THREE.Object3D } object - The 3D object whose bounding box will be projected.
42+ * @param {THREE.Camera } camera - The camera used for projection.
43+ * @param {HTMLElement } element - The DOM element representing the render area (used for width in pixels).
44+ * @returns {Bounds } An object containing `centerX` (center in pixels) and `width` (width in pixels).
3545 */
3646 public static getProjectedBoundsX (
3747 object : THREE . Object3D ,
@@ -58,4 +68,51 @@ export class Screen {
5868 width : width ,
5969 } ;
6070 }
71+
72+ /**
73+ * Recalculates horizontal spawn limits for enemies based on the camera and predefined Z depths.
74+ *
75+ * @param {THREE.PerspectiveCamera } camera - The perspective camera used to compute screen bounds at depth.
76+ * @returns {THREE.Vector3[] } An array with two `THREE.Vector3` entries: [leftSpawnPosition, rightSpawnPosition].
77+ */
78+ public static recalculateEnemyLimits ( camera : THREE . PerspectiveCamera ) : THREE . Vector3 [ ] {
79+ const spawnZMax = - 35 ;
80+ const spawnZMin = - 45 ;
81+ const bounds = this . getScreenBoundsAtDepth ( camera , spawnZMax ) ;
82+ return [
83+ new THREE . Vector3 ( bounds . centerX - bounds . width / 2 , 0 , spawnZMin ) ,
84+ new THREE . Vector3 ( bounds . centerX + bounds . width / 2 , 0 , spawnZMax ) ,
85+ ] ;
86+ }
87+
88+ /**
89+ * Calculate the world-space horizontal bounds (X) of the camera's view at a specific Z depth.
90+ *
91+ * This method unprojects normalized device coordinates (NDC) corners to world space,
92+ * intersects the camera ray with the plane at the given Z, and returns the center X and width.
93+ *
94+ * @private
95+ * @param {THREE.PerspectiveCamera } camera - The camera used to unproject screen corners.
96+ * @param {number } z - The world Z coordinate where bounds should be computed.
97+ * @returns {Bounds } An object with `centerX` (center X in world units) and `width` (width in world units).
98+ */
99+ private static getScreenBoundsAtDepth ( camera : THREE . PerspectiveCamera , z : number ) : Bounds {
100+ const ndcCorners = [ new THREE . Vector2 ( - 1 , - 1 ) , new THREE . Vector2 ( 1 , 1 ) ] ;
101+ const xs : number [ ] = [ ] ;
102+
103+ ndcCorners . forEach ( ( corner ) => {
104+ const clipPosition = new THREE . Vector3 ( corner . x , corner . y , 1 ) . unproject ( camera ) ;
105+ const direction = clipPosition . sub ( camera . position ) ;
106+ const t = ( z - camera . position . z ) / direction . z ;
107+ const intersection = camera . position . clone ( ) . add ( direction . multiplyScalar ( t ) ) ;
108+ xs . push ( intersection . x ) ;
109+ } ) ;
110+
111+ const left = Math . min ( ...xs ) ;
112+ const right = Math . max ( ...xs ) ;
113+ return {
114+ centerX : ( left + right ) / 2 ,
115+ width : Math . abs ( right - left ) ,
116+ } ;
117+ }
61118}
0 commit comments