import { Inject , Singleton } from 'typescript-ioc' ; import { CoreMovementControllerComponent } from './core-movement-controller.component' ; import { merge , Observable , ReplaySubject } from 'rxjs' ; import { Vector3 } from 'three' ; import { filter , map } from 'rxjs/operators' ; import { PhysicsComponent } from '../physics/physics.component' ; import { TeleportContext } from '../teleport/teleport.model' ; import { WorldComponent } from '../world/world.component' ; import { PortalWorldObject } from '../object/portal-world-object' ; @ Singleton export class MovementComponent { readonly position$ : Observable < Vector3 > ; private readonly teleportSubject = new ReplaySubject < TeleportContext > ( ) ; readonly teleport$ = this . teleportSubject . pipe ( ) ; private readonly positionSubject = new ReplaySubject < Vector3 > ( ) ; private readonly position = new Vector3 ( 0 , 1 , 3 ) ; constructor ( @ Inject private readonly movementController , @ Inject private readonly physics , @ Inject private readonly world ) { this . position$ = merge ( this . positionSubject , movementController . movement$ . pipe ( filter ( ( ) => physics . isWorldLoaded ( ) ) , map ( ( movement ) => { const collision = physics . handleCollision ( this . position , movement ) ; if ( collision ?. isPortal ) { const sourcePortal = collision . object as PortalWorldObject ; if ( ! sourcePortal . isVisible ( ) && ! sourcePortal . isInvisible ( ) ) { return movement ; } if ( ! sourcePortal . isEnabled ( ) ) { return null ; } this . teleportSubject . next ( { sourcePortal , collision , } as TeleportContext ) ; } return movement ; } ) , filter ( ( movement ) => ! ! movement ) , map ( ( movement ) => this . position . add ( movement ) ) ) ) ; this . update ( ) ; } setPosition ( position ) { this . position . copy ( position ) ; this . update ( ) ; } private update ( ) { this . positionSubject . next ( this . position ) ; } }