Spaces:
Sleeping
Sleeping
File size: 5,527 Bytes
90cbf22 14eb533 90cbf22 14eb533 90cbf22 14eb533 90cbf22 14eb533 90cbf22 14eb533 90cbf22 df2ef4f 90cbf22 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
import { PixiComponent, applyDefaultProps } from '@pixi/react';
import * as PIXI from 'pixi.js';
import { AnimatedSprite, WorldMap, TileLayer } 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';
import React from 'react';
export type MapProps = {
map: WorldMap;
[k: string]: any;
};
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',},
};
const createTiles = (map: WorldMap) => {
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),
);
}
}
return tiles;
};
const renderMap = (container: PIXI.Container, map:WorldMap, tiles: PIXI.Texture[]) => {
const screenxtiles = map.bgTiles[0].length;
const screenytiles = map.bgTiles[0][0].length;
const allLayers = [...map.bgTiles, ...map.objectTiles, ...map.decorTiles];
// 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);
}
}
};
const createAnimatedSprites = (container: PIXI.Container, map: WorldMap) => {
const spritesBySheet = new Map<string, AnimatedSprite[]>();
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();
}
});
}
};
export const PixiStaticMapComponent = PixiComponent('StaticMap', {
create: (props: { map: WorldMap; [k: string]: any }) => {
const container = new PIXI.Container();
const tiles = createTiles(props.map);
renderMap(container, props.map, tiles);
createAnimatedSprites(container, props.map);
container.x = 0;
container.y = 0;
// Set the hit area manually to ensure `pointerdown` events are delivered to this container.
const screenxtiles = props.map.bgTiles[0].length;
const screenytiles = props.map.bgTiles[0][0].length;
container.interactive = true;
container.hitArea = new PIXI.Rectangle(
0,
0,
screenxtiles * props.map.tileDim,
screenytiles * props.map.tileDim,
);
return container;
},
applyProps: (instance, oldProps: any, newProps: any) => {
if (oldProps.map !== newProps.map) {
instance.removeChildren();
const tiles = createTiles(newProps.map);
renderMap(instance, newProps.map, tiles);
createAnimatedSprites(instance, newProps.map);
}
applyDefaultProps(instance, oldProps, newProps);
},
});
const PixiStaticMap = React.memo(
(props: MapProps) => {
return <PixiStaticMapComponent {...props} />;
},
(prevProps, nextProps) => {
return (
prevProps.map.bgTiles === nextProps.map.bgTiles &&
prevProps.map.objectTiles === nextProps.map.objectTiles &&
prevProps.map.decorTiles === nextProps.map.decorTiles
);
}
);
export default PixiStaticMap;
|