import * as Phaser from 'phaser' ; import { Globals } from '../../shared/globals' ; import { CCMapLayer } from '../../shared/phaser/tilemap/cc-map-layer' ; import { Helper } from '../../shared/phaser/helper' ; import { Point } from '../../models/cross-code-map' ; import { MapPan } from '../../shared/phaser/map-pan' ; import { Subscription } from 'rxjs' ; import { SelectedTile } from '../../models/tile-selector' ; import { Vec2 } from '../../shared/phaser/vec2' ; export class TileSelectorScene extends Phaser . Scene { private tileMap ? : Phaser . Tilemaps . Tilemap ; private selecting = false ; private rect ? : Phaser . GameObjects . Rectangle ; private sub ? : Subscription ; private tilesetRendered = false ; private selectedTiles : SelectedTile [ ] = [ ] ; private rightClickStart ? : Point ; private rightClickEnd ? : Point ; private keyBindings : { event : string ; fun : Function ; } [ ] = [ ] ; private tilesetSize : Point = { x : 0 , y : 0 } ; constructor ( ) { super ( { key : 'main' } ) ; } create ( ) { this . cameras . main . setBackgroundColor ( '#616161' ) ; this . game . canvas . oncontextmenu = function ( e ) { e . preventDefault ( ) ; } ; this . sub = Globals . mapLoaderService . selectedLayer . subscribe ( layer => { if ( layer ) { this . drawTileset ( layer ) ; } } ) ; const pan = new MapPan ( this , 'mapPan' ) ; this . add . existing ( pan ) ; this . tileMap = this . add . tilemap ( undefined , Globals . TILE_SIZE , Globals . TILE_SIZE ) ; this . keyBindings = [ ] ; const pointerDown = ( pointer ) => { if ( pointer . rightButtonDown ( ) || pointer . leftButtonDown ( ) ) { this . onMouseDown ( ) ; } } ; this . keyBindings . push ( { event : 'pointerdown' , fun : pointerDown } ) ; const pointerUp = ( pointer ) => { if ( pointer . rightButtonReleased ( ) || pointer . leftButtonReleased ( ) ) { this . onMouseUp ( ) ; } } ; this . keyBindings . push ( { event : 'pointerup' , fun : pointerUp } ) ; this . keyBindings . forEach ( binding => { this . input . addListener ( binding . event , binding . fun ) ; } ) ; } private onMouseDown ( ) { if ( ! this . tilesetRendered ) { return ; } const pointer = this . input . activePointer ; const p = Helper . worldToTile ( pointer . worldX , pointer . worldY ) ; if ( ! Helper . isInBoundsP ( this . tilesetSize , p ) ) { return ; } this . rightClickStart = p ; } public resize ( ) { const size = this . scale . gameSize ; this . game . scale . resize ( size . width , size . height ) ; } private onMouseUp ( ) { if ( ! this . tilesetRendered ) { return ; } this . selectedTiles = [ ] ; if ( ! this . rightClickStart || ! this . rightClickEnd ) { this . drawRect ( 1 , 1 ) ; return ; } const start = this . rightClickStart ; const end = this . rightClickEnd ; const smaller = { x : Math . min ( start . x , end . x ) , y : Math . min ( start . y , end . y ) } ; const bigger = { x : Math . max ( start . x , end . x ) , y : Math . max ( start . y , end . y ) } ; const width = bigger . x - smaller . x + 1 ; const height = bigger . y - smaller . y + 1 ; const tilesWithin = this . tileMap ! . getTilesWithin ( smaller . x , smaller . y , width , height ) ; tilesWithin . forEach ( ( tile ) => { this . selectedTiles . push ( { id : tile . index , offset : Vec2 . sub ( tile , smaller , true ) } ) ; } ) ; this . drawRect ( width , height , smaller . x , smaller . y ) ; this . rightClickStart = undefined ; this . rightClickEnd = undefined ; Globals . phaserEventsService . changeSelectedTiles . next ( this . selectedTiles ) ; } destroy ( ) { if ( this . sub ) { this . sub . unsubscribe ( ) ; } this . keyBindings . forEach ( binding => { this . input . removeListener ( binding . event , binding . fun ) ; } ) ; this . keyBindings = [ ] ; } update ( time , delta ) { const pointer = this . input . activePointer ; const p = Helper . worldToTile ( pointer . worldX , pointer . worldY ) ; if ( this . rightClickStart ) { p . x = Helper . clamp ( p . x , 0 , this . tilesetSize . x - 1 ) ; p . y = Helper . clamp ( p . y , 0 , this . tilesetSize . y - 1 ) ; if ( this . rightClickEnd && this . rightClickEnd . x === p . x && this . rightClickEnd . y === p . y ) { return ; } this . rightClickEnd = p ; const diff = Vec2 . sub ( p , this . rightClickStart , true ) ; const start = { x : this . rightClickStart . x , y : this . rightClickStart . y } ; if ( diff . x >= 0 ) { diff . x ++ ; } else { start . x += 1 ; diff . x -- ; } if ( diff . y >= 0 ) { diff . y ++ ; } else { start . y += 1 ; diff . y -- ; } this . drawRect ( diff . x , diff . y , start . x , start . y ) ; return ; } } private async drawTileset ( selectedLayer ) { this . tilesetRendered = false ; this . drawRect ( 0 , 0 ) ; if ( ! selectedLayer . details . tilesetName ) { if ( this . tileMap ) { this . tileMap . removeAllLayers ( ) ; } return ; } if ( ! this . tileMap ) { return ; } const exists = await Helper . loadTexture ( selectedLayer . details . tilesetName , this ) ; if ( ! exists ) { return ; } const tilesetSize = Helper . getTilesetSize ( this , selectedLayer . details . tilesetName ) ; this . tilesetSize = tilesetSize ; this . tileMap . removeAllLayers ( ) ; const tileset = this . tileMap . addTilesetImage ( 'tileset' , selectedLayer . details . tilesetName , Globals . TILE_SIZE , Globals . TILE_SIZE ) ; if ( ! tileset ) { return ; } tileset . firstgid = 1 ; const layer = this . tileMap . createBlankDynamicLayer ( 'first' , tileset , 0 , 0 , tilesetSize . x , tilesetSize . y ) ; let counter = 1 ; const data = [ ] ; for ( let y = 0 ; y < tilesetSize . y ; y ++ ) { data [ y ] = [ ] ; for ( let x = 0 ; x < tilesetSize . x ; x ++ ) { data [ y ] [ x ] = counter ; counter ++ ; } } layer . putTilesAt ( data , 0 , 0 ) ; this . tilesetRendered = true ; } private drawRect ( width , height , x = 0 , y = 0 ) { if ( this . rect ) { this . rect . destroy ( ) ; } if ( ! this . tilesetRendered ) { return ; } this . rect = this . add . rectangle ( x * Globals . TILE_SIZE , y * Globals . TILE_SIZE , width * Globals . TILE_SIZE , height * Globals . TILE_SIZE ) ; this . rect . setOrigin ( 0 , 0 ) ; this . rect . setStrokeStyle ( 1 , 0xffffff , 0.6 ) ; } }