<script src = "three.js"></script>
<script src = "perlin.js"></script>
<script src = "PointerLockControls.js"></script>
<script src = "stats.js"></script>
<script type="text/javascript">
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(0);
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x00ffff);
scene.fog = new THREE.Fog(0x00ffff, 10, 20000);
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){
this.x = x;
this.y = y;
this.z = z;
this.placed = placed;
}
// 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 = 50
var renderDistance = 35;
var chunkSize = 10;
camera.position.x = 0;
camera.position.z = 0;
camera.position.y = 0;
var loader = new THREE.TextureLoader();
var materialArray = [
new THREE.MeshBasicMaterial({map : loader.load("texture/side.jpg")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/side.jpg")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/top.jpg")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/bottom.jpg")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/side.jpg")}),
new THREE.MeshBasicMaterial({map : loader.load("texture/side.jpg")}),
];
let leaves_box = new THREE.BoxGeometry(25, 25, 25)
let leaves_front_material = new THREE.MeshBasicMaterial({map : loader.load("texture/leaves.png"),side:THREE.DoubleSide})
let leaves2_box = new THREE.BoxGeometry(27, 27, 27)
let leaves_front2_material = new THREE.MeshBasicMaterial({map : loader.load("texture/leaves.png"),transparent:true})
let leaves3_box = new THREE.BoxGeometry(29, 29, 29)
let leaves_front3_material = new THREE.MeshBasicMaterial({map : loader.load("texture/leaves.png"),transparent:true})
let leaves_mesh = {}
let trunk_box = new THREE.BoxGeometry(5, 40, 5)
let trunk_material = new THREE.MeshBasicMaterial({map : loader.load("texture/trunk.png"),side:THREE.DoubleSide})
let trunk_mesh={}
var blockBox = new THREE.BoxGeometry(5, 15, 5)
var instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, renderDistance * renderDistance * chunkSize * chunkSize);
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
+ noise.perlin2(xoff / 100, zoff / 100) * amplitude / 5 * 100
+ noise.perlin2(xoff / 100000, zoff / 100000) * amplitude / 5 * 10000) * 5;
chunk.push(new Block(x * 5, v, z * 5));
if(Math.random()<0.0005){
id=Math.random()
trunk_mesh[id]={}
trunk_mesh[id].c = new THREE.Mesh(trunk_box,trunk_material)
trunk_mesh[id].c.position.set(x * 5, v + 20, z * 5)
scene.add(trunk_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves_box,leaves_front_material)
leaves_mesh[id].c.position.set(x * 5, v + 50, z * 5)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves2_box,leaves_front2_material)
leaves_mesh[id].c.position.set(x * 5, v + 50, z * 5)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves3_box,leaves_front3_material)
leaves_mesh[id].c.position.set(x * 5, v + 50, z * 5)
scene.add(leaves_mesh[id].c)
}
let matrix = new THREE.Matrix4().makeTranslation(
x * 5,
v,
z * 5
);
instancedChunk.setMatrixAt(count, matrix);
count++;
}
}
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!!!
}
document.addEventListener("keydown", function(e){
keys.push(e.key);
if(e.key == controlOptions.jump && canJump == true){
ySpeed = -0.9;
canJump = false;
}
});
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;
});
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];
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({x : x, y : y, z : z});
}
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) + 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);
count++;
}
}
scene.add(instancedChunk);
}
}
});
controls.addEventListener("lock", function(){
});
controls.addEventListener("unlock", function(){
});
var movingSpeed = 0.5;
var ySpeed = 0;
var acc = 0.065;
function update(){
if(keys.includes(controlOptions.forward)){
controls.moveForward(movingSpeed);
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
if(camera.position.x <= chunks[i][j].x + 2.5 && camera.position.x >= chunks[i][j].x - 2.5 && camera.position.z <= chunks[i][j].z + 2.5 && camera.position.z >= chunks[i][j].z - 2.5){
if(camera.position.y == chunks[i][j].y - 2.5){
controls.moveForward(-1 * movingSpeed);
}
}
}
}
}
if(keys.includes(controlOptions.left)){
controls.moveRight(-1 * movingSpeed);
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
if(camera.position.x <= chunks[i][j].x + 2.5 && camera.position.x >= chunks[i][j].x - 2.5 && camera.position.z <= chunks[i][j].z + 2.5 && camera.position.z >= chunks[i][j].z - 2.5){
if(camera.position.y == chunks[i][j].y - 2.5){
controls.moveRight(movingSpeed);
}
}
}
}
}
if(keys.includes(controlOptions.backward)){
controls.moveForward(-1 * movingSpeed);
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
if(camera.position.x <= chunks[i][j].x + 2.5 && camera.position.x >= chunks[i][j].x - 2.5 && camera.position.z <= chunks[i][j].z + 2.5 && camera.position.z >= chunks[i][j].z - 2.5){
if(camera.position.y == chunks[i][j].y - 2.5){
controls.moveForward(movingSpeed);
}
}
}
}
}
if(keys.includes(controlOptions.right)){
controls.moveRight(movingSpeed);
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
if(camera.position.x <= chunks[i][j].x + 2.5 && camera.position.x >= chunks[i][j].x - 2.5 && camera.position.z <= chunks[i][j].z + 2.5 && camera.position.z >= chunks[i][j].z - 2.5){
if(camera.position.y == chunks[i][j].y - 2.5){
controls.moveRight(-1 * movingSpeed);
}
}
}
}
}
camera.position.y = camera.position.y - ySpeed;
ySpeed = ySpeed + acc;
for(var i = 0; i < chunks.length; i++){
for(var j = 0; j < chunks[i].length; j++){
if(camera.position.x <= chunks[i][j].x + 2.5 && camera.position.x >= chunks[i][j].x - 2.5 && camera.position.z <= chunks[i][j].z + 2.5 && camera.position.z >= chunks[i][j].z - 2.5){
if(camera.position.y <= chunks[i][j].y + 15 && camera.position.y >= chunks[i][j].y){
camera.position.y = chunks[i][j].y + 15;
ySpeed = 0;
canJump = true;
break;
}
}
}
}
// INFINITE TERRAIN GENERATION PART!
var worldSize = chunkSize * renderDistance * 5;
var ratio = 0.4;
if(camera.position.z < lowestZBlock() + (worldSize * ratio)){ // 20 is 4 blocks
try{
for(let i1 in trunk_mesh){
if(trunk_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(trunk_mesh.c)
delete trunk_mesh[i1].c
}
}
for(let i1 in leaves_mesh){
if(leaves_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(leaves_mesh.c)
delete leaves_mesh[i1].c
}
}
}catch(e){}
/*
[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
+ noise.perlin2(xoff / 100, zoff / 100) * amplitude / 5 * 100
+ noise.perlin2(xoff / 100000, zoff / 100000) * amplitude / 5 * 10000) * 5;
// 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 && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
chunk.push(new Block(x, v, z));
if(Math.random()<0.0005){
id=Math.random()
trunk_mesh[id]={}
trunk_mesh[id].c = new THREE.Mesh(trunk_box,trunk_material)
trunk_mesh[id].c.position.set(x, v + 16, z)
scene.add(trunk_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves_box,leaves_front_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves2_box,leaves_front2_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves3_box,leaves_front3_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
}
}
// Check if there is also a placed block 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));
}
}
}
}
newChunks.splice(i * renderDistance, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize) + 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);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.z > highestZBlock() - (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
try{
for(let i1 in trunk_mesh){
if(trunk_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(trunk_mesh.c)
delete trunk_mesh[i1].c
}
}
for(let i1 in leaves_mesh){
if(leaves_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(leaves_mesh.c)
delete leaves_mesh[i1].c
}
}
}catch(e){}
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
+ noise.perlin2(xoff / 100, zoff / 100) * amplitude / 5 * 100
+ noise.perlin2(xoff / 100000, zoff / 100000) * amplitude / 5 * 10000) * 5;
// 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 && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
chunk.push(new Block(x, v, z));
if(Math.random()<0.0005){
id=Math.random()
trunk_mesh[id]={}
trunk_mesh[id].c = new THREE.Mesh(trunk_box,trunk_material)
trunk_mesh[id].c.position.set(x, v + 16, z)
scene.add(trunk_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves_box,leaves_front_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves2_box,leaves_front2_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves3_box,leaves_front3_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
}
}
// Check if there is also a placed block 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));
}
}
}
}
newChunks.splice(((i + 1) * renderDistance) - 1, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize) + 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);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.x > highestXBlock() - (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
try{
for(let i1 in trunk_mesh){
if(trunk_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(trunk_mesh.c)
delete trunk_mesh[i1].c
}
}
for(let i1 in leaves_mesh){
if(leaves_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(leaves_mesh.c)
delete leaves_mesh[i1].c
}
}
}catch(e){}
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
+ noise.perlin2(xoff / 100, zoff / 100) * amplitude / 5 * 100
+ noise.perlin2(xoff / 100000, zoff / 100000) * amplitude / 5 * 10000) * 5;
// 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 && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
chunk.push(new Block(x, v, z));
if(Math.random()<0.0005){
id=Math.random()
trunk_mesh[id]={}
trunk_mesh[id].c = new THREE.Mesh(trunk_box,trunk_material)
trunk_mesh[id].c.position.set(x, v + 16, z)
scene.add(trunk_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves_box,leaves_front_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves2_box,leaves_front2_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves3_box,leaves_front3_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
}
}
// Check if there is also a placed block 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));
}
}
}
}
newChunks.splice(chunks.length - (renderDistance - i), 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize) + 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);
count++;
}
}
scene.add(instancedChunk);
}
if(camera.position.x < lowestXBlock() + (worldSize * ratio)){ // 20 is 4 blocks
/*
[0], [3], [6],
[1], [x], [7],
[2], [5], [8],
*/
try{
for(let i1 in trunk_mesh){
if(trunk_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(trunk_mesh.c)
delete trunk_mesh[i1].c
}
}
for(let i1 in leaves_mesh){
if(leaves_mesh[i1].c.position.distanceTo(camera.position)>chunkSize*renderDistance){
scene.remove(leaves_mesh.c)
delete leaves_mesh[i1].c
}
}
}catch(e){}
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
+ noise.perlin2(xoff / 100, zoff / 100) * amplitude / 5 * 100
+ noise.perlin2(xoff / 100000, zoff / 100000) * amplitude / 5 * 10000) * 5;
// 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 && brokenBlocks[d].z == z){
blockIsDestroyed = true;
break;
}
}
if(!blockIsDestroyed){
chunk.push(new Block(x, v, z));
if(Math.random()<0.0005){
id=Math.random()
trunk_mesh[id]={}
trunk_mesh[id].c = new THREE.Mesh(trunk_box,trunk_material)
trunk_mesh[id].c.position.set(x, v + 16, z)
scene.add(trunk_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves_box,leaves_front_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves2_box,leaves_front2_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
id=Math.random()
leaves_mesh[id]={}
leaves_mesh[id].c = new THREE.Mesh(leaves3_box,leaves_front3_material)
leaves_mesh[id].c.position.set(x, v + 44, z)
scene.add(leaves_mesh[id].c)
}
}
// Check if there is also a placed block 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));
}
}
}
}
newChunks.splice(i, 0, chunk);
}
chunks = newChunks;
scene.remove(instancedChunk);
instancedChunk = new THREE.InstancedMesh(blockBox, materialArray, (renderDistance * renderDistance * chunkSize * chunkSize) + 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);
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();
});
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>
Minecraft.js by HritikRC
body {
margin : 0;
}
Depends on what you mean by “make shaders” - most of the time, you can use ShaderMaterial, RawShaderMaterial, CustomShaderMaterial, or just replacing parts of shader code of built-in materials in Material.onBeforeCompile.
1 Like