Hello I have this code:
<!DOCTYPE html>
<html>
<head>
<title>3D Minecraft</title>
<style type="text/css">
body {
margin : 0;
}
#cursor {
position : absolute;
width : 3%;
}
</style>
</head>
<body>
<script src = "three.js"></script>
<script src = "perlin.js"></script>
<script src = "PointerLockControls.js"></script>
<script src = "stats.js"></script>
<img src = "cursor.png" id = "cursor">
<script type="text/javascript">
// Cursor
var cursor = document.getElementById("cursor");
cursor.style.left = ((0.5 * window.innerWidth) - (0.5 * cursor.width)).toString() + "px";
cursor.style.top = ((0.5 * window.innerHeight) - (0.5 * cursor.height)).toString() + "px";
// Performance Stats
var stats = new Stats();
stats.showPanel(0); // 0:fps, 1:ms, 2:mb, 3+:custom
document.body.appendChild(stats.dom);
function animate(){
stats.begin();
// monitored code goes between this called functions
stats.end();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
noise.seed(Math.random());
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x00ffff);
scene.fog = new THREE.Fog(0x00ffff, 10, 650);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
/*
var groundBox = new THREE.BoxBufferGeometry(25, 1, 50);
var groundMesh = new THREE.MeshBasicMaterial({color : 0x00ff00});
var ground = new THREE.Mesh(groundBox, groundMesh);
scene.add(ground);
ground.position.y = -5;
// Creating the border lines for ground
var edges = new THREE.EdgesGeometry(groundBox);
var line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({color : 0x000000}));
scene.add(line);
line.position.y = -5;
*/
var faces = [
{ // left
dir: [ -5, 0, 0, "left"],
},
{ // right
dir: [ 5, 0, 0, "right"],
},
{ // bottom
dir: [ 0, -5, 0, "bottom"],
},
{ // top
dir: [ 0, 5, 0, "top"],
},
{ // back
dir: [ 0, 0, -5, "back"],
},
{ // front
dir: [ 0, 0, 5, "front"],
},
];
function Block(x, y, z, placed, blockType){
this.x = x;
this.y = y;
this.z = z;
this.placed = placed;
this.blockType = blockType;
}
var blocks = {
grass : {
color : new THREE.Color("rgb(0, 200, 0)"),
name : "grass",
},
dirt : {
color : new THREE.Color("rgb(115, 90, 53)"),
name : "dirt",
},
cobblestone : {
color : new THREE.Color("rgb(90, 90, 90)"),
name : "cobblestone"
}
};
// var axesHelper = new THREE.AxesHelper( 5 );
// scene.add( axesHelper );
/*
var blocks = [];
var xoff = 0;
var zoff = 0;
var inc = 0.05;
var amplitude = 50;
for(var x = 0; x < 20; x++){
xoff = 0;
for(var z = 0; z < 20; z++){
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
blocks.push(new Block(x * 5, v, z * 5));
xoff = xoff + inc;
}
zoff = zoff + inc;
}
*/
var chunks = [];
var xoff = 0;
var zoff = 0;
var inc = 0.05;
var amplitude = 30 + (Math.random() * 70);
var renderDistance = 5;
var chunkSize = 10;
camera.position.x = renderDistance * chunkSize / 2 * 5;
camera.position.z = renderDistance * chunkSize / 2 * 5;
camera.position.y = 50;
var loader = new THREE.TextureLoader();
var materialArray = [
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/texture.png")}),
];
var depth = 5; // keeps track of the depth of the world (in terms of blocks)
var minWorldY = -250; // the minimum y coordinate of a block
var blockBox = new THREE.BoxGeometry(5, 5, 5)
var instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, renderDistance * renderDistance * chunkSize * chunkSize * depth);
var count = 0;
for(var i = 0; i < renderDistance; i++){
for(j = 0; j < renderDistance; j++){
var chunk = [];
for(var x = i * chunkSize; x < (i * chunkSize) + chunkSize; x++){
for(var z = j * chunkSize; z < (j * chunkSize) + chunkSize; z++){
xoff = inc * x;
zoff = inc * z;
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
for(var d = 0; d < depth; d++){
if(v - (d * 5) < minWorldY){
continue;
}
let matrix = new THREE.Matrix4().makeTranslation(
x * 5,
v - (d * 5),
z * 5
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
var blockType = null;
if(d == 0){
color = blocks.grass.color;
blockType = blocks.grass.name;
} else if(d == 1 || d == 2 || d == 3){
color = blocks.dirt.color;
blockType = blocks.dirt.name;
} else if(d > 3){
color = blocks.cobblestone.color;
blockType = blocks.cobblestone.name;
}
instancedChunk.setColorAt(count, color);
count++;
chunk.push(new Block(x * 5, v - (d * 5), z * 5, false, blockType));
}
}
}
chunks.push(chunk);
}
}
scene.add(instancedChunk);
var keys = [];
var canJump = true;
var controlOptions = {
forward : "w",
backward : "s",
right : "d",
left : "a",
jump : " ", // " " = space
placeBlock : "q"
};
var placedBlocks = [];
var chunkMap = [];
for(var x = 0; x < renderDistance; x++){
for(var z = 0; z < renderDistance; z++){
chunkMap.push({x : x, z : z});
}
}
function identifyChunk(x, z){
var lowestX = lowestXBlock();
var lowestZ = lowestZBlock();
var difX = x - lowestX;
var difZ = z - lowestZ;
var divX = Math.floor(difX / (chunkSize * 5));
var divZ = Math.floor(difZ / (chunkSize * 5));
var index = undefined;
for(var i = 0; i < chunkMap.length; i++){
if(chunkMap[i].x == divX && chunkMap[i].z == divZ){
index = i;
break;
}
}
return index; // Identified the chunks!!!
}
var start = 0;
var sprint = false;
document.addEventListener("keydown", function(e){
if(e.key == "w") {
var elapsed = new Date().getTime();
if(elapsed - start <= 300){
sprint = true;
}
start = elapsed;
}
keys.push(e.key);
if(e.key == controlOptions.jump && canJump == true){
ySpeed = -1;
canJump = false;
}
if(e.key == controlOptions.placeBlock){
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
pointer.x = (0.5) * 2 - 1;
pointer.y = -1 * (0.5) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
var intersection = raycaster.intersectObject(instancedChunk);
if(intersection[0] != undefined && intersection[0].distance < 40){
console.log(intersection[0]);
var materialIndex = intersection[0].face.materialIndex;
var position = intersection[0].point; // object with x, y and z coords
var x = 0;
var y = 0;
var z = 0;
const inc = 2.5;
switch(materialIndex){
case 0: // right
x = position.x + inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 1: // left
x = position.x - inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 2: // top
x = Math.round(position.x / 5) * 5;
y = position.y + inc;
z = Math.round(position.z / 5) * 5;
break;
case 3: // bottom
x = Math.round(position.x / 5) * 5;
y = position.y - inc;
z = Math.round(position.z / 5) * 5;
break;
case 4: // front
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z + inc;
break;
case 5: // back
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z - inc;
break;
}
y = Math.round(y); // sometimes, y is for some reason e.g 4.999999999999
if(y > minWorldY){
var blockToBePlaced = "cobblestone";
var b = new Block(x, y, z, true, blockToBePlaced);
if(!intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d)){
chunks[identifyChunk(x, z)].push(new Block(x, y, z, true, blockToBePlaced));
placedBlocks.push(b);
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
}
}
}
});
document.addEventListener("keyup", function(e){
var newArr = [];
for(var i = 0; i < keys.length; i++){
if(keys[i] != e.key){
newArr.push(keys[i]);
}
}
keys = newArr;
if(!keys.includes("w")){
sprint = false;
}
});
var controls = new THREE.PointerLockControls(camera, document.body);
var brokenBlocks = [];
document.body.addEventListener("click", function(){
controls.lock();
// Breaking blocks
if(controls.isLocked){
// Shooting a ray
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
pointer.x = (0.5) * 2 - 1;
pointer.y = -1 * (0.5) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
var intersection = raycaster.intersectObject(instancedChunk);
if(intersection[0] != undefined && intersection[0].distance < 40){
// finding x, y, z positions of that
console.log(intersection[0].point);
var materialIndex = intersection[0].face.materialIndex;
var position = intersection[0].point; // object with x, y and z coords
var x = 0;
var y = 0;
var z = 0;
const inc = 2.5;
switch(materialIndex){ // finding x, y, z positions of block
case 0: // right
x = position.x - inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 1: // left
x = position.x + inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 2: // top
x = Math.round(position.x / 5) * 5;
y = position.y - inc;
z = Math.round(position.z / 5) * 5;
break;
case 3: // bottom
x = Math.round(position.x / 5) * 5;
y = position.y + inc;
z = Math.round(position.z / 5) * 5;
break;
case 4: // front
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z - inc;
break;
case 5: // back
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z + inc;
break;
}
// Find block with those x, y, z positions
// More efficient by finding it inside it's chunk
var index1 = identifyChunk(x, z);
var chunk = chunks[index1];
y = Math.round(y); // sometimes, y is for some reason e.g 4.999999999999
for(var i = 0; i < chunk.length; i++){
if(chunk[i].x == x && chunk[i].y == y && chunk[i].z == z){
// Found the block!
if(chunk[i].placed){
// find the placedBlock and remove it
for(var j = 0; j < placedBlocks.length; j++){
if(placedBlocks[j].x == x && placedBlocks[j].y == y && placedBlocks[j].z == z){
placedBlocks.splice(j, 1);
break;
}
}
} else { // if it is a normal block
brokenBlocks.push(new Block(x, y, z, false, chunk[i].blockType));
}
chunks[index1].splice(i, 1); // block is removed from chunks variable
break;
}
}
// update chunks, array.splice(index, 1);
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
}
});
controls.addEventListener("lock", function(){
});
controls.addEventListener("unlock", function(){
keys = [];
});
var movingSpeed = 0.5;
var ySpeed = 0;
var acc = 0.065;
var player = {
w : 0.6, // width
h : 8, // height
d : 0.5, // depth
x : camera.position.x,
y : camera.position.y,
z : camera.position.z,
forward : function(speed){
controls.moveForward(speed);
this.updatePosition();
},
backward : function(speed){
controls.moveForward(-1 * speed);
this.updatePosition();
},
right : function(speed){
controls.moveRight(speed);
this.updatePosition();
},
left : function(speed){
controls.moveRight(-1 * speed);
this.updatePosition();
},
updatePosition : function(){
this.x = camera.position.x;
this.y = camera.position.y - (this.h / 2);
this.z = camera.position.z;
}
};
function intersect(x1, y1, z1, w1, h1, d1, x2, y2, z2, w2, h2, d2){
var a = {
minX : x1 - (w1/2),
maxX : x1 + (w1/2),
minZ : z1 - (d1/2),
maxZ : z1 + (d1/2),
minY : y1 - (h1/2),
maxY : y1 + (h1/2),
};
var b = {
minX : x2 - (w2/2),
maxX : x2 + (w2/2),
minZ : z2 - (d2/2),
maxZ : z2 + (d2/2),
minY : y2 - (h2/2),
maxY : y2 + (h2/2),
};
return (a.minX <= b.maxX && a.maxX >= b.minX) &&
(a.minY <= b.maxY && a.maxY >= b.minY) &&
(a.minZ <= b.maxZ && a.maxZ >= b.minZ);
}
var deceleration = 1.35;
var forback = 0; // 1 = forward, -1 = backward
var rightleft = 0; // 1 = right, -1 = left
var sprintSpeedInc = 1.6; // 30% faster than walking
function update(){
player.updatePosition();
if(keys.includes(controlOptions.forward)){
player.forward(movingSpeed * (sprint ? sprintSpeedInc : 1));
forback = 1 * movingSpeed;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && (b.y - 2.5 < player.y + (player.h / 2) && b.y + 2.5 > player.y - (player.h / 2))){
player.backward((movingSpeed * (sprint ? sprintSpeedInc : 1)));
forback = 0;
rightleft = 0;
sprint = false;
}
}
}
}
if(keys.includes(controlOptions.backward)){
player.backward(movingSpeed * (sprint ? sprintSpeedInc : 1));
forback = -1 * movingSpeed;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && (b.y - 2.5 < player.y + (player.h / 2) && b.y + 2.5 > player.y - (player.h / 2))){
player.forward(movingSpeed * (sprint ? sprintSpeedInc : 1));
forback = 0;
rightleft = 0;
sprint = false;
}
}
}
}
if(keys.includes(controlOptions.right)){
player.right(movingSpeed * (sprint ? sprintSpeedInc : 1));
rightleft = 1 * movingSpeed;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && (b.y - 2.5 < player.y + (player.h / 2) && b.y + 2.5 > player.y - (player.h / 2))){
player.left(movingSpeed * (sprint ? sprintSpeedInc : 1));
forback = 0;
rightleft = 0;
sprint = false;
}
}
}
}
if(keys.includes(controlOptions.left)){
player.left(movingSpeed * (sprint ? sprintSpeedInc : 1));
rightleft = -1 * movingSpeed;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && (b.y - 2.5 < player.y + (player.h / 2) && b.y + 2.5 > player.y - (player.h / 2))){
player.right(movingSpeed * (sprint ? sprintSpeedInc : 1));
forback = 0;
rightleft = 0;
sprint = false;
}
}
}
}
// Decceleration part
if(!keys.includes(controlOptions.forward) && !keys.includes(controlOptions.backward) && !keys.includes(controlOptions.right) && !keys.includes(controlOptions.left)){
forback /= deceleration;
rightleft /= deceleration;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && (b.y - 2.5 < player.y + (player.h / 2) && b.y + 2.5 > player.y - (player.h / 2))){
var br = true;
forback /= -deceleration;
rightleft /= -deceleration;
sprint = false;
break;
}
}
if(br){
break;
}
}
player.forward(forback * (sprint ? sprintSpeedInc : 1));
player.right(rightleft * (sprint ? sprintSpeedInc : 1));
}
camera.position.y = camera.position.y - ySpeed;
ySpeed = ySpeed + acc;
// Not falling through a block or above a block (above collision)
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
var b = chunks[i][j];
var c = intersect(b.x, b.y + 10, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d);
if(c && camera.position.y <= chunks[i][j].y + 2.5 + player.h && camera.position.y >= chunks[i][j].y){
camera.position.y = chunks[i][j].y + 2.5 + player.h;
ySpeed = 0;
canJump = true;
}
var c = intersect(b.x, b.y, b.z, 5, 5, 5, player.x, player.y, player.z, player.w, player.h, player.d); // this one doesn't have a + 10 in the b.y
if(c && camera.position.y >= chunks[i][j].y - 2.5 && camera.position.y <= chunks[i][j].y){
ySpeed = 0.5;
}
}
}
// INFINITE TERRAIN GENERATION PART!
var worldSize = chunkSize * renderDistance * 5;
var ratio = 0.4;
if(camera.position.z < lowestZBlock() + (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
var newChunks = [];
for(var i = 0; i < chunks.length; i++){
if((i + 1) % renderDistance != 0){
newChunks.push(chunks[i]);
}
}
// add blocks
var lowestX = lowestXBlock();
var lowestZ = lowestZBlock();
for(var i = 0; i < renderDistance; i++){
var chunk = [];
for(var x = lowestX + (i * chunkSize * 5); x < lowestX + (i * chunkSize * 5) + (chunkSize * 5); x = x + 5){
for(var z = lowestZ - (chunkSize * 5); z < lowestZ; z = z + 5){
xoff = inc * x / 5;
zoff = inc * z / 5;
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
for(var e = 0; e < depth; e++){
if(v - (e * 5) < minWorldY){
continue;
}
// Try to find a broken block in that position
var blockIsDestroyed = false;
for(var d = 0; d < brokenBlocks.length; d++){
if(brokenBlocks[d].x == x && brokenBlocks[d].y == v - (e * 5) && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
var blockType = null;
if(e == 0){
blockType = blocks.grass.name;
} else if(e == 1 || e == 2 || e == 3){
blockType = blocks.dirt.name;
} else if(e > 3){
blockType = blocks.cobblestone.name;
}
chunk.push(new Block(x, v - (e * 5), z, false, blockType));
}
}
// Check if there is also placed blocks there
for(var b = 0; b < placedBlocks.length; b++){
if(placedBlocks[b].x == x && placedBlocks[b].z == z){
chunk.push(new Block(placedBlocks[b].x, placedBlocks[b].y, placedBlocks[b].z, true, placedBlocks[b].blockType));
}
}
}
}
newChunks.splice(i * renderDistance, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.z > highestZBlock() - (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
var newChunks = [];
for(var i = 0; i < chunks.length; i++){
if(i % renderDistance != 0){
newChunks.push(chunks[i]);
}
}
// add blocks
var lowestX = lowestXBlock();
var highestZ = highestZBlock();
for(var i = 0; i < renderDistance; i++){
var chunk = [];
for(var x = lowestX + (i * chunkSize * 5); x < lowestX + (i * chunkSize * 5) + (chunkSize * 5); x = x + 5){
for(var z = highestZ + 5; z < (highestZ + 5) + (chunkSize * 5); z = z + 5){
xoff = inc * x / 5;
zoff = inc * z / 5;
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
for(var e = 0; e < depth; e++){
if(v - (e * 5) < minWorldY){
continue;
}
// Try to find a broken block in that position
var blockIsDestroyed = false;
for(var d = 0; d < brokenBlocks.length; d++){
if(brokenBlocks[d].x == x && brokenBlocks[d].y == v - (e * 5) && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
var blockType = null;
if(e == 0){
blockType = blocks.grass.name;
} else if(e == 1 || e == 2 || e == 3){
blockType = blocks.dirt.name;
} else if(e > 3){
blockType = blocks.cobblestone.name;
}
chunk.push(new Block(x, v - (e * 5), z, false, blockType));
}
}
// Check if there is also placed blocks there
for(var b = 0; b < placedBlocks.length; b++){
if(placedBlocks[b].x == x && placedBlocks[b].z == z){
chunk.push(new Block(placedBlocks[b].x, placedBlocks[b].y, placedBlocks[b].z, true, placedBlocks[b].blockType));
}
}
}
}
newChunks.splice(((i + 1) * renderDistance) - 1, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.x > highestXBlock() - (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
var newChunks = [];
for(var i = renderDistance; i < chunks.length; i++){
newChunks.push(chunks[i]);
}
// add blocks
var highestX = highestXBlock();
var lowestZ = lowestZBlock();
for(var i = 0; i < renderDistance; i++){
var chunk = [];
for(var z = lowestZ + (i * chunkSize * 5); z < lowestZ + (i * chunkSize * 5) + (chunkSize * 5); z = z + 5){
for(var x = highestX + 5; x < highestX + 5 + (chunkSize * 5); x = x + 5){
xoff = inc * x / 5;
zoff = inc * z / 5;
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
for(var e = 0; e < depth; e++){
if(v - (e * 5) < minWorldY){
continue;
}
// Try to find a broken block in that position
var blockIsDestroyed = false;
for(var d = 0; d < brokenBlocks.length; d++){
if(brokenBlocks[d].x == x && brokenBlocks[d].y == v - (e * 5) && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
var blockType = null;
if(e == 0){
blockType = blocks.grass.name;
} else if(e == 1 || e == 2 || e == 3){
blockType = blocks.dirt.name;
} else if(e > 3){
blockType = blocks.cobblestone.name;
}
chunk.push(new Block(x, v - (e * 5), z, false, blockType));
}
}
// Check if there is also placed blocks there
for(var b = 0; b < placedBlocks.length; b++){
if(placedBlocks[b].x == x && placedBlocks[b].z == z){
chunk.push(new Block(placedBlocks[b].x, placedBlocks[b].y, placedBlocks[b].z, true, placedBlocks[b].blockType));
}
}
}
}
newChunks.splice(chunks.length - (renderDistance - i), 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.x < lowestXBlock() + (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
var newChunks = [];
for(var i = 0; i < chunks.length - renderDistance; i++){
newChunks.push(chunks[i]);
}
// add blocks
var lowestX = lowestXBlock();
var lowestZ = lowestZBlock();
for(var i = 0; i < renderDistance; i++){
var chunk = [];
for(var z = lowestZ + (i * chunkSize * 5); z < lowestZ + (i * chunkSize * 5) + (chunkSize * 5); z = z + 5){
for(var x = lowestX - (chunkSize * 5); x < lowestX; x = x + 5){
xoff = inc * x / 5;
zoff = inc * z / 5;
var v = Math.round(noise.perlin2(xoff, zoff) * amplitude / 5) * 5;
for(var e = 0; e < depth; e++){
if(v - (e * 5) < minWorldY){
continue;
}
// Try to find a broken block in that position
var blockIsDestroyed = false;
for(var d = 0; d < brokenBlocks.length; d++){
if(brokenBlocks[d].x == x && brokenBlocks[d].y == v - (e * 5) && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
var blockType = null;
if(e == 0){
blockType = blocks.grass.name;
} else if(e == 1 || e == 2 || e == 3){
blockType = blocks.dirt.name;
} else if(e > 3){
blockType = blocks.cobblestone.name;
}
chunk.push(new Block(x, v - (e * 5), z, false, blockType));
}
}
// Check if there is also placed blocks there
for(var b = 0; b < placedBlocks.length; b++){
if(placedBlocks[b].x == x && placedBlocks[b].z == z){
chunk.push(new Block(placedBlocks[b].x, placedBlocks[b].y, placedBlocks[b].z, true, placedBlocks[b].blockType));
}
}
}
}
newChunks.splice(i, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize * depth) + placedBlocks.length);
var count = 0;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
let matrix = new THREE.Matrix4().makeTranslation(
chunks[i][j].x,
chunks[i][j].y,
chunks[i][j].z
);
instancedChunk.setMatrixAt(count, matrix);
var color = null;
if(chunks[i][j].blockType == "grass"){
color = blocks.grass.color;
} else if(chunks[i][j].blockType == "dirt"){
color = blocks.dirt.color;
} else if(chunks[i][j].blockType == "cobblestone"){
color = blocks.cobblestone.color;
}
instancedChunk.setColorAt(count, color);
count++;
}
}
scene.add(instancedChunk);
}
}
function lowestXBlock(){
var xPosArray = [];
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
xPosArray.push(chunks[i][j].x);
}
}
return Math.min.apply(null, xPosArray);
}
function highestXBlock(){
var xPosArray = [];
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
xPosArray.push(chunks[i][j].x);
}
}
return Math.max.apply(null, xPosArray);
}
function lowestZBlock(){
var zPosArray = [];
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
zPosArray.push(chunks[i][j].z);
}
}
return Math.min.apply(null, zPosArray);
}
function highestZBlock(){
var zPosArray = [];
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
zPosArray.push(chunks[i][j].z);
}
}
return Math.max.apply(null, zPosArray);
}
// Resize Window
window.addEventListener("resize", function(){
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
cursor.style.left = ((0.5 * window.innerWidth) - (0.5 * cursor.width)).toString() + "px";
cursor.style.top = ((0.5 * window.innerHeight) - (0.5 * cursor.height)).toString() + "px";
});
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
pointer.x = (0.5) * 2 - 1;
pointer.y = -1 * (0.5) * 2 + 1;
var plane;
function render(){
raycaster.setFromCamera(pointer, camera);
var intersection = raycaster.intersectObject(instancedChunk);
if(intersection[0] != undefined && intersection[0].distance < 40){
//console.log(intersection[0]);
if(!scene.children.includes(plane)){
var planeG = new THREE.PlaneGeometry(5, 5);
var planeM = new THREE.MeshBasicMaterial({color : 0xffffff, side : THREE.DoubleSide});
planeM.transparent = true;
planeM.opacity = 0.5;
plane = new THREE.Mesh(planeG, planeM);
scene.add(plane);
} else {
plane.visible = true;
var materialIndex = intersection[0].face.materialIndex;
var position = intersection[0].point; // object with x, y and z coords
var x = 0;
var y = 0;
var z = 0;
const inc = 0.1;
switch(materialIndex){
case 0: // right
plane.rotation.x = 0;
plane.rotation.y = (Math.PI / 2);
plane.rotation.z = 0;
x = position.x + inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 1: // left
plane.rotation.x = 0;
plane.rotation.y = (Math.PI / 2);
plane.rotation.z = 0;
x = position.x - inc;
y = Math.round(position.y / 5) * 5;
z = Math.round(position.z / 5) * 5;
break;
case 2: // top
plane.rotation.x = (Math.PI / 2);
plane.rotation.y = 0;
plane.rotation.z = 0;
x = Math.round(position.x / 5) * 5;
y = position.y + inc;
z = Math.round(position.z / 5) * 5;
break;
case 3: // bottom
plane.rotation.x = (Math.PI / 2);
plane.rotation.y = 0;
plane.rotation.z = 0;
x = Math.round(position.x / 5) * 5;
y = position.y - inc;
z = Math.round(position.z / 5) * 5;
break;
case 4: // front
plane.rotation.x = 0;
plane.rotation.y = 0;
plane.rotation.z = 0;
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z + inc;
break;
case 5: // back
plane.rotation.x = 0;
plane.rotation.y = 0;
plane.rotation.z = 0;
x = Math.round(position.x / 5) * 5;
y = Math.round(position.y / 5) * 5;
z = position.z - inc;
break;
}
plane.position.x = x;
plane.position.y = y;
plane.position.z = z;
}
} else {
if(plane){
plane.visible = false;
}
}
renderer.render(scene, camera);
}
function GameLoop(){
requestAnimationFrame(GameLoop);
update();
render();
}
GameLoop();
</script>
</body>
</html>
And this is generation me this terrain:
And my question is:
If there is a function to change the color of an specific block of the chunk called setColorAt()
, there is another function which could be used to change the material array of the block to another material array in a specific block of the chunk? And… how to implement that and get my game with the new textures? Thanks for helping anyway.