<div id="scene">
  <div id="blocker">
    <div id="instructions">
				<span style="font-size:36px">Click to start</span>
				<br /><br />
				Move: WASD<br/>
				Jump: SPACE<br/>
				Look: MOUSE
			</div>
  </div>
  <div id="hint"><span>ESC to exit</span></div>
</div>


<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://threejs.org/examples/js/controls/PointerLockControls.js"></script>

 body {
    margin: 0;
    overflow: hidden;
  }
canvas {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

#blocker {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.5);
}

#instructions {
  width: 100%;
  height: 100%;

  display: -webkit-box;
  display: -moz-box;
  display: box;

  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;

  -webkit-box-pack: center;
  -moz-box-pack: center;
  box-pack: center;

  -webkit-box-align: center;
  -moz-box-align: center;
  box-align: center;

  color: #ffffff;
  text-align: center;
  font-family: Arial;
  font-size: 14px;
  line-height: 24px;

  cursor: pointer;
}

#hint {
  position: absolute;
  top: 5px;
  right: 10px;
  color: #ddd;
  font-size: 10px;
  font-family: Arial;
  display: none;
}

let particleSystem, particleCount, particles, controls, onKeyDown, onKeyUp, raycaster, scene, stats, camera;
let objects = [];
const lightColors = [
  '#2980b9',
  '#16a085',
  '#d35400',
  '#8e44ad',
  '#c0392b',
  '#2c3e50',
  '#b33939',
  '#218c74'
]
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let canJump = false;
let prevTime = performance.now();
let velocity = new THREE.Vector3();
let direction = new THREE.Vector3();
let vertex = new THREE.Vector3();
let color = new THREE.Color();
let clock = new THREE.Clock();



