cameraMoveObserver() { const mouse = this.mouseDown.flatMap(downEvent => { const [cameraX, cameraY] = [this.cameraX, this.cameraY] return this.mouseMove .takeUntil(this.mouseUp) .takeUntil(this.mouseOut) .map(moveEvent => [ cameraX + (downEvent.clientX - moveEvent.clientX) * this.scale, cameraY + (downEvent.clientY - moveEvent.clientY) * this.scale ]) }) const touch = this.touchStart.flatMap(startEvent => { const [cameraX, cameraY] = [this.cameraX, this.cameraY] return this.touchMove .takeUntil(this.touchEnd) .map(moveEvent => [ cameraX + (startEvent.touches[0].clientX - moveEvent.touches[0].clientX) * this.scale, cameraY + (startEvent.touches[0].clientY - moveEvent.touches[0].clientY) * this.scale ]) }) const scroll = this.mouseScroll.map(event => { const hasDelta = event.deltaX !== undefined return [ this.cameraX + (hasDelta ? event.deltaX : (event.wheelDeltaX || 0)), this.cameraY + (hasDelta ? event.deltaY : (event.wheelDeltaY || event.wheelDelta || 0)) ] }) return Rx.Observable.merge(mouse, touch, scroll) }
constructor(canvas, gridSize, options = {}) { this.renderer = PIXI.autoDetectRenderer(0, 0, {view: canvas, backgroundColor: 0xFFFFFF}) this.scene = new PIXI.Container() this.map = new PIXI.Container() this.grid = [] this.scene.addChild(this.map) this.scale = options.scale || 1 this.width = 0 this.height = 0 this.gridSize = gridSize this.tileSize = 32 * this.scale // Tileset texture info this.textureSize = 128 this.textureScale = this.tileSize / this.textureSize // Camera pixel position on the map (top-left) this.cameraX = 0 this.cameraY = 0 // List of all moves this.moves = {} // List of subscribed grids this.grids = [] // Game running state this.running = false // Should the game re-render this.update = true // Event observers this.mouseDown = Rx.Observable.fromEvent(this.renderer.view, "mousedown") this.mouseUp = Rx.Observable.fromEvent(this.renderer.view, "mouseup") this.mouseMove = Rx.Observable.fromEvent(this.renderer.view, "mousemove") this.mouseOut = Rx.Observable.fromEvent(this.renderer.view, "mouseout") this.touchStart = Rx.Observable.fromEvent(this.renderer.view, "touchstart") this.touchEnd = Rx.Observable.fromEvent(this.renderer.view, "touchend") this.touchMove = Rx.Observable.fromEvent(this.renderer.view, "touchmove") this.mouseScroll = Rx.Observable.fromEvent(this.renderer.view, "mousewheel") this.cameraMove = this.cameraMoveObserver() this.tileClick = this.tileClickObserver() // Callbacks this.onCameraMove = () => {} this.onTileClick = () => {} this.onRequestGrid = () => {} this.onDisposeGrid = () => {} }
tileClickObserver() { const dist = ([x1, y1], [x2, y2]) => Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) const mouse = this.mouseDown.flatMap(downEvent => { const p1 = [downEvent.clientX, downEvent.clientY] return this.mouseUp .map(upEvent => [upEvent.clientX, upEvent.clientY]) .filter(p2 => dist(p1, p2) <= this.scale) .map(([x, y]) => this.getScreenTileCoordinates(x, y)) .take(1) }) const touch = this.touchStart.flatMap(startEvent => { const p1 = [startEvent.touches[0].clientX, startEvent.touches[0].clientY] return this.touchEnd .map(endEvent => [endEvent.changedTouches[0].clientX, endEvent.changedTouches[0].clientY]) .filter(p2 => dist(p1, p2) <= this.scale) .map(([x, y]) => this.getScreenTileCoordinates(x, y)) .take(1) }) return Rx.Observable.merge(mouse, touch) }