feat: add grid

This commit is contained in:
trafficlunar 2024-12-13 22:31:03 +00:00
parent f2b3910432
commit 30beead56c
6 changed files with 96 additions and 19 deletions

View file

@ -1,3 +1,4 @@
import { SettingsProvider } from "./context/SettingsContext";
import { TexturesProvider } from "./context/TexturesContext"; import { TexturesProvider } from "./context/TexturesContext";
import { ToolProvider } from "./context/ToolContext"; import { ToolProvider } from "./context/ToolContext";
@ -7,15 +8,17 @@ import Canvas from "./components/Canvas";
function App() { function App() {
return ( return (
<TexturesProvider> <SettingsProvider>
<ToolProvider> <TexturesProvider>
<main className="h-screen grid grid-rows-[2.5rem_1fr] grid-cols-[2.5rem_1fr]"> <ToolProvider>
<Menubar /> <main className="h-screen grid grid-rows-[2.5rem_1fr] grid-cols-[2.5rem_1fr]">
<Toolbar /> <Menubar />
<Canvas /> <Toolbar />
</main> <Canvas />
</ToolProvider> </main>
</TexturesProvider> </ToolProvider>
</TexturesProvider>
</SettingsProvider>
); );
} }

View file

@ -2,10 +2,12 @@ import React, { useCallback, useContext, useEffect, useMemo, useRef, useState }
import { Container, Stage } from "@pixi/react"; import { Container, Stage } from "@pixi/react";
import * as PIXI from "pixi.js"; import * as PIXI from "pixi.js";
import { SettingsContext } from "@/context/SettingsContext";
import { ToolContext } from "@/context/ToolContext"; import { ToolContext } from "@/context/ToolContext";
import { TexturesContext } from "@/context/TexturesContext"; import { TexturesContext } from "@/context/TexturesContext";
import Blocks from "./Blocks"; import Blocks from "./Blocks";
import Grid from "./Grid";
import Cursor from "./Cursor"; import Cursor from "./Cursor";
import CursorInformation from "./information/Cursor"; import CursorInformation from "./information/Cursor";
import CanvasInformation from "./information/Canvas"; import CanvasInformation from "./information/Canvas";
@ -14,11 +16,12 @@ import CanvasInformation from "./information/Canvas";
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
function Canvas() { function Canvas() {
const { settings } = useContext(SettingsContext);
const { tool, selectedBlock } = useContext(ToolContext); const { tool, selectedBlock } = useContext(ToolContext);
const textures = useContext(TexturesContext); const textures = useContext(TexturesContext);
const stageContainerRef = useRef<HTMLDivElement>(null); const stageContainerRef = useRef<HTMLDivElement>(null);
const [stageSize, setStageSize] = useState({ width: 0, height: 0 }); const [stageSize, setStageSize] = useState<Dimension>({ width: 0, height: 0 });
const [coords, setCoords] = useState<Position>({ x: 0, y: 0 }); const [coords, setCoords] = useState<Position>({ x: 0, y: 0 });
const [scale, setScale] = useState(1); const [scale, setScale] = useState(1);
@ -136,6 +139,12 @@ function Canvas() {
<Blocks blocks={blocks} setBlocks={setBlocks} textures={textures} /> <Blocks blocks={blocks} setBlocks={setBlocks} textures={textures} />
<Cursor mouseCoords={mouseCoords} /> <Cursor mouseCoords={mouseCoords} />
</Container> </Container>
{settings.grid && (
<Container>
<Grid stageSize={stageSize} coords={coords} scale={scale} />
</Container>
)}
</Stage> </Stage>
<CursorInformation mouseCoords={mouseCoords} blocks={blocks} /> <CursorInformation mouseCoords={mouseCoords} blocks={blocks} />

32
src/components/Grid.tsx Normal file
View file

@ -0,0 +1,32 @@
import { Graphics } from "@pixi/react";
interface Props {
stageSize: Dimension;
coords: Position;
scale: number;
}
function Grid({ stageSize, coords, scale }: Props) {
return (
<Graphics
draw={(g) => {
g.clear();
g.lineStyle(1, 0xffffff, 0.1);
const tileSize = 16 * scale;
for (let x = coords.x % tileSize; x < stageSize.width; x += tileSize) {
g.moveTo(x, 0);
g.lineTo(x, stageSize.height);
}
for (let y = coords.y % tileSize; y < stageSize.height; y += tileSize) {
g.moveTo(0, y);
g.lineTo(stageSize.width, y);
}
}}
/>
);
}
export default Grid;

View file

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from "react"; import React, { useMemo } from "react";
import { Slider } from "@/components/ui/slider"; import { Slider } from "@/components/ui/slider";
interface Props { interface Props {
@ -22,8 +22,8 @@ function CanvasInformation({ scale, setScale, blocks }: Props) {
}); });
return { return {
x: maxX - minX, width: maxX - minX,
y: maxY - minY, height: maxY - minY,
}; };
}, [blocks]); }, [blocks]);
@ -36,8 +36,8 @@ function CanvasInformation({ scale, setScale, blocks }: Props) {
<div className="flex flex-col items-end gap-1"> <div className="flex flex-col items-end gap-1">
<div className="info-child">{Math.floor(scale * 100)}%</div> <div className="info-child">{Math.floor(scale * 100)}%</div>
<div className="info-child"> <div className="info-child">
<span>W: {canvasSize.x} </span> <span>W: {canvasSize.width} </span>
<span>H: {canvasSize.y}</span> <span>H: {canvasSize.height}</span>
</div> </div>
</div> </div>

View file

@ -0,0 +1,24 @@
import { createContext, ReactNode, useState } from "react";
interface Props {
children: ReactNode;
}
const defaultSettings: Settings = {
grid: false,
};
export const SettingsContext = createContext({
settings: defaultSettings,
setSetting: <K extends keyof Settings>(key: K, value: Settings[K]) => {},
});
export const SettingsProvider = ({ children }: Props) => {
const [settings, setSettings] = useState<Settings>(defaultSettings);
const setSetting = <K extends keyof Settings>(key: K, value: Settings[K]) => {
setSettings((prev) => ({ ...prev, [key]: value }));
};
return <SettingsContext.Provider value={{ settings, setSetting }}>{children}</SettingsContext.Provider>;
};

15
src/types.d.ts vendored
View file

@ -1,12 +1,21 @@
type Theme = "dark" | "light" | "system"; type Theme = "dark" | "light" | "system";
interface Position { interface Position {
x: number; x: number;
y: number y: number;
}
interface Dimension {
width: number;
height: number;
} }
interface Block extends Position { interface Block extends Position {
name: string; name: string;
} }
type Tool = "hand" | "pencil" | "eraser"; type Tool = "hand" | "pencil" | "eraser";
interface Settings {
grid: boolean;
}