mirror of
https://github.com/Floriansylvain/ThatsMyWorld.git
synced 2026-08-19 11:43:16 +02:00
feat: basic chunk system
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 322 B |
+119
@@ -0,0 +1,119 @@
|
|||||||
|
import { InstancedMesh, Texture, Vector3 } from "three"
|
||||||
|
import Face, { Orientation } from "./face"
|
||||||
|
|
||||||
|
const FACES_OFFSETS: { [key: string]: Vector3 } = {
|
||||||
|
Up: new Vector3(0, 1, 0),
|
||||||
|
North: new Vector3(0, 0, 1),
|
||||||
|
South: new Vector3(0, 0, -1),
|
||||||
|
East: new Vector3(-1, 0, 0),
|
||||||
|
West: new Vector3(1, 0, 0),
|
||||||
|
Down: new Vector3(0, -1, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlockData {
|
||||||
|
position: Vector3
|
||||||
|
textureName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Chunk {
|
||||||
|
chunk: BlockData[]
|
||||||
|
chunkSet: Set<string>
|
||||||
|
radius: number
|
||||||
|
textures: { [name: string]: Texture[] }
|
||||||
|
faces: { [key: string]: Face[] }
|
||||||
|
|
||||||
|
constructor(radius: number, textures: { [name: string]: Texture[] }) {
|
||||||
|
this.chunk = []
|
||||||
|
this.chunkSet = new Set<string>()
|
||||||
|
this.radius = radius
|
||||||
|
this.textures = textures
|
||||||
|
this.faces = {}
|
||||||
|
this.generateChunk()
|
||||||
|
this.initializeFaces()
|
||||||
|
}
|
||||||
|
|
||||||
|
generateChunk() {
|
||||||
|
for (let i = 0; i < this.radius; i++) {
|
||||||
|
for (let j = 0; j < this.radius; j++) {
|
||||||
|
const max = Math.ceil(Math.sin(i / 30) * 10 + Math.cos(j / 30) * 10)
|
||||||
|
for (let k = -16; k <= max; k++) {
|
||||||
|
const position = new Vector3(i, k, j)
|
||||||
|
let textureName = "stone"
|
||||||
|
if (k === max) textureName = "grass"
|
||||||
|
else if (k > max - 6) textureName = "dirt"
|
||||||
|
this.chunk.push({ position, textureName })
|
||||||
|
this.chunkSet.add(position.toArray().toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeFaces() {
|
||||||
|
for (const textureName in this.textures) {
|
||||||
|
const textureFaces = this.textures[textureName].map((texture, index) => {
|
||||||
|
const orientation = ["Up", "North", "South", "East", "West", "Down"][
|
||||||
|
index
|
||||||
|
] as Orientation
|
||||||
|
return new Face(orientation, 0, texture)
|
||||||
|
})
|
||||||
|
this.faces[textureName] = textureFaces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterFaces(block: Vector3, textureName: string): Face[] {
|
||||||
|
return this.faces[textureName].filter((face) => {
|
||||||
|
const offset = FACES_OFFSETS[face.orientation]
|
||||||
|
const adjacentBlock = new Vector3(
|
||||||
|
block.x + offset.x,
|
||||||
|
block.y + offset.y,
|
||||||
|
block.z + offset.z
|
||||||
|
)
|
||||||
|
return !this.chunkSet.has(adjacentBlock.toArray().toString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
countVisibleFaces() {
|
||||||
|
const faceCounts: { [key: string]: { [key: string]: number } } = {}
|
||||||
|
|
||||||
|
this.chunk.forEach(({ position, textureName }) => {
|
||||||
|
if (!faceCounts[textureName]) {
|
||||||
|
faceCounts[textureName] = {
|
||||||
|
Up: 0,
|
||||||
|
North: 0,
|
||||||
|
South: 0,
|
||||||
|
East: 0,
|
||||||
|
West: 0,
|
||||||
|
Down: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.keys(FACES_OFFSETS).forEach((orientation) => {
|
||||||
|
const offset = FACES_OFFSETS[orientation]
|
||||||
|
const adjacentBlock = new Vector3(
|
||||||
|
position.x + offset.x,
|
||||||
|
position.y + offset.y,
|
||||||
|
position.z + offset.z
|
||||||
|
)
|
||||||
|
if (!this.chunkSet.has(adjacentBlock.toArray().toString())) {
|
||||||
|
faceCounts[textureName][orientation]++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const textureName in faceCounts) {
|
||||||
|
for (const orientation in faceCounts[textureName]) {
|
||||||
|
const face = this.faces[textureName].find(
|
||||||
|
(f) => f.orientation === orientation
|
||||||
|
)
|
||||||
|
if (!face?.instancedMesh) return
|
||||||
|
face.instancedMesh.count = faceCounts[textureName][orientation]
|
||||||
|
face.instancedMesh = new InstancedMesh(
|
||||||
|
face?.geometry,
|
||||||
|
face?.material,
|
||||||
|
faceCounts[textureName][orientation]
|
||||||
|
) // TODO dégueulasse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return faceCounts
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-105
@@ -1,10 +1,9 @@
|
|||||||
import "./style.css"
|
import "./style.css"
|
||||||
import * as THREE from "three"
|
import * as THREE from "three"
|
||||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js"
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js"
|
||||||
import Face from "./face"
|
import Chunk from "./chunk"
|
||||||
import Block from "./block"
|
import Block from "./block"
|
||||||
import TextureLoader from "./textureLoader"
|
import TextureLoader from "./textureLoader"
|
||||||
// import TextureLoader from "./textureLoader"
|
|
||||||
|
|
||||||
const scene = new THREE.Scene()
|
const scene = new THREE.Scene()
|
||||||
const camera = new THREE.PerspectiveCamera(
|
const camera = new THREE.PerspectiveCamera(
|
||||||
@@ -21,121 +20,33 @@ const controls = new OrbitControls(camera, renderer.domElement)
|
|||||||
controls.update()
|
controls.update()
|
||||||
document.body.appendChild(renderer.domElement)
|
document.body.appendChild(renderer.domElement)
|
||||||
|
|
||||||
let grassTextures = [] as THREE.Texture[]
|
let textures: { [name: string]: THREE.Texture[] } = {}
|
||||||
let dirtTextures = [] as THREE.Texture[]
|
|
||||||
|
|
||||||
async function loadTextures() {
|
async function loadTextures() {
|
||||||
const textureLoader = new TextureLoader(16, 16)
|
const textureLoader = new TextureLoader(16, 16)
|
||||||
grassTextures = await textureLoader.load("/grass.png")
|
textures["grass"] = await textureLoader.load("/grass.png")
|
||||||
dirtTextures = await textureLoader.load("/dirt.png")
|
textures["dirt"] = await textureLoader.load("/dirt.png")
|
||||||
// const debugTextures = await textureLoader.load("/debug.png")
|
textures["stone"] = await textureLoader.load("/stone.png")
|
||||||
onTextureLoaded()
|
onTexturesLoaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
// const gridHelper = new THREE.GridHelper(1000, 1000)
|
function onTexturesLoaded() {
|
||||||
// scene.add(gridHelper)
|
const radius = 128
|
||||||
|
const chunk = new Chunk(radius, textures)
|
||||||
|
|
||||||
// const axesHelper = new THREE.AxesHelper(500)
|
chunk.countVisibleFaces()
|
||||||
// scene.add(axesHelper)
|
|
||||||
|
|
||||||
const FACES_OFFSETS: { [key: string]: THREE.Vector3 } = {
|
|
||||||
Up: new THREE.Vector3(0, 1, 0),
|
|
||||||
North: new THREE.Vector3(0, 0, 1),
|
|
||||||
South: new THREE.Vector3(0, 0, -1),
|
|
||||||
East: new THREE.Vector3(-1, 0, 0),
|
|
||||||
West: new THREE.Vector3(1, 0, 0),
|
|
||||||
Down: new THREE.Vector3(0, -1, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterFaces(
|
|
||||||
faces: Face[],
|
|
||||||
block: THREE.Vector3,
|
|
||||||
chunkSet: Set<string>
|
|
||||||
): Face[] {
|
|
||||||
return faces.filter((face) => {
|
|
||||||
const offset = FACES_OFFSETS[face.orientation]
|
|
||||||
const adjacentBlock = new THREE.Vector3(
|
|
||||||
block.x + offset.x,
|
|
||||||
block.y + offset.y,
|
|
||||||
block.z + offset.z
|
|
||||||
)
|
|
||||||
return !chunkSet.has(adjacentBlock.toArray().toString())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function countVisibleFaces(
|
|
||||||
chunkSet: Set<string>,
|
|
||||||
chunk: THREE.Vector3[]
|
|
||||||
): { [key: string]: number } {
|
|
||||||
const faceCounts: { [key: string]: number } = {
|
|
||||||
Up: 0,
|
|
||||||
North: 0,
|
|
||||||
South: 0,
|
|
||||||
East: 0,
|
|
||||||
West: 0,
|
|
||||||
Down: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk.forEach((block) => {
|
|
||||||
Object.keys(FACES_OFFSETS).forEach((orientation) => {
|
|
||||||
const offset = FACES_OFFSETS[orientation]
|
|
||||||
const adjacentBlock = new THREE.Vector3(
|
|
||||||
block.x + offset.x,
|
|
||||||
block.y + offset.y,
|
|
||||||
block.z + offset.z
|
|
||||||
)
|
|
||||||
if (!chunkSet.has(adjacentBlock.toArray().toString())) {
|
|
||||||
faceCounts[orientation]++
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return faceCounts
|
|
||||||
}
|
|
||||||
|
|
||||||
function onTextureLoaded() {
|
|
||||||
const chunk = [] as THREE.Vector3[]
|
|
||||||
const chunkSet = new Set<string>()
|
|
||||||
const radius = 32
|
|
||||||
for (let i = 0; i < radius; i++) {
|
|
||||||
for (let j = 0; j < radius; j++) {
|
|
||||||
const max = Math.ceil(Math.sin(i / 30) * 10 + Math.cos(j / 30) * 10)
|
|
||||||
for (let k = -64; k < max; k++) {
|
|
||||||
const vec3 = new THREE.Vector3(i, k, j)
|
|
||||||
chunk.push(vec3)
|
|
||||||
chunkSet.add(vec3.toArray().toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const faceCounts = countVisibleFaces(chunkSet, chunk)
|
|
||||||
|
|
||||||
const grassFaces = [
|
|
||||||
new Face("Up", faceCounts.Up, grassTextures[0]),
|
|
||||||
new Face("North", faceCounts.North, grassTextures[1]),
|
|
||||||
new Face("South", faceCounts.South, grassTextures[2]),
|
|
||||||
new Face("East", faceCounts.East, grassTextures[3]),
|
|
||||||
new Face("West", faceCounts.West, grassTextures[4]),
|
|
||||||
new Face("Down", faceCounts.Down, grassTextures[5])
|
|
||||||
]
|
|
||||||
|
|
||||||
const dirtFaces = [
|
|
||||||
new Face("Up", faceCounts.Up, dirtTextures[0]),
|
|
||||||
new Face("North", faceCounts.North, dirtTextures[1]),
|
|
||||||
new Face("South", faceCounts.South, dirtTextures[2]),
|
|
||||||
new Face("East", faceCounts.East, dirtTextures[3]),
|
|
||||||
new Face("West", faceCounts.West, dirtTextures[4]),
|
|
||||||
new Face("Down", faceCounts.Down, dirtTextures[5])
|
|
||||||
]
|
|
||||||
|
|
||||||
const cubes = [] as Block[]
|
const cubes = [] as Block[]
|
||||||
chunk.forEach((block) => {
|
chunk.chunk.forEach(({ position, textureName }) => {
|
||||||
cubes.push(new Block(filterFaces(grassFaces, block, chunkSet), block))
|
const faces = chunk.filterFaces(position, textureName)
|
||||||
|
cubes.push(new Block(faces, position))
|
||||||
})
|
})
|
||||||
|
|
||||||
grassFaces.forEach((face) => {
|
Object.values(chunk.faces).forEach((faceArray) => {
|
||||||
|
faceArray.forEach((face) => {
|
||||||
if (face.instancedMesh) scene.add(face.instancedMesh)
|
if (face.instancedMesh) scene.add(face.instancedMesh)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
camera.position.x = 15
|
camera.position.x = 15
|
||||||
|
|||||||
Reference in New Issue
Block a user