//==============================================================================// Welcome to the Infinite world with only grounds !//==============================================================================// This program was made by Nathan Bonnard.// In this world, you can generate an infinite world ! // But this isn't really infinite, it would be impossible, // the world do a simple loop when the player reach the border. Like in real life !// This is a little version of the real infinite world that you can find aswell on the enhanced page//------------------------------ TWEAKER BOX ------------------------------//const squaresize =7;// The world is like a infinite grid of square. squaresize is the size of a squarevar MOVESPEED =7;// Speed of the playervar viewDistance =2;// determinate the maximum distance to see ground (viewDistance * squaresize * groundMultiplier)var groundMultiplier =551;// The world is divided by zone (grounds) that size groundMultiplier*squaresizevar worldSize =13;// dimension of the world, it is not really infinite but big and can loop. There is worldSize * worldSize Grounds //------------------------------ END OF TWEAKER BOX ------------------------------//var newviewDistance = viewDistance;// letiables to re-generate the world with new letiables var newGroundMultiplier = groundMultiplier;var newworldSize = worldSize;const MAXPOS =4000;const startRadiusConst = MAXPOS *0.5;// distance from centre to start the camera atconst maxRadiusConst = MAXPOS *5;// maximum distance from camera we will render things const SKYCOLOR =0x6495ED;const LIGHTCOLOR =0xffffff;//used to manage the click and give back control to the user when you click on a button/text box //and don't want to enter into first person modevar HUDEVENT =false;var mouse;// vector2 : position of the mouse on the screen
threehandler.MAXCAMERAPOS = MAXPOS *10;// allow camera go far away
threeworld.drawCameraControls =false;
AB.clockTick =20;// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps =1000000;// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep =50;// Take screenshot on this step. (All resources should have finished loading.) Default 50./**
* A linear interpolator for hexadecimal colors
* @param {Int} a
* @param {Int} b
* @param {Number} amount
* @example
* // returns 0x7F7F7F
* lerpColor(0x000000, 0xffffff, 0.5)
* @returns {Int}
*/function lerpColor(a, b, amount){
let ah = a;
ar = ah >>16, ag = ah >>8&0xff, ab = ah &0xff,
bh = b;
br = bh >>16, bg = bh >>8&0xff, bb = bh &0xff,
rr = ar + amount *(br - ar),
rg = ag + amount *(bg - ag),
rb = ab + amount *(bb - ab);return((1<<24)+(rr <<16)+(rg <<8)+ rb |0);}/**/function map(n, start1, stop1, start2, stop2){return((n-start1)/(stop1-start1))*(stop2-start2)+start2;}//==============================================================================// World Definition//==============================================================================functionWorld(){//==============================================================================// All variables//==============================================================================var groundTexture;// Texture of the groundvar grounds;// Array2d : Stock all ground of the worldvar ai, aj;// position in grounds of the playervar pai, paj;// past position in grounds of the playervar timeRunning =0;// time updated var raycaster;// to determine direction of a clickvar camera, controls;var moveForward =false;var moveBackward =false;var moveLeft =false;var moveRight =false;var canJump =false;var prevTime = performance.now();var velocity =new THREE.Vector3();var direction =new THREE.Vector3();var vertex =new THREE.Vector3();var color =new THREE.Color();this.endCondition =false;//==============================================================================//==============================================================================//==============================================================================// All Class//==============================================================================//==============================================================================// Defines the THREE.PointerLockControls class, source at https://threejs.org///==============================================================================
THREE.PointerLockControls=function(camera){
let scope =this;
camera.rotation.set(0,0,0);
let pitchObject =new THREE.Object3D();
pitchObject.add( camera );
let yawObject =new THREE.Object3D();
yawObject.position.y =10;
yawObject.add( pitchObject );
let attachedObject =new THREE.Object3D();
yawObject.add(attachedObject);
attachedObject.position.set(0,-yawObject.position.y,-150);
let PI_2 =Math.PI /2;
let onMouseMove =function( event ){if( scope.enabled ===false)return;
let movementX = event.movementX || event.mozMovementX || event.webkitMovementX ||0;
let movementY = event.movementY || event.mozMovementY || event.webkitMovementY ||0;
yawObject.rotation.y -= movementX *0.002;
pitchObject.rotation.x -= movementY *0.002;
pitchObject.rotation.x =Math.max(- PI_2,Math.min( PI_2, pitchObject.rotation.x ));};this.getAttachedObject =function(){return attachedObject;};this.dispose =function(){
document.removeEventListener('mousemove', onMouseMove,false);};
document.addEventListener('mousemove', onMouseMove,false);this.enabled =false;this.getObject =function(){return yawObject;};this.getDirection =function(){// assumes the camera itself is not rotated
let direction =new THREE.Vector3(0,0,-1);
let rotation =new THREE.Euler(0,0,0,'YXZ');returnfunction( v ){
rotation.set( pitchObject.rotation.x, yawObject.rotation.y,0);
v.copy( direction ).applyEuler( rotation );return v;};}();};//==============================================================================// Class to stock Each Objects that were loaded // with their combobox size to place them in space// and to avoid collision ( objects at same place)classObj{
constructor(nameDoc, sX, sY, sZ){this.path = nameDoc;this.sizeX = sX;this.sizeY = sY;this.sizeZ = sZ;this.obj;}}//==============================================================================//==============================================================================//Just return a ground Elements that receive shadowfunction createGround(){
let texture = groundTexture;
let gr =new THREE.Mesh(new THREE.PlaneGeometry( squaresize*groundMultiplier, squaresize*groundMultiplier ),
texture );
gr.receiveShadow =true;
gr.rotation.x =(Math.PI /2)*3;return gr;}//initialize the ground of the world, to determine all type nd create fake grounds//around the world to fake a loopfunction initGround(){for(let i =0; i < worldSize; i++){for(let j =0; j < worldSize; j++){
grounds[i][j]= createGround();
grounds[i][j].position.set((i-Math.trunc(worldSize/2))* squaresize * groundMultiplier,0,(j-Math.trunc(worldSize/2))* squaresize*groundMultiplier);
threeworld.scene.add(grounds[i][j]);}}for(let i =- viewDistance; i < worldSize + viewDistance; i++){for(let j =- viewDistance; j < worldSize + viewDistance; j++){
let b =(worldSize + viewDistance);if(i <0|| j <0|| i >= worldSize || j >= worldSize){
let tmp;if( i <0){if(j <0){
tmp = grounds[worldSize + i][worldSize + j].clone();}elseif(j >= worldSize){
tmp = grounds[worldSize + i][j - worldSize].clone();}else{
tmp = grounds[worldSize + i][j].clone();}}elseif(i >= worldSize){if(j <0){
tmp = grounds[i - worldSize][worldSize + j].clone();}elseif(j >= worldSize){
tmp = grounds[i - worldSize][j - worldSize].clone();}else{
tmp = grounds[i - worldSize][j].clone();}}elseif(i >= worldSize){if(j <0){
tmp = grounds[i - worldSize][worldSize + j].clone();}elseif(j >= worldSize){
tmp = grounds[i - worldSize][j - worldSize].clone();}else{
tmp = grounds[i - worldSize][j].clone();}}elseif( j <0){
tmp = grounds[i][worldSize + j].clone();}elseif(j >= worldSize){
tmp = grounds[i][j - worldSize].clone();}
tmp.position.set((i -Math.trunc(worldSize/2))* squaresize * groundMultiplier,0,(j -Math.trunc(worldSize/2))* squaresize*groundMultiplier);
threeworld.scene.add(tmp);}}}}//==============================================================================//==============================================================================//==============================================================================// Functions link to an event//==============================================================================//Create a new infinite world. First destroy the previous one and then recreate one.function createNewInfiniteWorld(){
viewDistance = newviewDistance;
worldSize = newworldSize;
groundMultiplier = newGroundMultiplier;while(threeworld.scene.children.length){
threeworld.scene.remove(threeworld.scene.children[0]);}
threeworld.scene.add(controls.getObject());
init();}function onDocumentTouchStart( event ){
console.log("onDocumentTouchStart");
event.preventDefault();
event.clientX = event.touches[0].clientX;
event.clientY = event.touches[0].clientY;
onDocumentMouseDown( event );}//Called when a key is upfunction handleKeyUp (e){if((e.keyCode ==38)||(e.keyCode ==40)){
velocity =0;}if(e.keyCode ==37|| e.keyCode ==39){
speedRotation =0;}if(e.keyCode ==37|| e.keyCode ==39){
speedRotation =0;}}//==============================================================================//==============================================================================//Load all you needfunction loader(){
planeTex = THREE.ImageUtils.loadTexture("/uploads/meak/grass.jpg");
planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
planeTex.repeat.set(8,8);
groundTexture =new THREE.MeshPhongMaterial({map: planeTex, dithering:true});
groundTexture.wrapAround =true;
groundTexture.castShadow =true;
groundTexture.receiveShadow =true;}//Initalization before running the worldfunction init(){
grounds =newArray(worldSize);for(let i =0; i < worldSize; i++){
grounds[i]=newArray(worldSize);for(let j =0; j < worldSize; j++){
grounds[i][j]=null;}}
ai = parseInt(worldSize/2+ camera.getWorldPosition().x/(squaresize*groundMultiplier));
aj = parseInt(worldSize/2+ camera.getWorldPosition().z/(squaresize*groundMultiplier));
pai = ai;
paj = aj;
initGround();// LIGHTS
let hemiLight =new THREE.HemisphereLight( SKYCOLOR, SKYCOLOR,1);
hemiLight.position.set(0,50,0);
threeworld.scene.add( hemiLight );}function checkPositionPlayer(){//Update the position of the payer in the world so that it can generate ground around the player, depending on the viewDistanceif(worldSize/2+ camera.getWorldPosition().x/(squaresize*groundMultiplier)<0){
ai =-Math.ceil(-(worldSize/2+ camera.getWorldPosition().x/(squaresize*groundMultiplier)));}else{
ai =Math.trunc(worldSize/2+ camera.getWorldPosition().x/(squaresize*groundMultiplier));}if(worldSize/2+ camera.getWorldPosition().z/(squaresize*groundMultiplier)<0){
aj =-Math.ceil(-(worldSize/2+ camera.getWorldPosition().z/(squaresize*groundMultiplier)));}else{
aj =Math.trunc(worldSize/2+ camera.getWorldPosition().z/(squaresize*groundMultiplier));}if(ai <0){
controls.getObject().position.x =(worldSize/2)* groundMultiplier * squaresize -0.01;}if(ai >= worldSize){
controls.getObject().position.x =- worldSize/2* groundMultiplier * squaresize;}if(aj >= worldSize){
controls.getObject().position.z =- worldSize/2* groundMultiplier * squaresize;}if(aj <0){
controls.getObject().position.z =(worldSize/2)* groundMultiplier * squaresize -0.01;}if(ai != pai || aj != paj){
pai = ai;
paj = aj;}}//==============================================================================//==============================================================================//==============================================================================// Function newRun ,init and endRun//==============================================================================this.newRun =function(){
camera =new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,1,1000);
threeworld.camera = camera;
threeworld.init3d (0,0, SKYCOLOR );// can adjust renderer:
threeworld.renderer.shadowMap.enabled =true;
threeworld.renderer.shadowMap.type = THREE.PCFSoftShadowMap;//load ground texture
loader();//position of mouse in the canvas
mouse =new THREE.Vector2();//First person controller
controls =new THREE.PointerLockControls( camera );//This will handle key presses
let onKeyDown =function( event ){switch( event.keyCode ){case38:// upcase87:// w
moveForward =true;break;case37:// leftcase65:// a
moveLeft =true;break;case40:// downcase83:// s
moveBackward =true;break;case39:// rightcase68:// d
moveRight =true;break;case32:// spaceif( canJump ===true||true) velocity.y +=350;
canJump =false;break;case82://Re-generateTheworld (R)
createNewInfiniteWorld();break;}};
let onKeyUp =function( event ){switch( event.keyCode ){case38:// upcase87:// w
moveForward =false;break;case37:// leftcase65:// a
moveLeft =false;break;case40:// downcase83:// s
moveBackward =false;break;case39:// rightcase68:// d
moveRight =false;break;}};
document.addEventListener('keydown', onKeyDown,false);
document.addEventListener('keyup', onKeyUp,false);
raycaster =new THREE.Raycaster(new THREE.Vector3(),new THREE.Vector3(0,-1,0),0,10);//The following handles pointer locking when clicking the window
let havePointerLock ='pointerLockElement' in document ||'mozPointerLockElement' in document ||'webkitPointerLockElement' in document;
console.log(havePointerLock);if( havePointerLock ){
let element = document.body;
let pointerlockchange =function( event ){if( document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element ){if(HUDEVENT){
document.exitPointerLock();
HUDEVENT =false;}else{if(!controls.enabled && controls.getAttachedObject().children.length !==0){
controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);}if(!controls.enabled){
controls.enabled =true;
$("#user_span10").html("");}}}else{
controls.enabled =false;
$("#user_span10").html("<p><b>Click screen to enable mouse controls</b></p>");}};
let pointerlockerror =function( event ){
console.error("pointerlockerror");};// Hook pointer lock state change events
document.addEventListener('pointerlockchange', pointerlockchange,false);
document.addEventListener('mozpointerlockchange', pointerlockchange,false);
document.addEventListener('webkitpointerlockchange', pointerlockchange,false);
document.addEventListener('pointerlockerror', pointerlockerror,false);
document.addEventListener('mozpointerlockerror', pointerlockerror,false);
document.addEventListener('webkitpointerlockerror', pointerlockerror,false);
document.addEventListener('click',function( event ){// Ask the browser to lock the pointer
element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock;
element.requestPointerLock();},false);}else{
$("#user_span1").html('<p>Your browser doesn\'t seem to support Pointer Lock API</p>');}if( AB.onDesktop()){
$("#user_span1").html("<p>Use WASD or Arrows to move, mouse to look around and space to jump.</p>"+"<p> If you want to re-generate the world, you can press R !</p>");
$("#user_span10").html("<p><b>Click screen to enable mouse controls</b></p>");
$("#user_span4").html("<p> Size of each parcel of the world (1 to 1000) <input type=\"number\" min=\"1\" max=\"1000\" value=\""+ newGroundMultiplier +"\" class=\"slider\" id=\"groundMultiplierHtml\"></p>");
document.getElementById("groundMultiplierHtml").onchange =function(){
newGroundMultiplier =+this.value ;
console.log("groundMultiplierHtml "+ newGroundMultiplier);
HUDEVENT =true;}
document.getElementById("groundMultiplierHtml").onkeypress =function(){
newGroundMultiplier =+this.value ;
console.log("groundMultiplierHtml "+ newGroundMultiplier);
HUDEVENT =true;}
$("#user_span5").html("<p> Size of the world (1 to 50) <input type=\"number\" min=\"1\" max=\"50\" value=\""+ newworldSize +"\" class=\"slider\" id=\"worldSizeHtml\"></p>");
document.getElementById("worldSizeHtml").onchange =function(){
newworldSize =+this.value;if((newworldSize -1)/2< newviewDistance){
newviewDistance =0;
document.getElementById("viewDistanceHtml").value =0;}
HUDEVENT =true;
console.log("worldSizeHtml "+ newworldSize);}
document.getElementById("worldSizeHtml").onkeypress =function(){
newworldSize =+this.value;if((newworldSize -1)/2< newviewDistance){
newviewDistance =0;
document.getElementById("viewDistanceHtml").value =0;}
HUDEVENT =true;
console.log("worldSizeHtml "+ newworldSize);}
$("#user_span6").html("<p> viewDistance in term of parcel (0 to 10) <input type=\"number\" min=\"0\" max=\"10\" value=\""+ newviewDistance +"\" class=\"slider\" id=\"viewDistanceHtml\"></p>");
document.getElementById("viewDistanceHtml").onchange =function(){if(newworldSize/2>=+this.value){
newviewDistance =+this.value ;}
console.log("viewDistanceHtml "+ newviewDistance);
HUDEVENT =true;}
document.getElementById("viewDistanceHtml").onkeypress =function(){if(newworldSize/2>=+this.value){
newviewDistance =+this.value ;}
console.log("viewDistanceHtml "+ newviewDistance);
HUDEVENT =true;}}else{
$("#user_span1").html("<p> <b> This World currently only works on desktop. </b> </p>");}
createNewInfiniteWorld();};this.nextStep =function(){//======================================================================//This will handle moving the player and the camera//======================================================================
raycaster.ray.origin.copy( controls.getObject().position );
raycaster.ray.origin.y -=10;
let time = performance.now();
let delta =( time - prevTime )/1000;
velocity.x -= velocity.x *10.0* delta;
velocity.z -= velocity.z *10.0* delta;
velocity.y -=9.8*100.0* delta;// 100.0 = mass
direction.z =Number( moveForward )-Number( moveBackward );
direction.x =Number( moveLeft )-Number( moveRight );
direction.normalize();// this ensures consistent movements in all directionsif( moveForward || moveBackward ) velocity.z -= direction.z *400.0* MOVESPEED * delta;if( moveLeft || moveRight ) velocity.x -= direction.x *400.0* MOVESPEED * delta;
controls.getObject().translateX( velocity.x * delta );
controls.getObject().translateY( velocity.y * delta );
controls.getObject().translateZ( velocity.z * delta );if( controls.getObject().position.y <10){
velocity.y =0;
controls.getObject().position.y =10;
canJump =true;}
prevTime = time;//Function to do the loop if the player is at the edge of the world
checkPositionPlayer();};//==============================================================================//==============================================================================}