silphius/app/react-components/targeting-ghost.jsx

96 lines
2.8 KiB
React
Raw Normal View History

2024-06-18 04:36:44 -05:00
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 = 11;
function makeFade(renderer) {
const fade = new Graphics();
fade.beginFill(0xffffff);
fade.alpha = 0.35;
fade.drawCircle(
tileSize.x * (radius / 2),
tileSize.y * (radius / 2),
((tileSize.x + tileSize.y) / 2) * (radius * 0.35),
)
fade.filters = [new BlurFilter(((tileSize.x + tileSize.y) / 2) * 1.25)];
const renderTexture = RenderTexture.create({
width: tileSize.x * radius,
height: tileSize.y * radius,
});
renderer.render(fade, {renderTexture});
return new Sprite(renderTexture);
}
const TargetingGhostInternal = PixiComponent('TargetingGhost', {
create: ({app}) => {
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);
return container;
},
applyProps: (container, oldProps, {cx, cy, px, py, tint}) => {
container.x = px - (px % tileSize.x) - cx + (tileSize.x / 2) - (tileSize.x * (radius / 2));
container.y = py - (py % tileSize.y) - cy + (tileSize.y / 2) - (tileSize.y * (radius / 2));
container.children[0].x = px % tileSize.x - (tileSize.x / 2) ;
container.children[0].y = py % tileSize.y - (tileSize.y / 2) ;
const color = Math.round(255 - (tint * 255));
container.children[2].tint = `rgb(${color}, ${color}, ${color})`;
},
})
export default function TargetingGhost({cx, cy, px, py}) {
const app = useApp();
const [radians, setRadians] = useState(0);
useEffect(() => {
const handle = setInterval(() => {
setRadians((radians) => (radians + 0.2) % (Math.PI * 2))
}, 50);
return () => {
clearInterval(handle);
};
}, []);
return (
<TargetingGhostInternal
app={app}
cx={cx}
cy={cy}
px={px}
py={py}
tint={(Math.cos(radians) + 1) * 0.5}
/>
);
}