import { DROWNING_VELOCITY , GRAVITY , PIXEL_PER_METER , TERMINAL_VELOCITY } from "../constants" ; import { Entity } from "../Entity" ; import { Environment } from "../World" ; import { GameObject } from "../scenes/GameScene" ; import { Player } from "./Player" ; export abstract class PhysicsEntity extends Entity { private velocityX = 0 ; private velocityY = 0 ; private maxVelocityX = Infinity ; private maxVelocityY = Infinity ; private floating = false ; private ground : GameObject | null = null ; public carryHeight = this . height ; protected lastGroundPosition = { x : 0 , y : 0 } ; public setFloating ( floating ) { this . floating = floating ; if ( floating ) { this . setVelocity ( 0 , 0 ) ; } } public isFloating ( ) { return this . floating ; } public setMaxVelocity ( maxVelocityX , maxVelocityY = maxVelocityX ) { this . maxVelocityX = maxVelocityX ; this . maxVelocityY = maxVelocityY ; } public accelerate ( x , y ) { this . accelerateX ( x ) ; this . accelerateY ( y ) ; } public accelerateX ( x ) { if ( x > 0 ) { this . velocityX = Math . min ( this . maxVelocityX , this . velocityX + x ) ; } else { this . velocityX = Math . max ( - this . maxVelocityX , this . velocityX + x ) ; } } public accelerateY ( y ) { this . velocityY = Math . min ( this . maxVelocityY , this . velocityY + y ) ; } public decelerate ( x , y ) { this . decelerateX ( x ) ; this . decelerateY ( y ) ; } public decelerateX ( x ) { if ( x > 0 ) { this . velocityX = Math . max ( 0 , this . velocityX - x ) ; } else { this . velocityX = Math . min ( 0 , this . velocityX - x ) ; } } public decelerateY ( y ) { this . velocityY = Math . max ( 0 , this . velocityY - y ) ; } public setVelocity ( x , y ) { this . velocityX = x ; this . velocityY = y ; } public setVelocityX ( x ) { this . velocityX = x ; } public setVelocityY ( y ) { this . velocityY = y ; } public getVelocityX ( ) { return this . velocityX ; } public getVelocityY ( ) { return this . velocityY ; } private checkCollision ( x , y , ignore ? ) { return this . scene . world . collidesWith ( x , y , [ this ] , ignore ) ; } private checkCollisionBox ( x , y , ignore ? ) { for ( let i = - this . width / 2 ; i < this . width / 2 ; i ++ ) { let env = this . checkCollision ( x + i , y , ignore ) ; if ( env !== Environment . AIR ) { return env ; } env = this . checkCollision ( x + i , y + this . height , ignore ) ; if ( env !== Environment . AIR ) { return env ; } } for ( let i = 0 ; i < this . height ; i ++ ) { let env = this . checkCollision ( x - this . width / 2 , y + i , ignore ) ; if ( env !== Environment . AIR ) { return env ; } env = this . checkCollision ( x + this . width / 2 , y + i , ignore ) ; if ( env !== Environment . AIR ) { return env ; } } return Environment . AIR ; } protected updatePosition ( newX , newY ) { if ( this . floating ) { this . x = newX ; this . y = newY ; } else { const env = this . checkCollisionBox ( newX , newY , newY > this . y ? [ Environment . PLATFORM ] : [ ] ) ; if ( env === Environment . AIR || env === Environment . WATER ) { this . x = newX ; this . y = newY ; } else { this . setVelocity ( 0 , 0 ) ; } } } public update ( dt ) { super . update ( dt ) ; const world = this . scene . world ; const ground = world . getObjectAt ( this . x , this . y - 5 , [ this ] ) ; if ( ground instanceof PhysicsEntity ) { this . x += ground . getVelocityX ( ) * PIXEL_PER_METER * dt ; this . y += ground . getVelocityY ( ) * PIXEL_PER_METER * dt ; } this . ground = ground ; this . updatePosition ( this . x + this . velocityX * PIXEL_PER_METER * dt , this . y + this . velocityY * PIXEL_PER_METER * dt ) ; if ( ! this . floating ) { const environment = world . collidesWith ( this . x , this . y - 1 , [ this ] , this instanceof Player && this . jumpDown ? [ Environment . PLATFORM ] : [ ] ) ; if ( environment === Environment . AIR ) { this . velocityY -= this . getGravity ( ) * dt ; if ( this . velocityY < 0 ) { this . velocityY = Math . max ( this . velocityY , TERMINAL_VELOCITY ) ; } } else if ( environment === Environment . WATER ) { this . velocityY = DROWNING_VELOCITY ; this . velocityX = 0 ; } else if ( this . velocityY < 0 ) { this . velocityY = 0 ; if ( ! ( this instanceof Player ) ) { this . velocityX = 0 ; } this . x = Math . round ( this . x ) ; this . y = Math . round ( this . y ) ; } else { this . lastGroundPosition . x = this . x ; this . lastGroundPosition . y = this . y ; } } } protected getGravity ( ) { return GRAVITY ; } public getGround ( ) { return this . ground ; } }