import { PixiComponent, applyDefaultProps } from '@pixi/react'; import * as PIXI from 'pixi.js'; import { AnimatedSprite, WorldMap } from '../../convex/aiTown/worldMap'; import * as campfire from '../../data/animations/campfire.json'; import * as gentlesparkle from '../../data/animations/gentlesparkle.json'; import * as gentlewaterfall from '../../data/animations/gentlewaterfall.json'; import * as gentlesplash from '../../data/animations/gentlesplash.json'; import * as windmill from '../../data/animations/windmill.json'; const animations = { 'campfire.json': { spritesheet: campfire, url: '/assets/spritesheets/campfire.png' }, 'gentlesparkle.json': { spritesheet: gentlesparkle, url: '/assets/spritesheets/gentlesparkle32.png', }, 'gentlewaterfall.json': { spritesheet: gentlewaterfall, url: '/assets/spritesheets/gentlewaterfall32.png', }, 'windmill.json': { spritesheet: windmill, url: '/assets/spritesheets/windmill.png' }, 'gentlesplash.json': { spritesheet: gentlesplash, url: '/assets/spritesheets/gentlewaterfall32.png', }, }; export const PixiStaticMap = PixiComponent('StaticMap', { create: (props: { map: WorldMap; [k: string]: any }) => { const map = props.map; const numxtiles = Math.floor(map.tileSetDimX / map.tileDim); const numytiles = Math.floor(map.tileSetDimY / map.tileDim); const bt = PIXI.BaseTexture.from(map.tileSetUrl, { scaleMode: PIXI.SCALE_MODES.NEAREST, }); const tiles = []; for (let x = 0; x < numxtiles; x++) { for (let y = 0; y < numytiles; y++) { tiles[x + y * numxtiles] = new PIXI.Texture( bt, new PIXI.Rectangle(x * map.tileDim, y * map.tileDim, map.tileDim, map.tileDim), ); } } const screenxtiles = map.bgTiles[0].length; const screenytiles = map.bgTiles[0][0].length; const container = new PIXI.Container(); const allLayers = [...map.bgTiles, ...map.objectTiles]; // blit bg & object layers of map onto canvas for (let i = 0; i < screenxtiles * screenytiles; i++) { const x = i % screenxtiles; const y = Math.floor(i / screenxtiles); const xPx = x * map.tileDim; const yPx = y * map.tileDim; // Add all layers of backgrounds. for (const layer of allLayers) { const tileIndex = layer[x][y]; // Some layers may not have tiles at this location. if (tileIndex === -1) continue; const ctile = new PIXI.Sprite(tiles[tileIndex]); ctile.x = xPx; ctile.y = yPx; container.addChild(ctile); } } // TODO: Add layers. const spritesBySheet = new Map(); for (const sprite of map.animatedSprites) { const sheet = sprite.sheet; if (!spritesBySheet.has(sheet)) { spritesBySheet.set(sheet, []); } spritesBySheet.get(sheet)!.push(sprite); } for (const [sheet, sprites] of spritesBySheet.entries()) { const animation = (animations as any)[sheet]; if (!animation) { console.error('Could not find animation', sheet); continue; } const { spritesheet, url } = animation; const texture = PIXI.BaseTexture.from(url, { scaleMode: PIXI.SCALE_MODES.NEAREST, }); const spriteSheet = new PIXI.Spritesheet(texture, spritesheet); spriteSheet.parse().then(() => { for (const sprite of sprites) { const pixiAnimation = spriteSheet.animations[sprite.animation]; if (!pixiAnimation) { console.error('Failed to load animation', sprite); continue; } const pixiSprite = new PIXI.AnimatedSprite(pixiAnimation); pixiSprite.animationSpeed = 0.1; pixiSprite.autoUpdate = true; pixiSprite.x = sprite.x; pixiSprite.y = sprite.y; pixiSprite.width = sprite.w; pixiSprite.height = sprite.h; container.addChild(pixiSprite); pixiSprite.play(); } }); } container.x = 0; container.y = 0; // Set the hit area manually to ensure `pointerdown` events are delivered to this container. container.interactive = true; container.hitArea = new PIXI.Rectangle( 0, 0, screenxtiles * map.tileDim, screenytiles * map.tileDim, ); return container; }, applyProps: (instance, oldProps, newProps) => { applyDefaultProps(instance, oldProps, newProps); }, });