Code viewer for World: Pointer Lock (clone by MEN...

// Cloned by MENGTE ZHU on 7 Nov 2023 from World "Pointer Lock" by Michael Walsh 
// Please leave this clone trail here.
 
// imported from https://threejs.org/examples/misc_controls_pointerlock.html

import * as THREE from '/uploads/mjwalsh/three.module.js';

'use strict';

let camera, scene, renderer, controls;

const objects = [];

let raycaster;

let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let canJump = false;

let prevTime = performance.now();
const velocity = new THREE.Vector3();
const vertex = new THREE.Vector3();
const color = new THREE.Color();

const onKeyDown = function ( event ) {
    switch ( event.code ) {
        case 'ArrowUp':
            moveForward = true;
            break;

        case 'ArrowLeft':
            moveLeft = true;
            break;

        case 'ArrowDown':
            moveBackward = true;
            break;

        case 'ArrowRight':
            moveRight = true;
            break;

        case 'Space':
            if ( canJump === true ) velocity.y += 350;
            canJump = false;
            break;
    }
};

const onKeyUp = function ( event ) {
    switch ( event.code ) {
        case 'ArrowUp':
            moveForward = false;
            break;

        case 'ArrowLeft':
            moveLeft = false;
            break;

        case 'ArrowDown':
            moveBackward = false;
            break;

        case 'ArrowRight':
            moveRight = false;
            break;
    }
};

    document.addEventListener( 'keydown', onKeyDown );
    document.addEventListener( 'keyup', onKeyUp );

function init()
{


    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100000);
    
    camera.position.y = 5;
    camera.position.z = 5;
    camera.position.x = 0;
    
    

    scene = new THREE.Scene();
    scene.background = new THREE.Color( 0xffffff );
    scene.fog = new THREE.Fog( 0xffffff, 0, 750 );

   scene.add(new THREE.AmbientLight(0xffffff, 0.7))

    const dirLight = new THREE.DirectionalLight(0xffffff, 1)
    dirLight.position.set(- 60, 100, - 10);
    dirLight.castShadow = true;
    dirLight.shadow.camera.top = 50;
    dirLight.shadow.camera.bottom = - 50;
    dirLight.shadow.camera.left = - 50;
    dirLight.shadow.camera.right = 50;
    dirLight.shadow.camera.near = 0.1;
    dirLight.shadow.camera.far = 200;
    dirLight.shadow.mapSize.width = 4096;
    dirLight.shadow.mapSize.height = 4096;
    scene.add(dirLight);
    
    controls = new PointerLockControls( camera );

    



    



    raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );

    // floor
    let floorGeometry = new THREE.PlaneGeometry( 2000, 2000, 100, 100 );
    floorGeometry.rotateX( - Math.PI / 2 );

    // vertex displacement
    let position = floorGeometry.attributes.position;

    for ( let i = 0, l = position.count; i < l; i ++ ) {

        vertex.fromBufferAttribute( position, i );

        vertex.x += Math.random() * 20 - 10;
        vertex.y += Math.random() * 2;
        vertex.z += Math.random() * 20 - 10;

        position.setXYZ( i, vertex.x, vertex.y, vertex.z );
    }

    floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices

    position = floorGeometry.attributes.position;
    const colorsFloor = [];

    for ( let i = 0, l = position.count; i < l; i ++ ) {
        color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace );
        colorsFloor.push( color.r, color.g, color.b );
    }

    floorGeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorsFloor, 3 ) );

    const floorMaterial = new THREE.MeshBasicMaterial( { vertexColors: true } );

    const floor = new THREE.Mesh( floorGeometry, floorMaterial );
    scene.add( floor );

    
    //

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

    //

    window.addEventListener( 'resize', onWindowResize );
    
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );
}

