Merge pull request #1 from bhushan6/brick-anchor

Brick anchor
This commit is contained in:
Bhushan Wagh
2023-04-29 21:57:53 +05:30
committed by GitHub
12 changed files with 412 additions and 76 deletions
+165 -8
View File
@@ -8,6 +8,8 @@
"name": "lego-builder",
"version": "0.1.0",
"dependencies": {
"@liveblocks/client": "^1.0.1",
"@liveblocks/zustand": "^1.0.1",
"@react-three/drei": "^9.57.0",
"@react-three/fiber": "^8.11.6",
"@testing-library/jest-dom": "^5.16.5",
@@ -18,7 +20,9 @@
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"three": "^0.150.1",
"web-vitals": "^2.1.4"
"use-keyboard-shortcut": "^1.1.6",
"web-vitals": "^2.1.4",
"zustand": "^4.3.6"
}
},
"node_modules/@adobe/css-tools": {
@@ -3015,6 +3019,31 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"node_modules/@liveblocks/client": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-1.0.1.tgz",
"integrity": "sha512-lU+A+v1bbvI6H/pOjo93G8LAf1HYM2yqZc4D/LCI6b/JiZT/3bMrJ2X8Or4Yc5DVmIK3T5Rumk2za9bSdcjBQQ==",
"dependencies": {
"@liveblocks/core": "1.0.1"
}
},
"node_modules/@liveblocks/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-1.0.1.tgz",
"integrity": "sha512-IwtVtp1ogmVJLW7KSmkI7J+8+pPg0FMNdFV71oCPAugmlZRxUer3MvdIBOW4ULFBgoBJOzAmcjWRDFsl3K7ADA=="
},
"node_modules/@liveblocks/zustand": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-1.0.1.tgz",
"integrity": "sha512-cAXMS5r9wRa+NFAnJ4IusV/azRxcVB9zWtc99WSCXNq2uhxwlrsG6z+kDNR8LemoDHweSVkpb/c3Hi8FDFnv6Q==",
"dependencies": {
"@liveblocks/client": "1.0.1",
"@liveblocks/core": "1.0.1"
},
"peerDependencies": {
"zustand": "^4.1.3"
}
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -3290,6 +3319,22 @@
}
}
},
"node_modules/@react-three/drei/node_modules/zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"react": ">=16.8"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
}
},
"node_modules/@react-three/fiber": {
"version": "8.11.7",
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.11.7.tgz",
@@ -3339,6 +3384,22 @@
"loose-envify": "^1.1.0"
}
},
"node_modules/@react-three/fiber/node_modules/zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"react": ">=16.8"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -12520,6 +12581,22 @@
"react": "^16.8 || ^17.0"
}
},
"node_modules/leva/node_modules/zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"react": ">=16.8"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
}
},
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -17292,6 +17369,23 @@
"requires-port": "^1.0.0"
}
},
"node_modules/use-keyboard-shortcut": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.6.tgz",
"integrity": "sha512-tOKjR7eKXQIfAgFMwhelpWSRTrwE1GaB8CE/47ohtcVCKxUdn7UbfNNhiigTkATpUVoPu+5tRPbHrwjIBgTYoQ==",
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -18335,16 +18429,23 @@
"integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA=="
},
"node_modules/zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.6.tgz",
"integrity": "sha512-6J5zDxjxLE+yukC2XZWf/IyWVKnXT9b9HUv09VJ/bwGCpKNcaTqp7Ws28Xr8jnbvnZcdRaidztAPsXFBIqufiw==",
"dependencies": {
"use-sync-external-store": "1.2.0"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"immer": ">=9.0",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"immer": {
"optional": true
},
"react": {
"optional": true
}
@@ -20379,6 +20480,28 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"@liveblocks/client": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-1.0.1.tgz",
"integrity": "sha512-lU+A+v1bbvI6H/pOjo93G8LAf1HYM2yqZc4D/LCI6b/JiZT/3bMrJ2X8Or4Yc5DVmIK3T5Rumk2za9bSdcjBQQ==",
"requires": {
"@liveblocks/core": "1.0.1"
}
},
"@liveblocks/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-1.0.1.tgz",
"integrity": "sha512-IwtVtp1ogmVJLW7KSmkI7J+8+pPg0FMNdFV71oCPAugmlZRxUer3MvdIBOW4ULFBgoBJOzAmcjWRDFsl3K7ADA=="
},
"@liveblocks/zustand": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-1.0.1.tgz",
"integrity": "sha512-cAXMS5r9wRa+NFAnJ4IusV/azRxcVB9zWtc99WSCXNq2uhxwlrsG6z+kDNR8LemoDHweSVkpb/c3Hi8FDFnv6Q==",
"requires": {
"@liveblocks/client": "1.0.1",
"@liveblocks/core": "1.0.1"
}
},
"@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -20570,6 +20693,14 @@
"troika-three-text": "^0.47.1",
"utility-types": "^3.10.0",
"zustand": "^3.5.13"
},
"dependencies": {
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"requires": {}
}
}
},
"@react-three/fiber": {
@@ -20594,6 +20725,12 @@
"requires": {
"loose-envify": "^1.1.0"
}
},
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"requires": {}
}
}
},
@@ -27356,6 +27493,12 @@
}
}
}
},
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"requires": {}
}
}
},
@@ -30667,6 +30810,18 @@
"requires-port": "^1.0.0"
}
},
"use-keyboard-shortcut": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.6.tgz",
"integrity": "sha512-tOKjR7eKXQIfAgFMwhelpWSRTrwE1GaB8CE/47ohtcVCKxUdn7UbfNNhiigTkATpUVoPu+5tRPbHrwjIBgTYoQ==",
"requires": {}
},
"use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"requires": {}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -31481,10 +31636,12 @@
"integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA=="
},
"zustand": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"requires": {}
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.6.tgz",
"integrity": "sha512-6J5zDxjxLE+yukC2XZWf/IyWVKnXT9b9HUv09VJ/bwGCpKNcaTqp7Ws28Xr8jnbvnZcdRaidztAPsXFBIqufiw==",
"requires": {
"use-sync-external-store": "1.2.0"
}
}
}
}
+8 -4
View File
@@ -3,17 +3,21 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@liveblocks/client": "^1.0.1",
"@liveblocks/zustand": "^1.0.1",
"@react-three/drei": "^9.57.0",
"@react-three/fiber": "^8.11.6",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"leva": "^0.9.34",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4",
"@react-three/drei": "^9.57.0",
"@react-three/fiber": "^8.11.6",
"three": "^0.150.1",
"leva": "^0.9.34"
"use-keyboard-shortcut": "^1.1.6",
"web-vitals": "^2.1.4",
"zustand": "^4.3.6"
},
"scripts": {
"start": "react-scripts start",
+12 -4
View File
@@ -5,9 +5,9 @@ import { Suspense } from "react";
import { LinearToneMapping } from "three";
import { InfoPanel, Scene } from "./components";
function App() {
const LegoRoom = () => {
return (
<div className="App">
<>
<Canvas
gl={{
alpha: false,
@@ -20,8 +20,8 @@ function App() {
near: 0.1,
far: 20000,
}}
colorManagement={true}
shadowMap={true} // highlight-line
colorManagement
shadows
dpr={Math.min(2, window.devicePixelRatio)}
>
<Suspense fallback={null}>
@@ -30,6 +30,14 @@ function App() {
</Suspense>
</Canvas>
<InfoPanel />
</>
);
};
function App() {
return (
<div className="App">
<LegoRoom />
</div>
);
}
+42 -17
View File
@@ -12,8 +12,8 @@ export const Brick = ({
color = "#ff0000",
dimensions = { x: 1, z: 1 },
rotation = 0,
translation = 0,
addBrick = () => {},
translation = { x: 0, z: 0 },
onClick = () => {},
bricksBoundBox = { current: [] },
uID = "",
mouseMove = () => {},
@@ -54,28 +54,53 @@ export const Brick = ({
boundingBoxRef.push({ uID, brickBoundingBox });
return () => {
boundingBoxRef.filter((brick) => brick.uID !== uID);
boundingBoxRef.filter((brick) => {
return brick.uID !== uID;
});
};
}, [uID, bricksBoundBox]);
}, []);
const compansateX =
dimensions.x % 2 === 0 ? dimensions.x / 2 : (dimensions.x - 1) / 2;
const compansateZ =
dimensions.z % 2 === 0 ? dimensions.z / 2 : (dimensions.z - 1) / 2;
const offsetX =
Math.sign(translation.x) < 0
? Math.max(translation.x, -compansateX)
: Math.min(translation.x, compansateX);
const offsetZ =
Math.sign(translation.z) < 0
? Math.max(translation.z, -compansateZ)
: Math.min(translation.z, compansateZ);
return (
<>
<mesh
<group
ref={brickRef}
onClick={addBrick}
position={[position.x, Math.abs(position.y), position.z]}
rotation={[0, rotation, 0]}
castShadow={true}
receiveShadow={true}
geometry={brickGeometry}
onPointerMove={mouseMove}
position={[position.x, Math.abs(position.y), position.z]}
>
<meshStandardMaterial
color={CSSToHex(color)}
metalness={0.4}
roughness={0.5}
/>
</mesh>
<mesh
castShadow
receiveShadow
position={[
(offsetX * width) / dimensions.x,
0.5,
(offsetZ * depth) / dimensions.z,
]}
onClick={onClick}
geometry={brickGeometry}
onPointerMove={mouseMove}
>
<meshStandardMaterial
color={CSSToHex(color)}
metalness={0.4}
roughness={0.5}
/>
</mesh>
</group>
</>
);
};
+32 -8
View File
@@ -1,4 +1,3 @@
import { useThree } from "@react-three/fiber";
import React, { forwardRef, useMemo } from "react";
import { Vector3 } from "three";
import { getMeasurementsFromDimensions, base } from "../utils";
@@ -12,7 +11,7 @@ export const BrickCursor = forwardRef(
},
dimensions = { x: 1, z: 1 },
rotation = 0,
translation = 0,
translation = { x: 0, z: 0 },
},
ref
) => {
@@ -37,18 +36,43 @@ export const BrickCursor = forwardRef(
);
}, [intersect, height, rotation, width, depth]);
const compansateX =
dimensions.x % 2 === 0 ? dimensions.x / 2 : (dimensions.x - 1) / 2;
const compansateZ =
dimensions.z % 2 === 0 ? dimensions.z / 2 : (dimensions.z - 1) / 2;
const offsetX =
Math.sign(translation.x) < 0
? Math.max(translation.x, -compansateX)
: Math.min(translation.x, compansateX);
const offsetZ =
Math.sign(translation.z) < 0
? Math.max(translation.z, -compansateZ)
: Math.min(translation.z, compansateZ);
return (
<>
<mesh
<group
ref={ref}
position={[position.x, Math.abs(position.y), position.z]}
rotation={[0, rotation, 0]}
castShadow={true}
receiveShadow={true}
>
<boxGeometry args={[width, height, depth]} />
<meshBasicMaterial color={"black"} transparent={true} opacity={0.3} />
</mesh>
<mesh
position={[
(offsetX * width) / dimensions.x,
0,
(offsetZ * width) / dimensions.z,
]}
>
<boxGeometry args={[width, height, depth]} />
<meshBasicMaterial
color={"black"}
transparent={true}
opacity={0.3}
/>
</mesh>
</group>
</>
);
}
+3 -1
View File
@@ -13,7 +13,9 @@ export const InfoPanel = () => {
width: "200px",
}}
>
Use panel on right top corner to customize the Lego Bricks Properties
Use panel on right top corner to customize the Lego Bricks Properties Use
<br />
"AWSD" to chnage the anchor points of bricks
</div>
);
};
+37 -6
View File
@@ -1,17 +1,48 @@
import React from "react";
// import { useControls } from "leva";
export const Lights = () => {
// const [{ left, bottom, far, near, zoom }, set] = useControls(() => ({
// left: {
// value: 1,
// min: 1,
// max: 500,
// step: 1,
// },
// bottom: {
// value: 1,
// min: 1,
// max: 500,
// step: 1,
// },
// far: {
// value: 1,
// min: 1,
// max: 50000,
// step: 1,
// },
// near: {
// value: 0.01,
// min: 0.01,
// max: 20,
// step: 0.1,
// },
// zoom: {
// value: 0,
// min: 0,
// max: 2,
// step: 0.1,
// },
// }));
return (
<>
<spotLight
position={[-1000, 1500, -500]}
intensity={0.9}
castShadow={true}
shadowBias={-0.0000022}
penumbra={0.5}
decay={2}
shadowMapHeight={4096}
shadowMapWidth={4096}
penumbra={1}
shadow-mapSize={[512, 512]}
castShadow
/>
<ambientLight intensity={0.4} />
</>
+56 -25
View File
@@ -1,7 +1,12 @@
import React, { useEffect, useState, useRef } from "react";
import { Shadow, Brick, BrickCursor, Lights, Workspace } from ".";
import React, { useEffect, useRef, useState } from "react";
import { Brick, BrickCursor, Lights, Workspace } from ".";
import { Vector3, Box3 } from "three";
import { uID, getMeasurementsFromDimensions, base } from "../utils";
import {
uID,
getMeasurementsFromDimensions,
base,
useAnchorShorcuts,
} from "../utils";
import { useControls } from "leva";
let t;
@@ -13,22 +18,38 @@ export const Scene = () => {
const brickCursorRef = useRef();
const { width, depth, rotate, color } = useControls({
width: {
value: 1,
min: 1,
max: 5,
step: 1,
},
depth: {
value: 1,
min: 1,
max: 5,
step: 1,
},
rotate: false,
color: "#f00",
});
const [{ width, depth, rotate, color, anchorX, anchorZ }, set] = useControls(
() => ({
width: {
value: 1,
min: 1,
max: 5,
step: 1,
},
depth: {
value: 1,
min: 1,
max: 5,
step: 1,
},
rotate: false,
color: "#ff0",
anchorX: {
value: 0,
min: -2,
max: 2,
step: 1,
},
anchorZ: {
value: 0,
min: -2,
max: 2,
step: 1,
},
})
);
useAnchorShorcuts(anchorX, anchorZ, set);
const addBrick = (e) => {
e.stopPropagation();
@@ -53,7 +74,7 @@ export const Scene = () => {
const collision =
boundingBoxOfBrickToBeAdded.intersectsBox(brickBoundingBox);
console.log(collision);
console.log(collision, brickBoundingBox, boundingBoxOfBrickToBeAdded);
if (collision) {
const dx = Math.abs(
@@ -82,16 +103,17 @@ export const Scene = () => {
dimensions: { x: width, z: depth },
rotation: rotate ? Math.PI / 2 : 0,
color: color,
translation: { x: anchorX, z: anchorZ },
};
setBricks((prevState) => [...prevState, brickData]);
setBricks((prevBricks) => [...prevBricks, brickData]);
}
} else {
isDrag.current = false;
}
};
const mouseMove = (e) => {
const setBrickCursorPosition = (e) => {
e.stopPropagation();
if (!brickCursorRef.current) return;
@@ -120,6 +142,14 @@ export const Scene = () => {
);
};
const onClick = (e) => {
addBrick(e);
};
const mouseMove = (e) => {
setBrickCursorPosition(e);
};
const isDrag = useRef(false);
useEffect(() => {
@@ -152,22 +182,23 @@ export const Scene = () => {
key={b.uID}
dimensions={b.dimensions}
intersect={b.intersect}
addBrick={addBrick}
onClick={onClick}
rotation={b.rotation}
bricksBoundBox={bricksBoundBox}
uID={b.uID}
mouseMove={mouseMove}
color={b.color}
translation={b.translation}
/>
);
})}
<Shadow />
<Lights />
<Workspace addBrick={addBrick} mouseMove={mouseMove} />
<Workspace onClick={onClick} mouseMove={mouseMove} />
<BrickCursor
ref={brickCursorRef}
rotation={rotate ? Math.PI / 2 : 0}
dimensions={{ x: width, z: depth }}
translation={{ x: anchorX, z: anchorZ }}
/>
</>
);
+11 -3
View File
@@ -1,17 +1,25 @@
import React from "react";
export const Workspace = ({ addBrick = () => {}, mouseMove = () => {} }) => {
export const Workspace = ({ onClick = () => {}, mouseMove = () => {} }) => {
return (
<>
<gridHelper onClick={addBrick} args={[1500, 60]} />
<gridHelper args={[1500, 60]} />
<mesh
rotation={[-Math.PI / 2, 0, 0]}
onClick={addBrick}
onClick={onClick}
onPointerMove={mouseMove}
>
<planeGeometry args={[1500, 1500]} />
<meshBasicMaterial visible={false} />
</mesh>
{/* <mesh
rotation={[-0.5 * Math.PI, 0, 0]}
position={[0, -1, 0]}
receiveShadow
>
<planeGeometry args={[3000, 3000, 1, 1]} />
<shadowMaterial color="red" />
</mesh> */}
</>
);
};
View File
+45
View File
@@ -0,0 +1,45 @@
import useKeyboardShortcut from "use-keyboard-shortcut";
export const useAnchorShorcuts = (anchorX, anchorZ, set) => {
const anchorXPlus = () => {
set({ anchorX: anchorX + 1 });
};
const anchorXMinus = () => {
set({ anchorX: anchorX - 1 });
};
const anchorZPlus = () => {
set({ anchorZ: anchorZ - 1 });
};
const anchorZMinus = () => {
set({ anchorZ: anchorZ + 1 });
};
useKeyboardShortcut(["D"], anchorXPlus, {
overrideSystem: true,
ignoreInputFields: false,
repeatOnHold: false,
});
useKeyboardShortcut(["A"], anchorXMinus, {
overrideSystem: true,
ignoreInputFields: false,
repeatOnHold: false,
});
useKeyboardShortcut(["W"], anchorZPlus, {
overrideSystem: true,
ignoreInputFields: false,
repeatOnHold: false,
});
useKeyboardShortcut(["S"], anchorZMinus, {
overrideSystem: true,
ignoreInputFields: false,
repeatOnHold: false,
});
return null;
};
+1
View File
@@ -1,2 +1,3 @@
export * from "./helpers";
export * from "./constants";
export * from "./hooks";