Source: walk.js

// configuration variables
const headHeight = 1.50;
const startPoint = new THREE.Vector3(9, headHeight, 11);
const mouseRotateSpeed = 0.17;
const playerWidth = 0.4;
const mouseZoomSpeed = 0.8;
const baseDistancePerWalk = 4
let distancePerWalk = baseDistancePerWalk;

/**
 * Initialize the walking controls
 */
function initWalk() {

  camera.lookAt(new THREE.Vector3(-1, 0, -1));

  // register key events
  window.addEventListener("keydown", event => {
    switch (event.key) {
      case "ArrowUp":
      case "w":
      case "W":
        isWalking.forward = true;
        break;
      case "ArrowDown":
      case "s":
      case "S":
        isWalking.backward = true;
        break;
      case "ArrowLeft":
      case "a":
      case "A":
        isWalking.left = true;
        break;
      case "ArrowRight":
      case "d":
      case "D":
        isWalking.right = true;
        break;
      case "Shift":
      case "shift":
        distancePerWalk = baseDistancePerWalk * 2;
        break;
    }
  });

  window.addEventListener("keyup", event => {
    switch (event.key) {
      case "ArrowUp":
      case "w":
      case "W":
        isWalking.forward = false;
        break;
      case "ArrowDown":
      case "s":
      case "S":
        isWalking.backward = false;
        break;
      case "ArrowLeft":
      case "a":
      case "A":
        isWalking.left = false;
        break;
      case "ArrowRight":
      case "d":
      case "D":
        isWalking.right = false;
        break;
      case "Shift":
      case "shift":
        distancePerWalk = baseDistancePerWalk;
        break;
    }
  });
  createPlayer();
}


/**
 * Calculates the new position of the player/camera
 * @param {THREE.Vector3} position current position of the player/camera
 * @param {THREE.Vector3} lookAt current lookAt of the camera
 * @param {number} distance distance the player should walk
 * @param { { forward: boolean, backward: boolean, left: boolean, right: boolean } } isWalking object that stores if the user is walking in a direction
 * @returns {THREE.Vector3} new position of the player/camera
 */
function getNewPosition(position, lookAt, distance, isWalking) {
  const newPosition = new THREE.Vector3(position.x, position.y, position.z);

  // check if two keys are pressed at the same time
  if ((isWalking.forward && (isWalking.left || isWalking.right)) || (isWalking.backward && (isWalking.left || isWalking.right))) {
    distance = distance / 2;
  }

  if (isWalking.forward === true) {
    newPosition.add(lookAt.clone().multiplyScalar(distance));
  }

  if (isWalking.backward === true) {
    newPosition.add(lookAt.clone().multiplyScalar(-distance));
  }

  if (isWalking.left === true) {
    newPosition.add(
      lookAt
        .clone()
        .applyAxisAngle(new THREE.Vector3(0, 1, 0), degToRad(90))
        .multiplyScalar(distance)
    );
  }

  if (isWalking.right === true) {
    newPosition.add(
      lookAt
        .clone()
        .applyAxisAngle(new THREE.Vector3(0, 1, 0), degToRad(-90))
        .multiplyScalar(distance)
    );
  }

  newPosition.y = position.y;
  return newPosition;
}


/**
 * Creates a player mesh and adds it to the scene
 */
function createPlayer() {
  const playerGeometry = new THREE.BoxGeometry(playerWidth, headHeight, playerWidth);
  const playerMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0 });
  const player = new THREE.Mesh(playerGeometry, playerMaterial);
  player.position.set(startPoint.x, headHeight / 2 + 0.2, startPoint.z);
  scene.add(player);
  sceneObjects.player = player;
  camera.position.set(
    sceneObjects.player.position.x,
    headHeight,
    sceneObjects.player.position.z
  );
}


/**
 * Handle the walking of the player
 * Is called every frame in animate.js
 */
function handleWalking() {

  if (!(isWalking.forward || isWalking.backward || isWalking.left || isWalking.right)) return;

  // store previous position of player to check for collision
  const previousPosition = new THREE.Vector3(
    sceneObjects.player.position.x,
    sceneObjects.player.position.y,
    sceneObjects.player.position.z
  );
  let isCollision = false;

  // walk in the direction the player is looking at
  const newPosition = getNewPosition(
    sceneObjects.player.position,
    getCameraLookAt(camera),
    distancePerWalk * deltaTime,
    isWalking
  );
  sceneObjects.player.position.set(newPosition.x, newPosition.y, newPosition.z);

  // check if the player is inside a mesh
  if (collisionDetectionEnabled) {

    let allMeshs = []
    scene.traverse((child) => { allMeshs.push(child) });
    for (let i = 0; i < allMeshs.length; i++) {
      if (
        allMeshs[i] !== sceneObjects.player
        && allMeshs[i].name !== "Scene"
        && allMeshs[i].name !== "Floor"
        && allMeshs[i].name !== "Ground_Material007_0"
        && allMeshs[i].name !== ""
        && checkCollision(sceneObjects.player, allMeshs[i])
      ) {
        isCollision = true;
        break;
      }
    }

    // if the player is inside a mesh, set the position back to the previous position
    if (isCollision === true) {
      sceneObjects.player.position.set(
        previousPosition.x,
        previousPosition.y,
        previousPosition.z
      );
    }

  }

  // update the camera position
  camera.position.set(
    sceneObjects.player.position.x,
    headHeight,
    sceneObjects.player.position.z
  );
}


/**
 * Lets user rotate the camera with the mouse
 */
function initMouseClickMove() {

  renderer.domElement.addEventListener("mousedown", event => {
    isMouseDown = true;
  });

  window.addEventListener("mouseup", event => {
    isMouseDown = false;
    isMouseOnBlackboardBoard1 = false;
    isMouseOnBlackboardBoard2 = false;
  });

  renderer.domElement.addEventListener("mousemove", event => {
    if (!isMouseDown || isMouseOnBlackboardBoard1 || isMouseOnBlackboardBoard2) return;
    isMovingCamera = true;
    camera.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), event.movementX * mouseRotateSpeed * deltaTime);
    camera.rotateOnAxis(new THREE.Vector3(1, 0, 0), event.movementY * mouseRotateSpeed * deltaTime);
  });

  renderer.domElement.addEventListener("wheel", event => {
    const delta = Math.sign(event.deltaY);
    if ((camera.fov + delta * mouseZoomSpeed) < 135 && (camera.fov + delta * mouseZoomSpeed) > 20) {
      camera.fov += delta * mouseZoomSpeed;
      camera.updateProjectionMatrix();
    }
  });

}