function animate() {
    requestAnimationFrame( animate );

    const time = performance.now();

    raycaster.ray.origin.copy( camera.position );
    raycaster.ray.origin.y -= 10;

    const intersections = raycaster.intersectObjects( objects, false );

    const onObject = intersections.length > 0;

    const delta = ( time - prevTime ) / 1000;

    velocity.z -= velocity.z * 10.0 * delta;
    velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass

    const direction = new THREE.Vector3();

    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;

    // we're standing on an object
    if ( onObject === true ) {
        velocity.y = Math.max( 0, velocity.y );
        canJump = true;
    }
    
    // rotate the camera using the left and right arrows
    if ( direction.x != 0 ) {
        camera.rotation.x = 0;
        camera.rotation.y -= direction.x * 0.03;
        camera.rotation.z = 0;
    }

    controls.moveForward( - velocity.z * delta );

    camera.position.y += ( velocity.y * delta ); // new behavior

    if ( camera.position.y < 10 ) {
        velocity.y = 0;
        camera.position.y = 10;

        canJump = true;
    }

    prevTime = time;

    renderer.render( scene, camera );
}

class PointerLockControls extends THREE.EventDispatcher {
    euler = new THREE.Euler( 0, 0, 0, 'YXZ' );
    vector = new THREE.Vector3();

    changeEvent = { type: 'change' };
    lockEvent = { type: 'lock' };
    unlockEvent = { type: 'unlock' };

    PI_2 = Math.PI / 2;

	constructor( camera ) {
		super();

		this.camera = camera;

		// Set to constrain the pitch of the camera
		// Range is 0 to Math.PI radians
		this.minPolarAngle = 0; // radians
		this.maxPolarAngle = Math.PI; // radians

		this.pointerSpeed = 1.0;

		this.connect();
	}

	connect() {
		document.addEventListener( 'pointerlockchange', this.onPointerlockChange );
		document.addEventListener( 'pointerlockerror', this.onPointerlockError );
	}

	disconnect() {
		document.removeEventListener( 'pointerlockchange', this.onPointerlockChange );
		document.removeEventListener( 'pointerlockerror', this.onPointerlockError );
		document.removeEventListener( 'mousemove', this.onMouseMove );
	}

	dispose() {
		this.disconnect();
	}

	getObject() { // retaining this method for backward compatibility
		return this.camera;
	}

	getDirection( v ) {
		return v.set( 0, 0, - 1 ).applyQuaternion( this.camera.quaternion );
	}

	moveForward( distance ) {
		// move forward parallel to the xz-plane
		// assumes camera.up is y-up
		this.vector.setFromMatrixColumn( this.camera.matrix, 0 );
		this.vector.crossVectors( this.camera.up, this.vector );
		this.camera.position.addScaledVector( this.vector, distance );
	}

	moveRight( distance ) {
		this.vector.setFromMatrixColumn( this.camera.matrix, 0 );
		this.camera.position.addScaledVector( this.vector, distance );
	}

	lock() {
		document.body.requestPointerLock();
	}

	unlock() {
		document.exitPointerLock();
	}

    // event listeners
    onMouseMove = (event) => {
        const movementX = event.movementX || 0;
        const movementY = event.movementY || 0;

        this.euler.setFromQuaternion( this.camera.quaternion );

        this.euler.y -= movementX * 0.002 * this.pointerSpeed;
        this.euler.x -= movementY * 0.002 * this.pointerSpeed;

        this.euler.x = Math.max( this.PI_2 - this.maxPolarAngle, Math.min( this.PI_2 - this.minPolarAngle, this.euler.x ) );

        this.camera.quaternion.setFromEuler( this.euler );

        this.dispatchEvent( this.changeEvent );
    };

    onPointerlockChange = () => {
        if ( document.pointerLockElement === document.body ) {
            document.addEventListener( 'mousemove', this.onMouseMove );
            this.dispatchEvent( this.lockEvent );
        } else {
            this.dispatchEvent( this.unlockEvent );
            document.removeEventListener( 'mousemove', this.onMouseMove );
        }
    };

    onPointerlockError = () => {
        console.error( 'THREE.PointerLockControls: Unable to use Pointer Lock API' );
    };
}

init();
animate();