UNPKG

@phaser-plus/perspective2d

Version:

Create games with a linearly transformed projection

427 lines (401 loc) 13.8 kB
import {ObjectLayer as $aOSJq$ObjectLayer, Scene as $aOSJq$Scene, Structs as $aOSJq$Structs, Layer as $aOSJq$Layer, GameObject as $aOSJq$GameObject} from "@phaser-plus/core"; import {Math as $aOSJq$Math} from "phaser"; import {generateId as $aOSJq$generateId} from "@toolcase/base"; class $54651930da8c7e15$var$GameObject2D extends (0, $aOSJq$GameObject) { /** * @private * @type {World} */ context = null; transform = new (0, $aOSJq$Math).Vector2(0, 0); pivot = new (0, $aOSJq$Math).Vector2(0, 0); /** * * @param {Scene} scene * @param {World} context */ constructor(scene, context){ super(scene, 0, 0); this.context = context; } get projection() { return this.context.projection; } /** * * @param {number} x * @param {number} y */ setTransform(x, y) { this.projection.translate(x, y, this); this.transform.set(x, y); return this; } setTransformX(x) { return this.setTransform(x, this.transform.y); } setTransformY(y) { return this.setTransform(this.transform.x, y); } /** * * @param {string} tag */ addTag(tag) { return this; } /** * * @param {string} tag */ removeTag(tag) { return this; } removeTags() {} /** * * @param {number} time * @param {number} delta */ doUpdate(time, delta) { super.doUpdate(time, delta); this.projection.inverse.translate(this.x, this.y, this.transform); this.pivot.set(this.transform.x, this.transform.y); } } var $54651930da8c7e15$export$2e2bcd8739ae039 = $54651930da8c7e15$var$GameObject2D; /** * @callback SortFn * @param {GameObject2D} objectA * @param {GameObject2D} objectB * @returns {number} */ class $b7dc5985f8b4dc4c$var$DepthSort { /** * @private * @type {string} */ sortFn = "normalSort"; setup() { this.sortFn = "normalSort"; } disable() { this.sortFn = "disabledSort"; } set(inverseX = false, inverseY = false) { if (!inverseX && !inverseY) this.sortFn = "normalSort"; else if (inverseX && !inverseY) this.sortFn = "inverseXSort"; else if (!inverseX && inverseY) this.sortFn = "inverseYSort"; else if (inverseX && inverseY) this.sortFn = "inverseSort"; } /** * @private * @type {SortFn} */ normalSort = (objectA, objectB)=>{ let depth = objectA.depth - objectB.depth; if (depth !== 0) return depth; let orderY = objectA.pivot.y - objectB.pivot.y; if (orderY !== 0) return orderY; return objectA.pivot.x - objectB.pivot.x; }; /** * @private * @type {SortFn} */ inverseXSort = (objectA, objectB)=>{ let depth = objectA.depth - objectB.depth; if (depth !== 0) return depth; let orderY = objectA.pivot.y - objectB.pivot.y; if (orderY !== 0) return orderY; return objectB.pivot.x - objectA.pivot.x; }; /** * @private * @type {SortFn} */ inverseYSort = (objectA, objectB)=>{ let depth = objectA.depth - objectB.depth; if (depth !== 0) return depth; let orderY = objectB.pivot.y - objectA.pivot.y; if (orderY !== 0) return orderY; return objectA.pivot.x - objectB.pivot.x; }; /** * @private * @type {SortFn} */ inverseSort = (objectA, objectB)=>{ let depth = objectA.depth - objectB.depth; if (depth !== 0) return depth; let orderY = objectB.pivot.y - objectA.pivot.y; if (orderY !== 0) return orderY; return objectB.pivot.x - objectA.pivot.x; }; /** * @private * @type {SortFn} */ disabledSort = ()=>{}; get fn() { return this[this.sortFn]; } } var $b7dc5985f8b4dc4c$export$2e2bcd8739ae039 = $b7dc5985f8b4dc4c$var$DepthSort; class $9500e445b73a00bf$var$Grid extends (0, $aOSJq$GameObject) { STYLE = { GRID: 0x59758a, LINES: 0xffffff }; /** @private */ TEXTURE_KEY = ""; /** @private */ TILE_PRECISION = 7; /** * @private * @type {GameObjects.Graphics} */ canvas = null; /** * @private * @type {GameObjects.TileSprite} */ gridTile = null; /** @protected */ onCreate() { this.TEXTURE_KEY = `@toolcase/phaser+grid-${(0, $aOSJq$generateId)(4)}`; const { width: width , height: height } = this.game.config; this.gridTile = this.scene.add.tileSprite(0, 0, width, height).setVisible(false).setOrigin(0); this.add(this.gridTile); } setColors(gridColor, lineColor) { if (typeof gridColor !== "number" || typeof lineColor !== "number") return; this.STYLE.GRID = gridColor; this.STYLE.LINES = lineColor; } /** @private */ setCanvasStyle() { this.canvas.fillStyle(this.STYLE.GRID, 1); this.canvas.lineStyle(1, this.STYLE.LINES, .3); } /** @protected */ onDestroy() {} /** * * @param {Structs.Matrix2} matrix */ setProjection(matrix) { this.canvas = this.scene.add.graphics(); this.setCanvasStyle(); this.add(this.canvas); if (this.scene.textures.exists(this.TEXTURE_KEY)) this.scene.textures.remove(this.TEXTURE_KEY); this.gridTile.setVisible(false); let tile = this.getProjectionTileSize(matrix); let size = 0; for (let value of matrix)size = Math.max(size, Math.abs(value)); if (size < 25) this.drawBackground(); else if (tile.x === 0 || tile.y === 0) this.drawLinearTiles(matrix); else this.drawGridTiles(matrix, tile); this.canvas.clear(); this.canvas.destroy(); this.gridTile.setTexture(this.TEXTURE_KEY); this.gridTile.setVisible(true); } /** * * @param {Cameras.Scene2D.Camera} camera */ move(camera) { this.gridTile.setTilePosition(camera.scrollX, camera.scrollY); } /** * @private * @param {Structs.Matrix2} matrix * @param {M.Vector2} tile */ drawGridTiles(matrix, tile) { let polygons = this.TILE_PRECISION; let pointA = new (0, $aOSJq$Math).Vector2(0, 0); let pointB = new (0, $aOSJq$Math).Vector2(0, 0); let pointC = new (0, $aOSJq$Math).Vector2(0, 0); let pointD = new (0, $aOSJq$Math).Vector2(0, 0); this.canvas.fillRect(0, 0, tile.x, tile.y); for(let x = -polygons; x < polygons; x++)for(let y = -polygons; y < polygons; y++){ matrix.translate(x, y, pointA); matrix.translate(x, y + 1, pointB); matrix.translate(x + 1, y, pointC); matrix.translate(x + 1, y + 1, pointD); this.canvas.beginPath(); this.canvas.moveTo(pointA.x, pointA.y); this.canvas.lineTo(pointB.x, pointB.y); this.canvas.lineTo(pointD.x, pointD.y); this.canvas.strokePath(); } this.canvas.generateTexture(this.TEXTURE_KEY, tile.x, tile.y); } /** @private */ drawLinearTiles(matrix) { let crop = new (0, $aOSJq$Math).Vector2(0, 0); matrix.translate(2, 2, crop); this.canvas.fillRect(0, 0, crop.x, crop.y); this.canvas.lineStyle(1, 0xffffff, .2); this.canvas.strokePoints([ matrix.translate(.8, 1), matrix.translate(1.2, 1) ]); this.canvas.strokePoints([ matrix.translate(1, .8), matrix.translate(1, 1.2) ]); this.canvas.generateTexture(this.TEXTURE_KEY, crop.x, crop.y); } /** @private */ drawBackground() { this.canvas.fillRect(0, 0, 100, 100); this.canvas.lineStyle(1, 0xffffff, .1); this.canvas.strokeCircle(50, 50, 3); this.canvas.generateTexture(this.TEXTURE_KEY, 100, 100); } /** * @private * @param {Structs.Matrix2} matrix */ getProjectionTileSize(matrix) { let refPoint = new (0, $aOSJq$Math).Vector2(matrix.translate(1, 0).x, matrix.translate(0, 1).y); refPoint.x = Math.abs(refPoint.x); refPoint.y = Math.abs(refPoint.y); let point = new (0, $aOSJq$Math).Vector2(); let tempPoint = new (0, $aOSJq$Math).Vector2(); let x = 0; let shiftX = 0; while(shiftX < this.TILE_PRECISION){ x += refPoint.x; shiftX++; matrix.inverse.translate(x, 0, tempPoint); tempPoint.x = Math.round(tempPoint.x * 10) / 10; tempPoint.y = Math.round(tempPoint.y * 10) / 10; if (tempPoint.y % 1 === 0 && tempPoint.y % 1 === 0) { point.x = Math.round(x); break; } } let y = 0; let shiftY = 0; while(shiftY < this.TILE_PRECISION){ y += refPoint.y; shiftY++; matrix.inverse.translate(0, y, tempPoint); tempPoint.x = Math.round(tempPoint.x * 10) / 10; tempPoint.y = Math.round(tempPoint.y * 10) / 10; if (tempPoint.x % 1 === 0 && tempPoint.y % 1 === 0) { point.y = Math.round(y); break; } } return point; } } var $9500e445b73a00bf$export$2e2bcd8739ae039 = $9500e445b73a00bf$var$Grid; /** * @typedef GridColors * @property {number} background * @property {number} lines */ class $9a844ae0df6cdb61$var$World extends (0, $aOSJq$Layer) { /** * @private * @type {Grid} */ grid = null; /** @private */ gridUpdate = null; /** * @private * @type {Structs.Matrix2} */ _projection = (0, $aOSJq$Structs).Matrix2.create(50, 50); sort = new (0, $b7dc5985f8b4dc4c$export$2e2bcd8739ae039)(); /** @protected */ onCreate() { this.grid = new (0, $9500e445b73a00bf$export$2e2bcd8739ae039)(this.scene, 0, 0); this.grid.depth = -Number.MAX_SAFE_INTEGER; this.scene.add.existing(this.grid); this.grid.onCreate(); this.grid.setScrollFactor(0); this.grid.setVisible(false); super.onCreate(); this.onLayerUpdate(); } /** * @protected */ onLayerUpdate() { super.onLayerUpdate(); this.grid.cameraFilter = this.container.cameraFilter; this.grid.move(this.camera); if (this.gridUpdate !== null) { this.grid.setVisible(this.gridUpdate); if (this.gridUpdate) this.grid.setProjection(this._projection); this.gridUpdate = null; } this.container.list.sort(this.sort.fn); if (typeof this.scene.matter !== "undefined") { if (typeof this.scene.matter.world.debugGraphic !== "undefined") this.scene.matter.world.debugGraphic.cameraFilter = this.container.cameraFilter; } } /** @protected */ onDestroy() { super.onDestroy(); } /** * * @param {boolean} flag * @param {GridColors} [colors] */ debug(flag = true, colors = {}) { if (typeof colors === "object") this.grid.setColors(colors.background, colors.lines); if (typeof flag !== "boolean") return this; this.gridUpdate = null; if (this.grid.visible === flag) return this; this.gridUpdate = flag; } /** * * @param {Structs.Matrix2} matrix */ set projection(matrix) { this._projection.setValues(matrix.v00, matrix.v01, matrix.v10, matrix.v11); this.sort.setup(); this.list.forEach((object)=>{ object.setTransform(object.transform.x, object.transform.y); }); if (this.grid.visible) this.gridUpdate = true; return this._projection; } get projection() { return this._projection; } /** * @param {string} key * @param {new GameObject2D} gameObjectClass */ register(key, gameObjectClass) { this.scene.pool.register(key, gameObjectClass, this.createInstanceFn); return this; } /** * @template {GameObject2D} T * @param {string} key * @param {number} x * @param {number} y * @param {Array<string>} tags * @returns {T} */ add(key, x, y) { /** @type {GameObject2D} */ let object = this.scene.pool.obtain(key); if (object === null) return null; this.container.add(object); object.setTransform(x, y); return object; } /** * @template {GameObject2D} T * @param {T} gameObject */ remove(gameObject) { this.container.remove(gameObject); this.scene.pool.release(gameObject); return this; } /** * @private * @param {string} _ * @param {new GameObject2D} gameObjectClass * @param {Scene} scene */ createInstanceFn = (_, gameObjectClass, scene)=>{ let object = new gameObjectClass(scene, this); return object; }; } var $9a844ae0df6cdb61$export$2e2bcd8739ae039 = $9a844ae0df6cdb61$var$World; class $13a5a64f15c34df7$var$Scene2D extends (0, $aOSJq$Scene) { /** * @protected * @type {ObjectLayer} */ ui = null; /** * @protected * @type {World} */ world = null; /** * @protected * @override */ beforeInit() { this.world = this.features.register("world", (0, $9a844ae0df6cdb61$export$2e2bcd8739ae039)); this.ui = this.features.register("ui", (0, $aOSJq$ObjectLayer)); } } var $13a5a64f15c34df7$export$2e2bcd8739ae039 = $13a5a64f15c34df7$var$Scene2D; export {$13a5a64f15c34df7$export$2e2bcd8739ae039 as Scene2D, $9a844ae0df6cdb61$export$2e2bcd8739ae039 as World, $54651930da8c7e15$export$2e2bcd8739ae039 as GameObject2D, $9500e445b73a00bf$export$2e2bcd8739ae039 as Grid};