From 4be09f8d4504018a13b33587a1f3bfde919eaa5d Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Fri, 17 Dec 2021 15:33:33 -0800 Subject: [PATCH] Add destroying blocks --- index.js | 18 ++++++++-- world.js | 105 +++++++++++++++++++++++++++++++++---------------------- 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/index.js b/index.js index a412f42..559f455 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ import { loadTexture, makeProgram } from "./gl"; -import { blockLookup, BlockType, generateMissingChunks, makeWorld, updateWorldGeometry } from './world'; +import { blockLookup, BlockType, createChunkFace, generateMissingChunks, makeWorld, updateWorldGeometry } from './world'; import * as se3 from './se3'; import { makeBufferFromFaces, makeFace } from "./geometry"; @@ -591,8 +591,18 @@ async function main() { }; } - canvas.onclick = e => { + const canvasClickHandler = e => { canvas.requestPointerLock(); + canvas.onclick = null; + const clickListener = e => { + switch(e.button) { + case 0: // left click + destroySelectedBlock(params); + break; + case 2: // right click + break; + } + }; const keyListener = e => { if (e.type === 'keydown') { params.keys.add(e.code); @@ -617,16 +627,20 @@ async function main() { if (document.pointerLockElement === canvas) { return; } + document.removeEventListener('pointerdown', clickListener); document.removeEventListener('pointerlockchange', changeListener); document.removeEventListener('pointermove', moveListener); document.removeEventListener('keydown', keyListener); document.removeEventListener('keyup', keyListener); + canvas.onclick = canvasClickHandler; }; + document.addEventListener('pointerdown', clickListener); document.addEventListener('pointerlockchange', changeListener); document.addEventListener('pointermove', moveListener); document.addEventListener('keydown', keyListener); document.addEventListener('keyup', keyListener); }; + canvas.onclick = canvasClickHandler; requestAnimationFrame(time => tick(time, gl, params)); } diff --git a/world.js b/world.js index c405c1e..50fc4d3 100644 --- a/world.js +++ b/world.js @@ -111,17 +111,47 @@ export function blockLookup(world, x, y, z) { const j = Math.floor(midx - chunkj * 16); const k = Math.floor(midy); + const blockIndex = 256 * (16*i + j) + k; + return { - type: chunk.data[256 * (16*i + j) + k], + type: chunk.data[blockIndex], centerPosition: [ Math.floor(midx), k, Math.floor(midz), ], + chunk, + blockIndex, }; } -function makeChunkBuffer(gl, data, z0, x0, blockLookup) { +function faceTexture(type, dir) { + switch (type) { + case BlockType.GRASS: + switch (dir) { + case '+y': return [0, 15]; + case '-y': return [2, 15]; + default: return [1, 15]; + } + case BlockType.DIRT: return [2, 15]; + case BlockType.STONE: return [3, 15]; + default: return [0, 0]; + } +} + +function faceCenter(blockCenter, dir) { + const [x, y, z] = blockCenter; + switch (dir) { + case '+x': return [x + 0.5, y, z]; + case '-x': return [x - 0.5, y, z]; + case '+y': return [x, y + 0.5, z]; + case '-y': return [x, y - 0.5, z]; + case '+z': return [x, y, z + 0.5]; + case '-z': return [x, y, z - 0.5]; + } +} + +function makeFaceList(data, chunkz, chunkx, blockLookup) { const lookup = (i, j, k) => { if (i < 0 || j < 0 || i > 15 || j > 15) { return blockLookup(i, j, k); @@ -131,13 +161,14 @@ function makeChunkBuffer(gl, data, z0, x0, blockLookup) { } return data[256*(16*i + j) + k]; }; - const sideNeighbors = (i, j, k) => - [ - { block: lookup(i - 1, j, k), dir: '-z', faceCenter: [x0 + j, k, z0 + i - 0.5] }, - { block: lookup(i + 1, j, k), dir: '+z', faceCenter: [x0 + j, k, z0 + i + 0.5] }, - { block: lookup(i, j - 1, k), dir: '-x', faceCenter: [x0 + j - 0.5, k, z0 + i] }, - { block: lookup(i, j + 1, k), dir: '+x', faceCenter: [x0 + j + 0.5, k, z0 + i] }, - ]; + const neighbors = (i, j, k) => [ + { block: lookup(i - 1, j, k), dir: '-z', faceCenter: [chunkx + j, k, chunkz + i - 0.5] }, + { block: lookup(i + 1, j, k), dir: '+z', faceCenter: [chunkx + j, k, chunkz + i + 0.5] }, + { block: lookup(i, j - 1, k), dir: '-x', faceCenter: [chunkx + j - 0.5, k, chunkz + i] }, + { block: lookup(i, j + 1, k), dir: '+x', faceCenter: [chunkx + j + 0.5, k, chunkz + i] }, + { block: lookup(i, j, k - 1), dir: '-y', faceCenter: [chunkx + j, k - 0.5, chunkz + i] }, + { block: lookup(i, j, k + 1), dir: '+y', faceCenter: [chunkx + j, k + 0.5, chunkz + i] }, + ]; const faces = []; @@ -145,37 +176,20 @@ function makeChunkBuffer(gl, data, z0, x0, blockLookup) { for (let j = 0; j < 16; j++) { let bi = i * 16 * 256 + j * 256; for (let k = 0; k < 256; k++, bi++) { - const upTexture = (() => { - switch (data[bi - 1]) { - case BlockType.GRASS: return [0, 15]; - case BlockType.DIRT: return [2, 15]; - case BlockType.STONE: return [3, 15]; - } - })(); - - if (data[bi] == BlockType.AIR) { - faces.push(makeFace('+y', upTexture, [x0 + j, k - 0.5, z0 + i])); - break; + if (data[bi] === BlockType.AIR) { + continue; } - - const sideTexture = (() => { - switch (data[bi]) { - case BlockType.GRASS: return [1, 15]; - case BlockType.DIRT: return [2, 15]; - case BlockType.STONE: return [3, 15]; - } - })(); - - for (let {block, dir, faceCenter} of sideNeighbors(i, j, k)) { - if (block === BlockType.AIR) { - faces.push(makeFace(dir, sideTexture, faceCenter)); - } + for (const {block, dir, faceCenter} of neighbors(i, j, k).filter(({block}) => block === BlockType.AIR)) { + faces.push({ + blockIndex: bi, + face: makeFace(dir, faceTexture(data[bi], dir), faceCenter), + }); } } } } - return makeBufferFromFaces(gl, faces); + return faces; } // - data <-- need to generate the first time, update when m&p @@ -251,17 +265,22 @@ function invalidateChunkGeometry(world, i, j) { delete chunk.buffer; } +export function createChunkFace(block, dir) { + return { + blockIndex: block.blockIndex, + face: makeFace(dir, faceTexture(block.type, dir), faceCenter(block.centerPosition, dir)), + }; +} + /** Generates geometry for all visible chunks. */ export function updateWorldGeometry(gl, world, z, x, timeLimit = 10000) { const ic = Math.floor(z / 16); const jc = Math.floor(x / 16); - const blockIndex = (i, j, k) => 256 * (i*16 +j) + k; - const start = performance.now(); // k. Now, generate buffers for all chunks - for (let radius = 0; radius < 8; radius++) { + for (let radius = 1; radius < 8; radius++) { for (let i = ic - radius; i < ic + radius; i++) { for (let j = jc - radius; j < jc + radius; j++) { const chunk = world.chunkMap.get(i, j); @@ -270,11 +289,15 @@ export function updateWorldGeometry(gl, world, z, x, timeLimit = 10000) { continue; } - const chunkz = 16 * i; - const chunkx = 16 * j; - const lookup = (i, j, k) => blockLookup(world, j + chunkx, k, i + chunkz).type; + if(chunk.faces === undefined) { + const chunkz = 16 * i; + const chunkx = 16 * j; + const lookup = (i, j, k) => blockLookup(world, j + chunkx, k, i + chunkz).type; - chunk.buffer = makeChunkBuffer(gl, chunk.data, chunk.position.z, chunk.position.x, lookup); + chunk.faces = makeFaceList(chunk.data, chunk.position.z, chunk.position.x, lookup); + } + + chunk.buffer = makeBufferFromFaces(gl, chunk.faces.map(f => f.face)); // throttle this for fluidity if (performance.now() - start > timeLimit) {