feat: chunks working generation

This commit is contained in:
Florian Sylvain
2024-03-17 03:22:26 +01:00
parent 6d161ba2e9
commit ca5caae875
2 changed files with 62 additions and 52 deletions
+34 -30
View File
@@ -1,3 +1,4 @@
import { useEffect } from "react";
import { import {
ClampToEdgeWrapping, ClampToEdgeWrapping,
FrontSide, FrontSide,
@@ -8,45 +9,46 @@ import {
} from "three"; } from "three";
import { ImprovedNoise } from "three/examples/jsm/Addons.js"; import { ImprovedNoise } from "three/examples/jsm/Addons.js";
const canvas = document.createElement("canvas", { is: "canvas" });
const grassTexture = new TextureLoader().load("./texture_grass.jpg");
grassTexture.wrapS = grassTexture.wrapT = RepeatWrapping;
grassTexture.repeat.set(100, 100);
const SIZE = 100;
const SCALE = 1.5;
const AMPLITUDE = 30;
const OVERLAP = 0.5;
const GEOMETRY = 50;
const CHUNK_SIZE = 100;
const ADJUSTED_GEOMETRY = GEOMETRY + OVERLAP * 2;
const ADJUSTED_SIZE = SIZE + OVERLAP * 2;
const ADJUSTED_SCALE = SIZE / SCALE;
export function Chunk(props: { position: Vector2; seed: number }): JSX.Element { export function Chunk(props: { position: Vector2; seed: number }): JSX.Element {
const size = 100;
const scale = 1.5;
const amplitude = 30;
const overlap = 0.5;
const geometry = 50;
const chunkSize = 100;
const adjustedGeometry = geometry + overlap * 2;
const noise = (x: number, y: number): number => { const noise = (x: number, y: number): number => {
const noise = new ImprovedNoise(); const noise = new ImprovedNoise();
return noise.noise(x, y, props.seed); return noise.noise(x, y, props.seed);
}; };
const canvas = document.createElement("canvas"); canvas.width = canvas.height = ADJUSTED_SIZE;
canvas.width = size + overlap * 2; const context = canvas.getContext("2d", { willReadFrequently: true });
canvas.height = size + overlap * 2;
const context = canvas.getContext("2d");
if (!context) throw new Error("Canvas context not found"); if (!context) throw new Error("Canvas context not found");
const offsetX = -overlap + props.position.x; const offsetX = -OVERLAP + props.position.x;
const offsetY = -overlap + props.position.y; const offsetY = -OVERLAP + props.position.y;
const imageData = context.getImageData( const imageData = context.getImageData(0, 0, ADJUSTED_SIZE, ADJUSTED_SIZE);
0,
0,
size + overlap * 2,
size + overlap * 2
);
const data = imageData.data; const data = imageData.data;
for (let x = 0; x < size + overlap * 2; x++) { for (let x = 0; x < ADJUSTED_SIZE; x++) {
for (let y = 0; y < size + overlap * 2; y++) { for (let y = 0; y < ADJUSTED_SIZE; y++) {
const n = const n =
noise((x + offsetX) / (size / scale), (y + offsetY) / (size / scale)) * noise((x + offsetX) / ADJUSTED_SCALE, (y + offsetY) / ADJUSTED_SCALE) *
127 + 127 +
127; 127;
const id = (x + y * (size + overlap * 2)) * 4; const id = (x + y * ADJUSTED_SIZE) * 4;
data[id] = n; data[id] = n;
data[id + 1] = n; data[id + 1] = n;
data[id + 2] = n; data[id + 2] = n;
@@ -57,9 +59,11 @@ export function Chunk(props: { position: Vector2; seed: number }): JSX.Element {
const displacementMap = new TextureLoader().load(canvas.toDataURL()); const displacementMap = new TextureLoader().load(canvas.toDataURL());
displacementMap.wrapS = displacementMap.wrapT = ClampToEdgeWrapping; displacementMap.wrapS = displacementMap.wrapT = ClampToEdgeWrapping;
const grassTexture = new TextureLoader().load("./texture_grass.jpg"); useEffect(() => {
grassTexture.wrapS = grassTexture.wrapT = RepeatWrapping; return () => {
grassTexture.repeat.set(100, 100); displacementMap.dispose();
};
}, [displacementMap]);
return ( return (
<group position={new Vector3(props.position.x, 0, props.position.y)}> <group position={new Vector3(props.position.x, 0, props.position.y)}>
@@ -71,14 +75,14 @@ export function Chunk(props: { position: Vector2; seed: number }): JSX.Element {
> >
<planeGeometry <planeGeometry
attach="geometry" attach="geometry"
args={[chunkSize, chunkSize, adjustedGeometry, adjustedGeometry]} args={[CHUNK_SIZE, CHUNK_SIZE, ADJUSTED_GEOMETRY, ADJUSTED_GEOMETRY]}
></planeGeometry> ></planeGeometry>
<meshStandardMaterial <meshStandardMaterial
toneMapped={false} toneMapped={false}
attach="material" attach="material"
map={grassTexture} map={grassTexture}
displacementMap={displacementMap} displacementMap={displacementMap}
displacementScale={amplitude} displacementScale={AMPLITUDE}
shadowSide={FrontSide} shadowSide={FrontSide}
/> />
</mesh> </mesh>
+28 -22
View File
@@ -6,42 +6,48 @@ import { Chunk } from "./Chunk";
export function ChunkGenerator(): JSX.Element { export function ChunkGenerator(): JSX.Element {
const { playerPosition } = useContext(GameContext); const { playerPosition } = useContext(GameContext);
const [chunks, setChunks] = useState([] as JSX.Element[]);
const [lastPlayerPosition] = useState(new Vector2(0, 0)); const [lastPlayerPosition] = useState(new Vector2(0, 0));
const [chunks, setChunks] = useState([] as JSX.Element[]);
const chunkPosVec2 = new Vector2(); const chunkPosVec2 = new Vector2();
function generateChunk(x: number, y: number) { const isChunkAlreadyGenerated = (x: number, y: number) =>
setChunks([ chunks.some((chunk) => chunk.key === `${x}-${y}`);
<Chunk
key={`${x}-${y}`}
position={chunkPosVec2.set(x * 100, y * 100)}
seed={897624}
/>,
]);
}
useEffect(() => { function generateNewChunks(playerX: number, playerY: number) {
generateChunk(0, 0); const newChunks = [];
}, []); for (let x = -2; x <= 2; x++) {
for (let y = -2; y <= 2; y++) {
if (isChunkAlreadyGenerated(playerX + x, playerY + y)) continue;
newChunks.push(
<Chunk
key={`${playerX + x}-${playerY + y}`}
position={chunkPosVec2
.clone()
.set((playerX + x) * 100, (playerY + y) * 100)}
seed={0.25386}
/>
);
}
}
setChunks([...chunks, ...newChunks]);
}
useFrame(() => { useFrame(() => {
const playerX = Math.floor(playerPosition.x / 100 + 0.5); const playerX = Math.floor(playerPosition.x / 100 + 0.5);
const playerY = Math.floor(playerPosition.z / 100 + 0.5); const playerY = Math.floor(playerPosition.z / 100 + 0.5);
// generateChunk(playerX, playerY); if (lastPlayerPosition.x === playerX && lastPlayerPosition.y === playerY)
// console.log("player", playerX, playerY); return;
// // every time the player moves to a new chunk, generate 3x3 chunks around the player generateNewChunks(playerX, playerY);
// for (let x = -1; x <= 1; x++) {
// for (let y = -1; y <= 1; y++) {
// generateChunk(playerX + x, playerY + y);
// }
// }
lastPlayerPosition.set(playerX, playerY); lastPlayerPosition.set(playerX, playerY);
}); });
useEffect(() => {
generateNewChunks(0, 0);
}, []);
return <>{chunks}</>; return <>{chunks}</>;
} }