Newer
Older
gnexus-tasks / frontend / src / game / textures.ts
// Pixi-текстуры из пиксель-матриц сада: кэш модульного уровня — текстуры
// статичны, переживают перемонтаж компонента, поэтому при app.destroy
// не уничтожаются (texture: false). Модуль импортирует pixi и попадает
// в async-чанк рендерера (GardenRenderer импортируется динамически).
import { CanvasSource, Rectangle, Texture } from 'pixi.js'
import { drawMatrix } from './pixelart'
import type { Matrix, Palette } from './pixelart'
import {
  DECOR,
  GRASS_A,
  GRASS_B,
  GRASS_SUPER,
  GRASS_TUFT,
  HEDGE,
  HOUSE,
  PAL,
  PLANT_BUILDERS,
  RING_EPIC,
  RING_RARE,
  SELECT_OUTLINE,
  SHADOW,
  WILD,
  plantFlower,
} from './sprites'

const cache = new Map<string, Texture>()

/** Текстура из матрицы; кэшируется по ключу (повторный вызов матрицу не читает). */
export function textureFor(key: string, rows: Matrix, palette: Palette): Texture {
  const hit = cache.get(key)
  if (hit) return hit
  const cv = drawMatrix(rows, palette, 1)
  // CanvasSource (не сырой TextureSource): только он знает uploadMethodId 'image'
  // для загрузки canvas в GPU; TextureSource без адаптера молча не рисуется.
  const source = new CanvasSource({
    resource: cv,
    scaleMode: 'nearest',
    antialias: false,
  })
  const tex = new Texture({ source, frame: new Rectangle(0, 0, cv.width, cv.height) })
  cache.set(key, tex)
  return tex
}

/** Текстура тайла по имени. */
export function tileTexture(
  name: 'grass-a' | 'grass-b' | 'grass-super' | 'grass-tuft' | 'wild' | 'hedge',
): Texture {
  switch (name) {
    case 'grass-a':
      return textureFor('tile:grass-a', GRASS_A, PAL)
    case 'grass-b':
      return textureFor('tile:grass-b', GRASS_B, PAL)
    case 'grass-super':
      return textureFor('tile:grass-super', GRASS_SUPER, PAL)
    case 'grass-tuft':
      return textureFor('tile:grass-tuft', GRASS_TUFT, PAL)
    case 'wild':
      return textureFor('tile:wild', WILD, PAL)
    case 'hedge':
      return textureFor('tile:hedge', HEDGE, PAL)
  }
}

/** Текстура домика. */
export function houseTexture(): Texture {
  return textureFor('house', HOUSE, PAL)
}

/** Текстура растения (вид × стадия). */
export function plantTexture(species: string, stage: number): Texture {
  const build = PLANT_BUILDERS[species] ?? plantFlower
  const rows: Matrix = build(stage)
  return textureFor(`plant:${species}:${stage}`, rows, PAL)
}

/** Текстура декорации по item_key. */
export function decorTexture(key: string): Texture {
  return textureFor(`decor:${key}`, DECOR[key] ?? DECOR.flowerbed!, PAL)
}

/** Кольцо редкости. */
export function ringTexture(rarity: string): Texture {
  return textureFor(`ring:${rarity}`, rarity === 'epic' ? RING_EPIC : RING_RARE, PAL)
}

/** Блёстка (эпик-растения). */
export function sparkleTexture(): Texture {
  return textureFor('sparkle', ['.q.', 'qqq', '.q.'], PAL)
}

/** Рамка выделенной/целевой клетки. */
export function selectOutlineTexture(): Texture {
  return textureFor('select-outline', SELECT_OUTLINE, PAL)
}

/** Овальная тень под объектом (ширина матрицы 24, высота 10). */
export function shadowTexture(): Texture {
  return textureFor('shadow', SHADOW, PAL)
}