render optimize

master
Denis Ranneft 1 month ago
parent d9d8e72933
commit 0d6a82e0e1

File diff suppressed because it is too large Load Diff

@ -37,6 +37,8 @@ export interface WorldPoint {
type SpritePoolEntry = { type SpritePoolEntry = {
sprite: Sprite; sprite: Sprite;
textureKey: string; textureKey: string;
worldX?: number;
worldY?: number;
}; };
const TERRAIN_SEAM_BLEED_SCALE = 1.002; const TERRAIN_SEAM_BLEED_SCALE = 1.002;
@ -101,6 +103,10 @@ export class GameRenderer {
private _objectSpritePool = new Map<string, SpritePoolEntry>(); private _objectSpritePool = new Map<string, SpritePoolEntry>();
private _tileSpriteFreeList: Sprite[] = []; private _tileSpriteFreeList: Sprite[] = [];
private _objectSpriteFreeList: Sprite[] = []; private _objectSpriteFreeList: Sprite[] = [];
private _usedTileSprites = new Set<string>();
private _usedObjectSprites = new Set<string>();
private _emptySpriteSet = new Set<string>();
private _groundTerrainCache = new Map<string, string>();
private _buildingSpritePool = new Map<string, SpritePoolEntry>(); private _buildingSpritePool = new Map<string, SpritePoolEntry>();
private _characterSpritePool = new Map<string, SpritePoolEntry>(); private _characterSpritePool = new Map<string, SpritePoolEntry>();
private _npcSpritePool = new Map<string, SpritePoolEntry>(); private _npcSpritePool = new Map<string, SpritePoolEntry>();
@ -321,6 +327,8 @@ export class GameRenderer {
textureKey: string, textureKey: string,
texture: SpritePoolEntry['sprite']['texture'], texture: SpritePoolEntry['sprite']['texture'],
layer: Container, layer: Container,
worldX?: number,
worldY?: number,
freeList?: Sprite[], freeList?: Sprite[],
): SpritePoolEntry { ): SpritePoolEntry {
let entry = pool.get(poolKey); let entry = pool.get(poolKey);
@ -332,7 +340,7 @@ export class GameRenderer {
sprite.anchor.set(0.5, 1); sprite.anchor.set(0.5, 1);
sprite.roundPixels = true; sprite.roundPixels = true;
if (!sprite.parent) layer.addChild(sprite); if (!sprite.parent) layer.addChild(sprite);
entry = { sprite, textureKey }; entry = { sprite, textureKey, worldX, worldY };
pool.set(poolKey, entry); pool.set(poolKey, entry);
return entry; return entry;
} }
@ -340,6 +348,10 @@ export class GameRenderer {
entry.sprite.texture = texture; entry.sprite.texture = texture;
entry.textureKey = textureKey; entry.textureKey = textureKey;
} }
if (typeof worldX === 'number' && typeof worldY === 'number') {
entry.worldX = worldX;
entry.worldY = worldY;
}
return entry; return entry;
} }
@ -359,10 +371,8 @@ export class GameRenderer {
maxFreeListSize: number, maxFreeListSize: number,
): void { ): void {
for (const [key, entry] of pool) { for (const [key, entry] of pool) {
const sep = key.indexOf(','); const wx = entry.worldX ?? Number.NaN;
if (sep < 0) continue; const wy = entry.worldY ?? Number.NaN;
const wx = Number(key.slice(0, sep));
const wy = Number(key.slice(sep + 1));
if (!Number.isFinite(wx) || !Number.isFinite(wy)) continue; if (!Number.isFinite(wx) || !Number.isFinite(wy)) continue;
if (wx >= minX && wx <= maxX && wy >= minY && wy <= maxY) continue; if (wx >= minX && wx <= maxX && wy >= minY && wy <= maxY) continue;
pool.delete(key); pool.delete(key);
@ -627,8 +637,20 @@ export class GameRenderer {
const hw = TILE_WIDTH / 2; const hw = TILE_WIDTH / 2;
const hh = TILE_HEIGHT / 2; const hh = TILE_HEIGHT / 2;
const terrainCtx = this._worldTerrainContext; const terrainCtx = this._worldTerrainContext;
const usedTileSprites = new Set<string>(); const usedTileSprites = this._usedTileSprites;
const usedObjectSprites = new Set<string>(); const usedObjectSprites = this._usedObjectSprites;
usedTileSprites.clear();
usedObjectSprites.clear();
const terrainCache = this._groundTerrainCache;
terrainCache.clear();
const terrainAt = (wx: number, wy: number): string => {
const key = `${wx},${wy}`;
const cached = terrainCache.get(key);
if (cached) return cached;
const terrain = proceduralTerrain(wx, wy, terrainCtx);
terrainCache.set(key, terrain);
return terrain;
};
// Pass 1: tiles // Pass 1: tiles
for (let wx = startX; wx <= endX; wx++) { for (let wx = startX; wx <= endX; wx++) {
@ -640,7 +662,7 @@ export class GameRenderer {
) { ) {
continue; continue;
} }
const terrain = proceduralTerrain(wx, wy, terrainCtx); const terrain = terrainAt(wx, wy);
const dark = (wx + wy) % 2 === 0; const dark = (wx + wy) % 2 === 0;
const textureKey = spritesReady ? terrainToTextureKey(terrain) : null; const textureKey = spritesReady ? terrainToTextureKey(terrain) : null;
const texture = textureKey ? this._spriteRegistry.getTexture(textureKey) : null; const texture = textureKey ? this._spriteRegistry.getTexture(textureKey) : null;
@ -654,6 +676,8 @@ export class GameRenderer {
textureKey, textureKey,
texture, texture,
this._groundSpriteLayer, this._groundSpriteLayer,
wx,
wy,
this._tileSpriteFreeList, this._tileSpriteFreeList,
); );
entry.sprite.x = iso.x; entry.sprite.x = iso.x;
@ -705,7 +729,7 @@ export class GameRenderer {
) { ) {
continue; continue;
} }
const terrainHere = proceduralTerrain(wx, wy, terrainCtx); const terrainHere = terrainAt(wx, wy);
const obj = proceduralObject(wx, wy, terrainHere, terrainCtx); const obj = proceduralObject(wx, wy, terrainHere, terrainCtx);
if (!obj) continue; if (!obj) continue;
const variant = tileHash(wx, wy, 999); const variant = tileHash(wx, wy, 999);
@ -720,6 +744,8 @@ export class GameRenderer {
objTextureKey, objTextureKey,
objTexture, objTexture,
this._objectSpriteLayer, this._objectSpriteLayer,
wx,
wy,
this._objectSpriteFreeList, this._objectSpriteFreeList,
); );
entry.sprite.x = iso.x; entry.sprite.x = iso.x;
@ -767,8 +793,8 @@ export class GameRenderer {
1800, 1800,
); );
} else { } else {
this._hideUnusedSprites(this._tileSpritePool, new Set()); this._hideUnusedSprites(this._tileSpritePool, this._emptySpriteSet);
this._hideUnusedSprites(this._objectSpritePool, new Set()); this._hideUnusedSprites(this._objectSpritePool, this._emptySpriteSet);
} }
} }
@ -1926,7 +1952,7 @@ export class GameRenderer {
for (const lbl of this._npcLabels) { for (const lbl of this._npcLabels) {
lbl.visible = false; lbl.visible = false;
} }
this._hideUnusedSprites(this._npcSpritePool, new Set()); this._hideUnusedSprites(this._npcSpritePool, this._emptySpriteSet);
} }
/** /**

Loading…
Cancel
Save