@spearwolf/twopoint5d
Version:
a library to create 2.5d realtime graphics and pixelart with three.js
147 lines • 4.64 kB
JavaScript
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