feat: block selector
This commit is contained in:
parent
78b762a361
commit
c9d1b8b44a
1 changed files with 65 additions and 34 deletions
|
|
@ -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 getBlockPosition = (index: number): Position => {
|
||||||
const baseTexture = new PIXI.BaseTexture(constants.MISSING_TEXTURE);
|
const x = (index % blocksPerColumn) * (32 + 2) + 2;
|
||||||
texture = new PIXI.Texture(baseTexture);
|
const y = Math.floor(index / blocksPerColumn) * (32 + 2) + 2;
|
||||||
|
return { x, y };
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const index = filteredBlocks.indexOf(selectedBlock);
|
||||||
|
if (index == -1) {
|
||||||
|
setSelectedBlockPosition(null);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
const position = getBlockPosition(index);
|
||||||
|
setSelectedBlockPosition(position);
|
||||||
|
}, [searchInput, selectedBlock]);
|
||||||
|
|
||||||
return texture;
|
if (filteredBlocks.length == 0) {
|
||||||
};
|
|
||||||
}, [textures]);
|
|
||||||
|
|
||||||
const onMouseMove = (e: React.MouseEvent) => {
|
|
||||||
console.log(e.clientX, e.clientY);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (blocks.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}
|
||||||
<Graphics
|
x={x}
|
||||||
draw={(g) => {
|
y={y}
|
||||||
g.clear();
|
scale={2}
|
||||||
g.lineStyle(1, 0xffffff, 1);
|
interactive={true}
|
||||||
g.drawRect(0, 0, 16, 16);
|
pointerover={() => setHoverPosition({ x, y })}
|
||||||
|
click={() => {
|
||||||
|
setSelectedBlock(block);
|
||||||
|
setSelectedBlockPosition({ x, y });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{hoverPosition && (
|
||||||
|
<Graphics
|
||||||
|
x={hoverPosition.x}
|
||||||
|
y={hoverPosition.y}
|
||||||
|
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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue