1- import type { Vector } from "../../engine/bundle" ;
1+ import { Vector } from "../../Math/Vector" ;
2+ import type { Camera } from "../Camera" ;
23import { Part } from "../Part" ;
34import type { Transform } from "./Transform" ;
45
@@ -8,6 +9,7 @@ export class Collider extends Part {
89 constructor ( ) {
910 super ( { name : "Collider" } ) ;
1011 this . type = "Collider" ;
12+ this . base = "Collider" ;
1113 }
1214
1315 clone ( memo = new Map ( ) ) : this {
@@ -68,4 +70,95 @@ export class Collider extends Part {
6870 this . hoverbug = `${ this . colliding ? "🟥" : "🟩" } - ${ Array . from ( this . collidingWith ) . map ( o => o . name ) . join ( "," ) } objects`
6971
7072 }
71- }
73+
74+ isVisible ( camera : Camera ) : boolean {
75+ if ( ! this . top ) {
76+ throw new Error ( "Collider cannot calculate visibility without a 'top' (Game instance)." ) ;
77+ }
78+
79+ // 1. Get camera's view boundaries in world space.
80+ const { offset, scale } = camera . getViewMatrix ( ) ;
81+ // cameraPos is the world coordinate at the center of the camera's view.
82+ const cameraPos = offset . multiply ( - 1 ) ;
83+
84+ const screenWidth = this . top . width ;
85+ const screenHeight = this . top . height ;
86+
87+ // Calculate the width and height of the camera's view in world units.
88+ const viewWidth = screenWidth / scale . x ;
89+ const viewHeight = screenHeight / scale . y ;
90+
91+ // 2. Get collider's AABB in world space.
92+ const vertices = this . vertices ;
93+ if ( vertices . length === 0 ) {
94+ return false ; // No vertices means it has no shape to be visible.
95+ }
96+
97+ const transform = this . sibling < Transform > ( "Transform" ) ;
98+ if ( ! transform ) {
99+ throw new Error ( "Can not calculate visibility if transform sibling is not present" ) ;
100+ }
101+
102+ const worldVertices = vertices . map ( vertex => {
103+ return vertex . add ( transform . position )
104+ } ) ;
105+
106+ const cameraVertices = [
107+ new Vector ( cameraPos . x - viewWidth / 2 , cameraPos . y - viewHeight / 2 ) ,
108+ new Vector ( cameraPos . x + viewWidth / 2 , cameraPos . y - viewHeight / 2 ) ,
109+ new Vector ( cameraPos . x + viewWidth / 2 , cameraPos . y + viewHeight / 2 ) ,
110+ new Vector ( cameraPos . x - viewWidth / 2 , cameraPos . y + viewHeight / 2 )
111+ ]
112+
113+
114+ return this . checkVerticesAgainstVertices ( worldVertices , cameraVertices ) ;
115+ }
116+
117+ protected checkVerticesAgainstVertices ( vertices1 : Vector [ ] , vertices2 : Vector [ ] ) {
118+ const axes1 = this . getAxes ( vertices1 ) ;
119+ const axes2 = this . getAxes ( vertices2 ) ;
120+
121+ const axes = axes1 . concat ( axes2 ) ;
122+
123+ for ( const axis of axes ) {
124+ const projection1 = this . project ( vertices1 , axis ) ;
125+ const projection2 = this . project ( vertices2 , axis ) ;
126+
127+ if ( ! this . overlap ( projection1 , projection2 ) ) {
128+ return false ;
129+ }
130+ }
131+
132+ return true ;
133+ }
134+ // Helper to get axes (normals) of a polygon's edges
135+ protected getAxes ( vertices : Vector [ ] ) : Vector [ ] {
136+ const axes : Vector [ ] = [ ] ;
137+ for ( let i = 0 ; i < vertices . length ; i ++ ) {
138+ const p1 = vertices [ i ] ;
139+ const p2 = vertices [ i === vertices . length - 1 ? 0 : i + 1 ] ;
140+ const edge = p2 . subtract ( p1 ) ;
141+ const normal = new Vector ( - edge . y , edge . x ) . normalize ( ) ; // Perpendicular vector (normal)
142+ axes . push ( normal ) ;
143+ }
144+ return axes ;
145+ }
146+ // Helper to project a polygon onto an axis
147+ protected project ( vertices : Vector [ ] , axis : Vector ) : { min : number , max : number } {
148+ let min = axis . dot ( vertices [ 0 ] ) ;
149+ let max = min ;
150+ for ( let i = 1 ; i < vertices . length ; i ++ ) {
151+ const p = axis . dot ( vertices [ i ] ) ;
152+ if ( p < min ) {
153+ min = p ;
154+ } else if ( p > max ) {
155+ max = p ;
156+ }
157+ }
158+ return { min, max } ;
159+ }
160+ // Helper to check if two projections overlap
161+ protected overlap ( proj1 : { min : number , max : number } , proj2 : { min : number , max : number } ) : boolean {
162+ return proj1 . max >= proj2 . min && proj2 . max >= proj1 . min ;
163+ }
164+ }
0 commit comments