@@ -53,8 +53,6 @@ class Entity extends EventEmitter {
5353 static object_name :string = 'oUnknownEntity' ;
5454 type : string ;
5555 object_name : string ;
56- // type = Entity.type;
57- // object_name = Entity.object_name;
5856
5957 is_solid = false ;
6058 is_static = false ;
@@ -63,12 +61,14 @@ class Entity extends EventEmitter {
6361 pos :Point ; // keep in mind that the coordinates are always set to a whole number (to achieve pixel-perfect collisions)
6462 spd :Point ; // speed in pixels per second, can be fractional
6563 angle :number = 0 ;
64+ origin :Point = { x : 0 , y : 0 } ; // origin from 0 (top/left) to 1 (bottom/right)
6665
6766 prev_pos :Point ;
6867 serialized :SerializedEntity ; // save the last serialized version of this entity (to compare changes)
6968
7069 base_size :Point = { x : 64 , y : 64 } ;
7170 scale :Point = { x : 1 , y : 1 } ;
71+ flip :Point = { x : 0 , y : 0 } ;
7272
7373
7474 // the custom variables that need sending with the entitiy
@@ -84,6 +84,7 @@ class Entity extends EventEmitter {
8484
8585 collider :Collider = null ; // a polygon or a circle
8686 collider_type :ColliderType | string = 'box' ;
87+ collider_origin :Point = { x : 0 , y : 0 } ;
8788 collider_radius :number = this . width / 2 ; // only relevant when collider_type is 'circle'
8889 collider_vertices :Point [ ] = [ ] ; // if this is not overridden, a default rectangle collider will be used
8990
@@ -112,7 +113,7 @@ class Entity extends EventEmitter {
112113 if ( typeof value === 'string' ) {
113114 this . _state = this . states [ value ] ;
114115 }
115- // it's a number
116+ // state is a number
116117 // (-1 means keep the old state)
117118 else if ( value != - 1 ) {
118119 this . _state = value ;
@@ -133,14 +134,13 @@ class Entity extends EventEmitter {
133134 this . id = crypto . randomUUID ( ) ;
134135 this . room = room ;
135136 this . pos = { x, y } ;
136- this . spd = { x : 0 , y : 0 } ;
137+ this . spd = { x : 0 , y : 0 } ;
137138 this . prev_pos = { x, y } ;
138139
139140 this . type = this . constructor [ 'type' ] ;
140141 this . object_name = this . constructor [ 'object_name' ] ;
141142
142143 this . createCollider ( ) ;
143- this . collider . entity = this ;
144144
145145 this . tree . insert ( this . collider ) ;
146146 }
@@ -194,12 +194,15 @@ class Entity extends EventEmitter {
194194 }
195195
196196 public createCollider ( x = this . x , y = this . y ) {
197- let pos = { x : x , y : y } ;
197+ let pos = {
198+ x : x + this . width * ( this . collider_origin . x - this . origin . x ) ,
199+ y : y + this . height * ( this . collider_origin . y - this . origin . y )
200+ } ;
198201
199202 // create the collider
200203 switch ( this . collider_type ) {
201204 case 'box' :
202- this . collider = new BoxCollider ( pos , this . width - .01 , this . height - .01 ) ;
205+ this . collider = new BoxCollider ( pos , this . base_size . x - .01 , this . base_size . y - .01 ) ;
203206 break ;
204207 case 'circle' :
205208 this . collider = new CircleCollider ( pos , this . collider_radius ) ;
@@ -212,6 +215,10 @@ class Entity extends EventEmitter {
212215 throw 'Unknown collider type: ' + this . collider_type ;
213216 }
214217
218+ this . collider . setScale ( this . xscale , this . yscale ) ;
219+ this . collider . setAngle ( this . angle ) ;
220+ // this.tree.updateBody(this.collider);
221+
215222 this . collider . entity = this ;
216223 }
217224
@@ -224,46 +231,72 @@ class Entity extends EventEmitter {
224231 this . tree . insert ( this . collider ) ;
225232 }
226233
227- protected updateCollider ( x = this . x , y = this . y ) {
228- if ( this . size . x != this . prev_size . x || this . size . y != this . prev_size . y ) {
229- this . regenerateCollider ( x , y ) ;
234+ protected updateCollider ( x = this . x , y = this . y , collider = this . collider ) {
235+ let pos = {
236+ x : x + this . width * ( this . collider_origin . x - this . origin . x ) ,
237+ y : y + this . height * ( this . collider_origin . y - this . origin . y )
238+ } ;
239+
240+ if ( collider === this . collider ) {
241+ collider . setScale ( this . xscale , this . yscale ) ;
242+ collider . setAngle ( this . angle ) ;
243+ collider . setPosition ( pos . x , pos . y ) ;
244+ }
245+ else {
246+ collider . setPosition ( x , y ) ;
230247 }
231248
232- this . collider . setAngle ( this . angle ) ;
233- this . collider . setPosition ( x , y ) ;
234- this . tree . updateBody ( this . collider ) ;
249+ this . tree . updateBody ( collider ) ;
235250 }
236251
237- public checkCollision ( x : number = this . x , y : number = this . y , e :Entity ) :boolean {
238- this . updateCollider ( x , y ) ;
239- return this . tree . checkCollision ( this . collider , e . collider ) ;
252+ public checkCollision ( x : number = this . x , y : number = this . y , e :Entity , collider = this . collider ) :boolean {
253+ this . updateCollider ( x , y , collider ) ;
254+
255+ let result = this . tree . checkCollision ( collider , e . collider ) ;
256+
257+ // move back the collider
258+ if ( collider === this . collider )
259+ this . updateCollider ( this . x , this . y ) ;
260+
261+ return result ;
240262 }
241263
242- public placeMeeting ( x :number = this . x , y :number = this . y , type :EntityType | string = 'solid' ) :boolean {
243- this . updateCollider ( x , y ) ;
264+ public placeMeeting ( x :number = this . x , y :number = this . y , type :EntityType | string = 'solid' , collider = this . collider ) :boolean {
265+ this . updateCollider ( x , y , collider ) ;
244266
245267 this . prev_size = { x : this . size . x , y : this . size . y }
246268
247- return this . tree . checkOne ( this . collider , ( res ) => {
269+ let result = this . tree . checkOne ( this . collider , ( res ) => {
248270 let e = res . b . entity ;
249- return e . matchesType ( type ) ;
271+ return e && e . matchesType ( type ) ;
250272 } ) ;
273+
274+ // move back the collider
275+ if ( collider === this . collider )
276+ this . updateCollider ( this . x , this . y ) ;
277+
278+ return result ;
251279 }
252280
253- public placeMeetingAll < T = Entity > ( x :number = this . x , y :number = this . y , type :EntityType | string = 'solid' ) :T [ ] {
254- this . updateCollider ( x , y ) ;
281+ public placeMeetingAll < T = Entity > ( x :number = this . x , y :number = this . y , type :EntityType | string = 'solid' , collider = this . collider ) :T [ ] {
282+ this . updateCollider ( x , y , collider ) ;
255283
256284 let entities = [ ] ;
257- this . tree . checkOne ( this . collider , ( res ) => {
285+ this . tree . checkOne ( collider , ( res ) => {
258286 let e = res . b . entity ;
259- if ( e . matchesType ( type ) )
287+ if ( e && e . matchesType ( type ) )
260288 entities . push ( e ) ;
261289 } ) ;
290+
291+ // move back the collider
292+ if ( collider === this . collider )
293+ this . updateCollider ( this . x , this . y ) ;
294+
262295 return entities ;
263296 }
264297
265298 isOutsideRoom ( x = this . x , y = this . y ) :boolean {
266- let bbox = this . bbox ; // this is an optimization btw
299+ let bbox = this . bbox ; // don't call the getter every time
267300
268301 return bbox . left - this . x + x > this . room . width
269302 || bbox . right - this . x + x < 0
@@ -301,8 +334,11 @@ class Entity extends EventEmitter {
301334
302335 // removes the entity from the room (and triggers the 'remove' event)
303336 public remove ( ) {
304- this . emit ( 'remove' ) ;
305337 let idx = this . room . entities . indexOf ( this ) ;
338+ if ( idx === - 1 ) { // already removed
339+ return ;
340+ }
341+ this . emit ( 'remove' ) ;
306342 this . room . entities . splice ( idx , 1 ) ;
307343 this . tree . remove ( this . collider ) ;
308344 }
@@ -343,11 +379,14 @@ class Entity extends EventEmitter {
343379 let x :number = this . x , y :number = this . y ;
344380 let w :number = this . width , h :number = this . height ;
345381
382+ let ox = this . origin . x ;
383+ let oy = this . origin . y ;
384+
346385 return {
347- left : x ,
348- top : y ,
349- right : x + w ,
350- bottom : y + h
386+ left : x - w * ox ,
387+ top : y - h * oy ,
388+ right : x + w * ( 1 - ox ) ,
389+ bottom : y + h * ( 1 - oy )
351390 }
352391 }
353392
0 commit comments