109 lines
3.3 KiB
JavaScript
109 lines
3.3 KiB
JavaScript
import {RenderTexture} from '@pixi/core';
|
|
import {Container} from '@pixi/display';
|
|
import {BlurFilter} from '@pixi/filter-blur';
|
|
import {Graphics} from '@pixi/graphics';
|
|
import {PixiComponent, useApp} from '@pixi/react';
|
|
import {Sprite} from '@pixi/sprite';
|
|
import {useEffect, useState} from 'react';
|
|
|
|
const tileSize = {x: 16, y: 16};
|
|
const radius = 9;
|
|
|
|
function makeFade(renderer) {
|
|
const fade = new Graphics();
|
|
fade.beginFill(0xffffff);
|
|
fade.alpha = 0.5;
|
|
fade.drawCircle(
|
|
tileSize.x * (radius / 2),
|
|
tileSize.y * (radius / 2),
|
|
((tileSize.x + tileSize.y) / 2) * (radius * 0.35),
|
|
)
|
|
fade.filters = [new BlurFilter(24)];
|
|
const renderTexture = RenderTexture.create({
|
|
width: tileSize.x * radius,
|
|
height: tileSize.y * radius,
|
|
});
|
|
renderer.render(fade, {renderTexture});
|
|
return new Sprite(renderTexture);
|
|
}
|
|
|
|
const TargetingGridInternal = PixiComponent('TargetingGrid', {
|
|
create: ({app, ecs}) => {
|
|
const fade = makeFade(app.renderer);
|
|
const grid = new Graphics();
|
|
const lineWidth = 1;
|
|
grid.lineStyle(lineWidth, 0xffffff);
|
|
for (let y = 0; y < radius; ++y) {
|
|
for (let x = 0; x < radius; ++x) {
|
|
grid.drawRect(
|
|
(x * tileSize.x) + (lineWidth / 2),
|
|
(y * tileSize.y) + (lineWidth / 2),
|
|
tileSize.x,
|
|
tileSize.y,
|
|
);
|
|
}
|
|
}
|
|
grid.mask = fade;
|
|
const innerGrid = new Graphics();
|
|
innerGrid.lineStyle(lineWidth, 0x777777);
|
|
for (let y = 0; y < radius; ++y) {
|
|
for (let x = 0; x < radius; ++x) {
|
|
innerGrid.drawRect(
|
|
(x * tileSize.x) + (lineWidth / 2) + 1,
|
|
(y * tileSize.y) + (lineWidth / 2) + 1,
|
|
tileSize.x - 2,
|
|
tileSize.y - 2,
|
|
);
|
|
}
|
|
}
|
|
innerGrid.mask = fade;
|
|
const container = new Container();
|
|
container.addChild(fade, grid, innerGrid);
|
|
// Clamp within layer area.
|
|
const area = new Graphics();
|
|
area.beginFill(0xffffff);
|
|
const {TileLayers: {layers: [layer]}} = ecs.get(1)
|
|
const {x, y} = layer.area;
|
|
area.drawRect(0, 0, x * tileSize.x, y * tileSize.y);
|
|
container.mask = area;
|
|
const top = new Container();
|
|
top.addChild(container, area);
|
|
return top;
|
|
},
|
|
applyProps: ({children: [container]}, oldProps, {entity, radians}) => {
|
|
const pulse = (Math.cos(radians) + 1) * 0.5;
|
|
const {Position: {x, y}} = entity;
|
|
const tileX = x - (x % tileSize.x);
|
|
const tileY = y - (y % tileSize.y);
|
|
const gridX = (tileSize.x * (radius / 2));
|
|
const gridY = (tileSize.y * (radius / 2));
|
|
container.x = tileX + (tileSize.x / 2) - gridX;
|
|
container.y = tileY + (tileSize.y / 2) - gridY;
|
|
container.children[0].x = x % tileSize.x - (tileSize.x / 2) ;
|
|
container.children[0].y = y % tileSize.y - (tileSize.y / 2) ;
|
|
const color = Math.round(255 - (pulse * 255));
|
|
container.children[2].tint = `rgb(${color}, ${color}, ${color})`;
|
|
},
|
|
})
|
|
|
|
export default function TargetingGrid({ecs, entity}) {
|
|
const app = useApp();
|
|
const [radians, setRadians] = useState(0);
|
|
useEffect(() => {
|
|
const handle = setInterval(() => {
|
|
setRadians((radians) => (radians + 0.1) % (Math.PI * 2))
|
|
}, 50);
|
|
return () => {
|
|
clearInterval(handle);
|
|
};
|
|
}, []);
|
|
return (
|
|
<TargetingGridInternal
|
|
app={app}
|
|
ecs={ecs}
|
|
entity={entity}
|
|
radians={radians}
|
|
/>
|
|
);
|
|
}
|