mirror of
https://github.com/Floriansylvain/generic-threejs-game.git
synced 2026-08-19 19:53:23 +02:00
feat: chunks working generation
This commit is contained in:
+34
-30
@@ -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>
|
||||||
|
|||||||
@@ -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}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user