function setupStats() {
  stats = new Stats();
  stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
  document.body.appendChild( stats.dom );
}
function setupCamera() {
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
  camera.position.y = 10;
  camera.rotation.y = 180.65;
}
function setupScene() {
  scene = new THREE.Scene();
  scene.fog = new THREE.Fog(0x242426, 20, 250);
}
function setupRenderer() {
  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize(window.innerWidth, window.innerHeight);

  renderer.setClearColor( 0x242426 );
  renderer.toneMapping = THREE.LinearToneMapping;
 
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  document.body.appendChild(renderer.domElement);
}
function setupControls() {
  raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );
  
  let onKeyDown = function ( event ) {
    
   switch ( event.keyCode ) {
              case 27:
                moveForward = false;
                moveBackward = false;
                moveLeft = false;
                moveRight = false;
                break
              case 38: // up
              case 87: // w
                moveForward = true;
                break;
              case 37: // left
              case 65: // a
                moveLeft = true; break;
              case 40: // down
              case 83: // s
                moveBackward = true;
                break;
              case 39: // right
              case 68: // d
                moveRight = true;
                break;
              case 32: // space
                if ( canJump === true ) velocity.y += 350;
                canJump = false;
                break;
            }
  };
  let onKeyUp = function ( event ) {
    switch( event.keyCode ) {
      case 38: // up
      case 87: // w
        moveForward = false;
        break;
      case 37: // left
      case 65: // a
        moveLeft = false;
        break;
      case 40: // down
      case 83: // s
        moveBackward = false;
        break;
      case 39: // right
      case 68: // d
        moveRight = false;
        break;
    }
  };

  document.addEventListener( 'keydown', onKeyDown, false );
  document.addEventListener( 'keyup', onKeyUp, false );
  
  controls = new THREE.PointerLockControls( camera );
  
  let blocker = document.getElementById( 'blocker' );
  let instructions = document.getElementById( 'instructions' );
  let hint = document.getElementById( 'hint' );

  instructions.addEventListener( 'click', function () { controls.lock(); }, false );

  controls.addEventListener( 'lock', function () {
    instructions.style.display = 'none';
    blocker.style.display = 'none';
    hint.style.display = 'block';
  } );

  controls.addEventListener( 'unlock', function () {
    blocker.style.display = 'block';
    instructions.style.display = '';
    hint.style.display = 'none';
  } );
 
  scene.add( controls.getObject() );
 
}
function handleWindowResize() {
  window.addEventListener( 'resize', onWindowResize, false );
  function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( window.innerWidth, window.innerHeight );

  }
}
function snow() {
   let loader = new THREE.TextureLoader();
    loader.crossOrigin = '';
   particleCount = 15000;
   let pMaterial = new THREE.PointCloudMaterial({
      color: 0xFFFFFF,
      size: 1.5,
      map: loader.load(
         "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/sprites/snowflake2.png"
       ),
       blending: THREE.AdditiveBlending,
       depthTest: false,
       transparent: true
    });

    particles = new THREE.Geometry;
    for (var i = 0; i < particleCount; i++) {
        var pX = Math.random()*500 - 250,
            pY = Math.random()*500 - 250,
            pZ = Math.random()*500 - 250,
            particle = new THREE.Vector3(pX, pY, pZ);
        particle.velocity = {};
        particle.velocity.y = 0;
        particles.vertices.push(particle);
    }
    particleSystem = new THREE.PointCloud(particles, pMaterial);
    particleSystem.position.x = 100;
    particleSystem.position.y = 100;
    scene.add(particleSystem);
}
function makeItSnow() {
    var pCount = particleCount;
    while (pCount--) {
    var particle = particles.vertices[pCount];
    if (particle.y < -200) {
      particle.y = 200;
      particle.velocity.y = 0;
    }
    particle.velocity.y -= Math.random() * .02;
    particle.y += particle.velocity.y;
    }
    particles.verticesNeedUpdate = true;
}
function ground() {  
  let geometry = new THREE.PlaneGeometry( 700, 600, 22, 12 );
  for (let i = 0; i < geometry.vertices.length; i++) {
    geometry.vertices[i].z = (Math.sin(i * i * i)+1/2) * 3;
  }
  geometry.verticesNeedUpdate = true;
  geometry.normalsNeedUpdate = true;
  geometry.computeFaceNormals(); 

  let material = new THREE.MeshPhongMaterial({ 
    color: 0xFFFFFF, 
    shininess: 60,
    bumpScale: 0.045,
    emissive: 0xEBF7FD,
    emissiveIntensity: 0.03,
  }); 

  let plane = new THREE.Mesh( geometry, material );
  plane.rotation.x = Math.PI / -2;
  plane.receiveShadow = true;
  plane.position.y = -5;

  scene.add(plane)
}
function light() {
    var ambientLight = new THREE.AmbientLight(0x222222);
    scene.add(ambientLight);
  
    let hemiLight = new THREE.HemisphereLight( 0xEBF7FD, 0xEBF7FD, 0.2 );
    hemiLight.color.setRGB(0.75,0.8,0.95);
    hemiLight.position.set( 0, 100, 0 );
    scene.add( hemiLight );
}
function createTree() {
  // tree
  var tree = new THREE.Group();
  var trunkGeometry = new THREE.CylinderBufferGeometry(5, 10, 50);
  var trunkMaterial = new THREE.MeshPhongMaterial({ color: 0x49311c });
  var trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
  tree.add(trunk);

  // leaves
  var leavesMaterial = new THREE.MeshPhongMaterial({ color: 0x3d5e3a });
 
  
  var leavesCone= new THREE.ConeBufferGeometry(20, 40, 6);
  var leavesBottom = new THREE.Mesh(leavesCone, leavesMaterial);
  leavesBottom.position.y = 35;
  tree.add(leavesBottom);

  addRingOfLights(leavesBottom, 15, 17, -15, 0)
  addRingOfLights(leavesBottom, 16, 16, -15,  Math.PI  / 4)
  addRingOfLights(leavesBottom, 10, 11, -3,  0)
  addRingOfLights(leavesBottom, 10, 11, -3,  Math.PI  / 4)

  
  var middleLeaveCone = new THREE.ConeBufferGeometry(15, 30, 6);    
  var leavesMiddle = new THREE.Mesh(middleLeaveCone, leavesMaterial );
  leavesMiddle.position.y = 55;
  tree.add(leavesMiddle);
  
  addRingOfLights(leavesMiddle, 10, 11, -8)
  addRingOfLights(leavesMiddle, 10, 11, -8, Math.PI  / 4)

  var topLeaveCone = new THREE.ConeBufferGeometry(10, 20, 6);  
  var leavesTop = new THREE.Mesh(topLeaveCone, leavesMaterial);
  leavesTop.position.y = 70;
  tree.add(leavesTop);
  
  addRingOfLights(leavesTop, 6, 6, -3)
  addRingOfLights(leavesTop, 6, 6, -3, Math.PI  / 4)
  
  return tree
}
function createForest() {
  let numOfTrees = 4;
  
  // Right Line of Trees
  for(let i = 0; i <= numOfTrees; i++) {
    placeTree(100, 0,40 * i + 40);
  }
  
  // Right Wall
  for(let i = 0; i <= numOfTrees + 1; i++) {
     placeTree(40 * i + 100, 0,40 * numOfTrees + 40);
  }
  
  // Right Back Wall
  for(let i = 0; i <= numOfTrees + 1; i++) {
    placeTree(40 * (numOfTrees + 1) + 100, 0, (40 * numOfTrees + 40) - (40 * i + 40));
  }
  
  // Left Line of Trees
  for(let i = 0; i <= numOfTrees; i++) {
    placeTree(100, 0, -(40 * i + 40));
  }
  
  // Left Wall of Trees
  for(let i = 0; i <= numOfTrees + 1; i++) {
     placeTree( 40 * i + 100, 0, -(40 * numOfTrees + 40));
  }
  
   // Left Wall Back of Trees
  for(let i = 0; i <= numOfTrees; i++) {
     placeTree(40 * (numOfTrees + 1) + 100 , 0, -(40 * numOfTrees + 40) + (40 * i + 40));
  }
   
  // Right Entrance
  placeTree(80, 0, 40);
  placeTree(60, 0, 40);
  placeTree(40, 0, 40);
  placeTree(20, 0, 40);
  placeTree(0, 0, 40);
  placeTree(-20, 0, 40);
  // Left Entrance
  placeTree(80, 0, -40);
  placeTree(60, 0, -40);
  placeTree(40, 0, -40);
  placeTree(20, 0, -40);
  placeTree(0, 0, -40);
  placeTree(-20, 0, -40);
  
  // Back of Entrance
  placeTree(-40, 0, -40);
  placeTree(-40, 0, -20);
  placeTree(-40, 0, 0);
  placeTree(-40, 0, 20);
  placeTree(-40, 0, 40);
    

}
function placeTree(x, y, z) {
  let newTree = createTree();
  newTree.position.y = y;
  newTree.position.x = x;
  newTree.position.z = z;
  scene.add(newTree);
  objects.push( newTree );
}
function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
function addRingOfLights(thing, left, right, y, rotation = 0) {
    let group = new THREE.Group();
    let light = christmasLight(left, y, 0, randomChristmasColor())  
    let light2 = christmasLight(-left, y, 0, randomChristmasColor())  
    let light3 = christmasLight(0, y, right, randomChristmasColor())  
    let light4 = christmasLight(0, y, -right, randomChristmasColor())  
    group.add( light );
    group.add( light2 );
    group.add( light3 );
    group.add( light4 );
    group.rotation.y = rotation;
    thing.add(group);
}
function randomChristmasColor() {
  const numOfLightColors = lightColors.length;
  const color = lightColors[getRandomInt(0, numOfLightColors - 1)];
  return color;
}
function christmasLight(x,y,z, color) {
  var bulbGeometry = new THREE.SphereBufferGeometry( 1, 16, 8 );
  bulbMat = new THREE.MeshStandardMaterial( {
    emissive:color || 0xffffee,
    emissiveIntensity: 3,
    color: color || 0x000000
  } );
  const bulbMesh = new THREE.Mesh( bulbGeometry, bulbMat );
  bulbMesh.position.set(x,y,z);
  return bulbMesh;
}
function createFireLight(color, power = 7){
  var light = new THREE.PointLight( color || 0xFFFFFF , 1, 0 );
  light.castShadow = true;
  light.shadow.mapSize.width = 512;
  light.shadow.mapSize.height = 512;
  light.shadow.camera.near = 0.1;
  light.shadow.camera.far = 120;
  light.shadow.bias = 0.9;
  light.shadow.radius = 5;
  light.power = power;

  return light;
}
function createFlame(x, y, z, color, outerColor, hasLight) {
  const fireLight = createFireLight(color);
  let geometry =  new THREE.ConeGeometry( .5, 4, 6, 10 );
  let material = new THREE.MeshPhongMaterial({ 
    color: color, 
    shininess: 550, 
    emissive: color,
    transparent: true,
    opacity: 0.4,
  });
   let flame = new THREE.Mesh( geometry, material );
  
  if(hasLight) flame.add(fireLight)

  flame.position.x = x;
  flame.position.y = 0;
  flame.position.z = z;
  
  let outerGeometry = new THREE.ConeGeometry( 1, 6, 6, 10 );
  let outerMaterial = new THREE.MeshPhongMaterial({ 
    color: outerColor, 
    shininess: 550, 
    emissive: outerColor,
    transparent: true,
    opacity: .4,
  });
  let outerFlame = new THREE.Mesh( outerGeometry, outerMaterial );
  flame.add(outerFlame)
  outerFlame.position.y =  1;
  
  return flame;
}
function createLog(x,y,z){
   let geometry = new THREE.CylinderBufferGeometry( 1, 1, 6, 8 );
   let material = new THREE.MeshPhongMaterial({ 
    color: 0x5C2626, 
    shininess: 10, 
    emissive: 0x5C2626,
  });
  var log = new THREE.Mesh( geometry, material );
  log.rotation.z = Math.PI / 2;
  log.position.x = x;
  log.position.y = y - 3;
  log.position.z = z;
  return log;
}
function campFire() {
  const log1 = createLog(172, 0, 0);
  log1.rotation.y = Math.PI / 2;
  const log2 = createLog(168, 0, 0);
  log2.rotation.y = Math.PI / 2;
  const log3 = createLog(170, 1, 2);
  const log4 = createLog(170, 1, -2);
  
  const flame1 = createFlame(172, 3, 0, 0xdb2902, 0xfb4402, false );
  const flame2 = createFlame(170, 3, 2, 0xdb2902, 0xfb4402 );
  const flame3 = createFlame(170, 3, -2, 0xdb2902, 0xfb4402 );
  const flame4 = createFlame(168, 3, 0, 0xdb2902, 0xfb4402, false );
  const flame5 = createFlame(170, 3, 0, 0xdb2902, 0xfb4402, true );
  flame5.scale.set(2,2,2);
  
  scene.add(flame1);
  scene.add(flame2);
  scene.add(flame3);
  scene.add(flame4);
  scene.add(flame5);
  
  scene.add(log1);
  scene.add(log2);
  scene.add(log3);
  scene.add(log4);
}
function snowman(x,y,z) {
  
  const snowMaterial = new THREE.MeshPhongMaterial({ 
    color: 0xFFFFFF, 
    shininess: 60,
    bumpScale: 0.045,
    emissive: 0xEBF7FD,
    emissiveIntensity: 0.03,
  }); 
  const bottomBall = new THREE.Mesh( new THREE.SphereBufferGeometry( 22, 32, 32 ) , snowMaterial );	
  bottomBall.position.set(x, y, z);
  bottomBall.rotation.y = - Math.PI / 2;
	
  
  const middleBall = new THREE.Mesh( new THREE.SphereBufferGeometry( 16, 32, 32 ) , snowMaterial );	
  middleBall.position.set(0, 24, 0);
	bottomBall.add(middleBall);

  
  const head = new THREE.Mesh( new THREE.SphereBufferGeometry( 12, 24, 24 ) , snowMaterial );
  head.position.y = 20;
  middleBall.add(head);

	
  const armMaterial = new THREE.MeshBasicMaterial( { color: 0x111111 , side:THREE.DoubleSide} );	
	const rightBicep = new THREE.Mesh( new THREE.CylinderBufferGeometry(1, 1, 22, 12, 1), armMaterial);
  rightBicep.position.x = 20;
	rightBicep.position.y = 5;
	rightBicep.rotation.z = Math.PI / 2;
	middleBall.add( rightBicep );
  
  const rightForearm = new THREE.Mesh( new THREE.CylinderBufferGeometry(1, 1, 15, 12, 1), armMaterial);
  rightForearm.position.x = 31;
	rightForearm.position.y = 12;
	rightForearm.rotation.z = Math.PI + .03;
  middleBall.add( rightForearm );
  
  const leftBicep = new THREE.Mesh( new THREE.CylinderBufferGeometry(1, 1, 22, 12, 1), armMaterial);
  leftBicep.position.x = -20;
  leftBicep.position.z = 10;
	leftBicep.position.y = 5;
	leftBicep.rotation.z = Math.PI / 2;
  leftBicep.rotation.y = Math.PI / 4;
	middleBall.add( leftBicep );
  
  const leftForearm = new THREE.Mesh( new THREE.CylinderBufferGeometry(1, 1, 15, 12, 1), armMaterial);
  leftForearm.position.x = -27;
  leftForearm.position.z = 22;
	leftForearm.position.y = 10;
	leftForearm.rotation.z = Math.PI + .03;
  leftForearm.rotation.x = Math.PI / 4;
  middleBall.add( leftForearm );
  
  const leftFinger = new THREE.Mesh( new THREE.CylinderBufferGeometry(.4, .4, 4, 12, 1), armMaterial);
  leftFinger.position.x = 0;
  leftFinger.position.z = 0;
	leftFinger.position.y = -9;
  leftForearm.add( leftFinger );
  
  const leftLeftFinger = new THREE.Mesh( new THREE.CylinderBufferGeometry(.4, .4, 5, 12, 1), armMaterial);
  leftLeftFinger.position.x = 2;
  leftLeftFinger.position.z = 0;
	leftLeftFinger.position.y = -8;
  leftLeftFinger.rotation.x = Math.PI / 8;
  leftLeftFinger.rotation.z = Math.PI / 8;
  leftForearm.add( leftLeftFinger );
  
  const leftRightFinger = new THREE.Mesh( new THREE.CylinderBufferGeometry(.4, .4, 5, 12, 1), armMaterial);
  leftRightFinger.position.x = -2;
  leftRightFinger.position.z = 0;
	leftRightFinger.position.y = -8;
  leftRightFinger.rotation.x = Math.PI / 8;
  leftRightFinger.rotation.z = -Math.PI / 8;
  leftForearm.add( leftRightFinger );

 
  const noseMaterial = new THREE.MeshPhongMaterial({ 
    color: 0xff1133, 
    shininess: 60,
    bumpScale: 0.045,
    emissive: 0xff1133,
    emissiveIntensity: 0.03,
  }); 
	const nose = new THREE.Mesh(new THREE.CylinderBufferGeometry(0.5, 2.5, 8, 12, 4), noseMaterial);
  nose.position.z = 15;
	nose.rotation.x = 1.6;
  nose.rotation.y = -1;
	head.add(nose);
  
  const eyeMaterial = new THREE.MeshBasicMaterial( { color: 0x000000 } );
	const leftEye = new THREE.Mesh( new THREE.CylinderBufferGeometry(1.75, 1.75, 2, 12, 1), eyeMaterial); 	
  leftEye.rotation.x = 1.57;
	leftEye.position.set(5,3,11);	
	head.add(leftEye)

	const rightEye = leftEye.clone();
  rightEye.rotation.x = 1.57;
	rightEye.position.set(-5,3,11);
	head.add(rightEye);
  
  snowmanHat = topHat(0, 12, 0);
  head.add(snowmanHat);
  
  objects.push(bottomBall);
  return bottomBall;
}
function topHat(x = 0, y = 0, z = 0, brimY = -5) {
  let hatMaterial = new THREE.MeshBasicMaterial( { color: 0x111111 , side:THREE.DoubleSide} );	
  let hat = new THREE.Mesh( new THREE.CylinderGeometry(10, 10, 14, 12, 1), hatMaterial); 
  hat.position.x = x;
	hat.position.y = y;
  hat.position.z = z;
  
  
	let brim = new THREE.Mesh( new THREE.RingGeometry( 10, 16, 24, 1 ), hatMaterial);
	hat.add( brim );
	brim.position.y = brimY;
	brim.rotation.x = 1.57;	
  
  return hat;
}
function createSnowmen() {
  const mainSnowman = snowman(220, 10, 0);
  scene.add(mainSnowman);
  
  const glowingGlobe = christmasLight(193, 53, -27);
  glowingGlobe.scale.x = 3;
  glowingGlobe.scale.y = 3;
  glowingGlobe.scale.z = 3;
  scene.add(glowingGlobe)
  
  const rightSnowman = snowman(215, 7, 50);
  rightSnowman.scale.x = .75;
  rightSnowman.scale.y = .75;
  rightSnowman.scale.z = .75;
  scene.add(rightSnowman)
  
  const glowingGlobe2 = christmasLight(195, 39, 30);
  glowingGlobe2.scale.x = 2;
  glowingGlobe2.scale.y = 2;
  glowingGlobe2.scale.z = 2;
  scene.add(glowingGlobe2)
  
  const leftSnowman = snowman(210, 7, -45);
  leftSnowman.scale.x = .5;
  leftSnowman.scale.y = .5;
  leftSnowman.scale.z = .5;
  scene.add(leftSnowman)
  
  const glowingGlobe3 = christmasLight(197, 28, -59);
  glowingGlobe2.scale.x = 1.25;
  glowingGlobe2.scale.y = 1.25;
  glowingGlobe2.scale.z =  1.25;
  scene.add(glowingGlobe3)
  
 
}
function createTopHats() {
  snowmanHat1 = topHat(128, 1, -50);
  snowmanHat1.scale.set(.25, .25, .25);
  snowmanHat2 = topHat(130, 2, -70);
  snowmanHat2.scale.set(.5, .5, .5);
  snowmanHat3 = topHat(140, 4, -100);  
  snowmanHat4 = topHat(170, 6, -130);
  snowmanHat4.scale.set(1.5, 1.5, 1.5);
  snowmanHat5 = topHat(240, 15, -140, -7);
  snowmanHat5.scale.set(2, 2, 2);
  
  
  snowmanHat6 = topHat(128, 1, 50);
  snowmanHat6.scale.set(.25, .25, .25);
  snowmanHat7 = topHat(130, 2, 70);
  snowmanHat7.scale.set(.5, .5, .5);
  snowmanHat8 = topHat(140, 4, 100);  
  snowmanHat9 = topHat(170, 6, 130);
  snowmanHat9.scale.set(1.5, 1.5, 1.5);
  snowmanHat10 = topHat(240, 15, 140, -7);
  snowmanHat10.scale.set(2, 2, 2);
  
  
  scene.add(snowmanHat1);
  scene.add(snowmanHat2);
  scene.add(snowmanHat3);
  scene.add(snowmanHat4);
  scene.add(snowmanHat5);
  scene.add(snowmanHat6);
  scene.add(snowmanHat7);
  scene.add(snowmanHat8);
  scene.add(snowmanHat9);
  scene.add(snowmanHat10);
  objects.push(snowmanHat1, snowmanHat2 ,snowmanHat3, snowmanHat4, snowmanHat5, snowmanHat6, snowmanHat7, snowmanHat8, snowmanHat9, snowmanHat10)
}
function animate() {
  requestAnimationFrame( animate );
  stats.begin();
  particleSystem.rotation.y += 0.01;
  makeItSnow();
 
  if ( controls.isLocked === true ) {
    raycaster.ray.origin.copy( controls.getObject().position );
	  raycaster.ray.origin.y -= 10;
    
  	var intersections = raycaster.intersectObjects( objects );
    var onObject = intersections.length > 0;
    var time = performance.now();
    var 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( moveRight ) - Number( moveLeft );
    direction.normalize(); // this ensures consistent movements in all directions

    if ( moveForward || moveBackward ) velocity.z -= direction.z * 400.0 * delta;
    if ( moveLeft || moveRight ) velocity.x -= direction.x * 400.0 * delta;

    if ( onObject === true ) {
      velocity.y = Math.max( 0, velocity.y );
      canJump = true;
    }

    controls.moveRight( - velocity.x * delta );
    controls.moveForward( - velocity.z * delta );
    controls.getObject().position.y += ( velocity.y * delta ); // new behavior

    if ( controls.getObject().position.y < 10 ) {
      velocity.y = 0;
      controls.getObject().position.y = 10;
      canJump = true;
    }

    prevTime = time;

  	stats.end();
  } else {
    // Prevent Player from continuing if esc and forward at the same time
    velocity.x = 0;
    velocity.z = 0;
    controls.moveRight(0);
    controls.moveForward( 0 );
    moveForward = false;
    moveBackward = false;
    moveLeft = false;
    moveRight = false;
  }
  render();
}
function render() {
  renderer.render( scene, camera );
}
const init = () => {
  setupStats();
  setupCamera();
  setupScene();
  setupRenderer();
  setupControls();
  handleWindowResize();
  ground();
  createForest();
  snow();
  light();
  campFire();
  createSnowmen();
  createTopHats();
}



init();
animate();


External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.