UNPKG

@spearwolf/twopoint5d

Version:

a library to create 2.5d realtime graphics and pixelart with three.js

147 lines 4.64 kB
import { emit, eventize, on } from '@spearwolf/eventize'; import { Vector2, Vector3 } from 'three'; import { TileSprites } from '../sprites/TileSprites/TileSprites.js'; import { TileSet } from '../texture/TileSet.js'; import { VertexObjectPool } from '../vertex-objects/VertexObjectPool.js'; import { Map2DTile } from './Map2DTile.js'; export class Map2DTileSprites extends TileSprites { #tileData; #tiles = new Map(); #deferredTiles = new Set(); #curUpdateSerial = 0; #isReady = false; #tileSet; #nextUpdateShouldResetTiles = false; constructor() { super(); eventize(this); this.name = 'twopoint5d.Map2DTileSprites'; on(this, 'ready', () => this.#addDeferredTiles()); } get tileData() { return this.#tileData; } set tileData(tileData) { const previousTileData = this.#tileData; this.#tileData = tileData; this.#checkReady(); if (previousTileData !== tileData) { emit(this, 'tileDataChanged', tileData, previousTileData); } } get tileSet() { return this.#tileSet; } set tileSet(tileSet) { const previousTileSet = this.#tileSet; this.#tileSet = tileSet; this.#checkReady(); if (previousTileSet !== tileSet) { emit(this, 'tileSetChanged', tileSet, previousTileSet); } } get tilesPool() { return this.geometry?.instancedPool; } #updateReadyState() { this.#isReady = this.tilesPool != null && this.tileData != null && this.tileSet != null; return this.#isReady; } #checkReady() { if (!this.#isReady && this.#updateReadyState()) { emit(this, 'ready'); } } update() { super.update(); this.#checkReady(); } beginUpdate(offset, translate) { this.position.set(offset.x + translate.x, translate.y, offset.y + translate.z); this.#checkReady(); this.#curUpdateSerial = 0; if (this.#nextUpdateShouldResetTiles) { this.#resetTiles(); } } addTile(tile) { if (!this.#isReady) { this.#deferredTiles.add(tile); return; } const tileDataId = this.tileData.getTileIdAt(tile.x, tile.y); if (tileDataId === 0) { return; } const sprite = this.tilesPool.createVO(); sprite.setQuadSize([tile.view.width, tile.view.height]); sprite.setInstancePosition([tile.view.left, 0, tile.view.top]); const frameId = this.tileSet.frameId(tileDataId); const texCoords = this.tileSet.atlas.get(frameId).coords; sprite.setTexCoords([texCoords.s, texCoords.t, texCoords.u, texCoords.v]); this.#tiles.set(tile.id, sprite); ++this.#curUpdateSerial; } #addDeferredTiles = () => { const { size: deferredCount } = this.#deferredTiles; if (deferredCount > 0) { this.#deferredTiles.forEach((tile) => { this.addTile(tile); }); this.#deferredTiles.clear(); this.#syncGeometryBuffers(); } }; reuseTile(tile) { if (!this.#isReady) return; const sprite = this.#tiles.get(tile.id); if (sprite) { sprite.setInstancePosition([tile.view.left, 0, tile.view.top]); ++this.#curUpdateSerial; } else { this.addTile(tile); } } removeTile(tile) { if (!this.#isReady) { this.#deferredTiles.delete(tile); return; } const sprite = this.#tiles.get(tile.id); if (sprite) { this.#tiles.delete(tile.id); this.tilesPool.freeVO(sprite); ++this.#curUpdateSerial; } } resetTiles() { this.#nextUpdateShouldResetTiles = true; } #resetTiles() { if (!this.#isReady) return; for (const sprite of this.#tiles.values()) { this.tilesPool.freeVO(sprite); } this.#tiles.clear(); ++this.#curUpdateSerial; this.#nextUpdateShouldResetTiles = false; } endUpdate() { if (!this.#isReady) return; if (this.#curUpdateSerial) { this.#syncGeometryBuffers(); } } #syncGeometryBuffers() { this.geometry.touch('quadSize', 'texCoords', 'instancePosition'); this.update(); } dispose() { console.warn('TODO Map2DTileSpritesRenderer3D.dispose() is not implemented'); } } //# sourceMappingURL=Map2DTileSprites.js.map