feat: block selector

This commit is contained in:
trafficlunar 2024-12-24 20:12:25 +00:00
parent 78b762a361
commit c9d1b8b44a

View file

@ -1,11 +1,9 @@
import { useContext, useMemo } from "react"; import { useContext, useEffect, useMemo, useState } from "react";
import { Container, Graphics, Sprite, Stage } from "@pixi/react"; import { Container, Graphics, Sprite, Stage } from "@pixi/react";
import * as PIXI from "pixi.js";
import { BlocksIcon } from "lucide-react"; import { BlocksIcon } from "lucide-react";
import constants from "@/constants";
import { TexturesContext } from "@/context/Textures"; import { TexturesContext } from "@/context/Textures";
import { ToolContext } from "@/context/Tool";
import _blockData from "@/data/blocks/programmer-art/data.json"; import _blockData from "@/data/blocks/programmer-art/data.json";
const blockData: BlockData = _blockData; const blockData: BlockData = _blockData;
@ -16,28 +14,32 @@ interface Props {
} }
function SelectorBlocks({ stageWidth, searchInput }: Props) { function SelectorBlocks({ stageWidth, searchInput }: Props) {
const { textures } = useContext(TexturesContext); const { missingTexture, textures } = useContext(TexturesContext);
const { selectedBlock, setSelectedBlock } = useContext(ToolContext);
const blocksPerColumn = Math.floor(stageWidth / (32 + 1)); const [hoverPosition, setHoverPosition] = useState<Position | null>(null);
const blocks = useMemo(() => Object.keys(blockData).filter((value) => value.includes(searchInput)), [searchInput]); const [selectedBlockPosition, setSelectedBlockPosition] = useState<Position | null>({ x: 0, y: 0 });
const textureCache = useMemo(() => { const blocksPerColumn = Math.floor(stageWidth / (32 + 2));
return (blockName: string) => { const filteredBlocks = useMemo(() => Object.keys(blockData).filter((value) => value.includes(searchInput)), [searchInput]);
let texture = textures[`${blockName}.png`];
if (!texture) {
const baseTexture = new PIXI.BaseTexture(constants.MISSING_TEXTURE);
texture = new PIXI.Texture(baseTexture);
}
return texture; const getBlockPosition = (index: number): Position => {
}; const x = (index % blocksPerColumn) * (32 + 2) + 2;
}, [textures]); const y = Math.floor(index / blocksPerColumn) * (32 + 2) + 2;
return { x, y };
const onMouseMove = (e: React.MouseEvent) => {
console.log(e.clientX, e.clientY);
}; };
if (blocks.length == 0) { useEffect(() => {
const index = filteredBlocks.indexOf(selectedBlock);
if (index == -1) {
setSelectedBlockPosition(null);
return;
}
const position = getBlockPosition(index);
setSelectedBlockPosition(position);
}, [searchInput, selectedBlock]);
if (filteredBlocks.length == 0) {
return ( return (
<div className="w-full h-full flex flex-col justify-center items-center gap-1 text-zinc-400"> <div className="w-full h-full flex flex-col justify-center items-center gap-1 text-zinc-400">
<BlocksIcon size={40} /> <BlocksIcon size={40} />
@ -51,24 +53,53 @@ function SelectorBlocks({ stageWidth, searchInput }: Props) {
width={stageWidth} width={stageWidth}
height={Math.ceil(Object.keys(blockData).length / blocksPerColumn) * (32 + 2)} height={Math.ceil(Object.keys(blockData).length / blocksPerColumn) * (32 + 2)}
options={{ backgroundAlpha: 0 }} options={{ backgroundAlpha: 0 }}
onMouseMove={onMouseMove} onMouseLeave={() => setHoverPosition(null)}
> >
<Container> <Container>
{blocks.map((block, index) => { {filteredBlocks.map((block, index) => {
const texture = textureCache(block); const texture = textures[`${block}.png`] ?? missingTexture;
const x = (index % blocksPerColumn) * (32 + 2); const { x, y } = getBlockPosition(index);
const y = Math.floor(index / blocksPerColumn) * (32 + 2);
return <Sprite texture={texture} x={x} y={y} scale={2} />; return (
<Sprite
texture={texture}
x={x}
y={y}
scale={2}
interactive={true}
pointerover={() => setHoverPosition({ x, y })}
click={() => {
setSelectedBlock(block);
setSelectedBlockPosition({ x, y });
}}
/>
);
})} })}
<Graphics {hoverPosition && (
draw={(g) => { <Graphics
g.clear(); x={hoverPosition.x}
g.lineStyle(1, 0xffffff, 1); y={hoverPosition.y}
g.drawRect(0, 0, 16, 16); draw={(g) => {
}} g.clear();
/> g.beginFill("#0000004D");
g.lineStyle(2, 0xffffff, 1, 1);
g.drawRect(0, 0, 32, 32);
}}
/>
)}
{selectedBlockPosition && (
<Graphics
x={selectedBlockPosition.x}
y={selectedBlockPosition.y}
draw={(g) => {
g.clear();
g.lineStyle(2, 0xffffff, 1, 1);
g.drawRect(0, 0, 32, 32);
}}
/>
)}
</Container> </Container>
</Stage> </Stage>
); );