Code viewer for World: Test world
// Customise AB run parameters (optional).
// The following parameters can be customised. (They have default values.)

AB.clockTick = 20;    
AB.maxSteps = 65545;    
screenshotStep = 50;   
AB.drawRunControls = false;
threeworld.drawCameraControls = false;

const floorTextureFile = "/uploads/darragh2003/GrassSamp1.jpg";
const skyTexture = "/uploads/darragh2003/sky.jpg";
const treeTexture = "/uploads/darragh2003/tree.glb"
const MOVESPEED = 10;

THREE.PointerLockControls = function (camera) {
    var scope = this;
    camera.rotation.set(0, 0, 0);
    var pitchObject = new THREE.Object3D();
    pitchObject.add(camera);
    var yawObject = new THREE.Object3D();
    yawObject.position.y = 3000;
    yawObject.add(pitchObject);
    var PI_2 = Math.PI / 2;
    var onMouseMove = function (event) {
        if (scope.enabled === false) return;
        var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
        var 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.dispose = function () {
        document.removeEventListener('mousemove', onMouseMove, false);
    };
    document.addEventListener('mousemove', onMouseMove, false);
    this.enabled = false;
    this.getObject = function () {
        return yawObject;
    };
    this.getDirection = function () {
        var direction = new THREE.Vector3(0, 0, -1);
        var rotation = new THREE.Euler(0, 0, 0, 'YXZ');
        return function (v) {
            rotation.set(pitchObject.rotation.x, yawObject.rotation.y, 0);
            v.copy(direction).applyEuler(rotation);
            return v;
        };
    }();
};

function loadModelAndDistribute(modelPath, count, range, groundY) {
    var loader = new THREE.GLTFLoader();
    loader.load(modelPath, function(gltf) {
        for (let i = 0; i < count; i++) {
            var model = gltf.scene.clone();
            var x = Math.random() * range - range / 2;
            var y = groundY;
            var z = Math.random() * range - range / 2;
            model.position.set(x, y, z);
            threeworld.scene.add(model);
        }
    }, undefined, function(error) {
        console.error(error);
    });
}

function World() { 
    var camera, controls;
    var objects = [];
    var raycaster;
    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();

    this.newRun = function() {
        camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
        threeworld.camera = camera;
        threeworld.init3d(0, 0, 0x7ec0ee);
        var light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 0.75);
        light.position.set(0.5, 1, 0.75);
        threeworld.scene.add(light);
        threeworld.scene.fog = new THREE.Fog(0xffffff, 0, 1500);
        controls = new THREE.PointerLockControls(camera);
        threeworld.scene.add(controls.getObject());

        // Set the static sky background
        threeworld.scene.background = new THREE.TextureLoader().load(skyTexture);

        var onKeyDown = function (event) {
            switch (event.keyCode) {
                case 38: case 87: // up
                    moveForward = true;
                    break;
                case 37: case 65: // left
                    moveLeft = true;
                    break;
                case 40: case 83: // down
                    moveBackward = true;
                    break;
                case 39: case 68: // right
                    moveRight = true;
                    break;
                case 32: // space
                    if (canJump === true) velocity.y += 350;
                    canJump = false;
                    break;
            }
        };
        var onKeyUp = function (event) {
            switch(event.keyCode) {
                case 38: case 87: // up
                    moveForward = false;
                    break;
                case 37: case 65: // left
                    moveLeft = false;
                    break;
                case 40: case 83: // down
                    moveBackward = false;
                    break;
                case 39: case 68: // right
                    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);

        var floorGeometry = new THREE.PlaneBufferGeometry(20000, 20000, 1000, 1000);
        floorGeometry.rotateX(- Math.PI / 2);
        var floorTexture = new THREE.TextureLoader().load(floorTextureFile);
        floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
        floorTexture.repeat.set(40, 40);
        var floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture });
        var floor = new THREE.Mesh(floorGeometry, floorMaterial);
        floor.position.set(0, -20, 0);
        threeworld.scene.add(floor);

        // Implementing the pointer lock functionality
        $("#user_span1").html("Use WASD or Arrows to move, mouse to look around and space to jump.");
        var blocker = $("#user_span2");
        blocker.html("<p><b>Click screen to enable mouse controls</b></p>");
        var havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
        if (havePointerLock) {
            var element = document.body;
            var pointerlockchange = function (event) {
                if (document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element) {
                    controls.enabled = true;
                    blocker.html("");
                } else {
                    controls.enabled = false;
                    blocker.html("<p><b>Click screen to enable mouse controls</b></p>");
                }
            };
            var pointerlockerror = function (event) {
                console.error("pointerlockerror");
            };
            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) {
                element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock;
                element.requestPointerLock();
            }, false);
        } else {
            $("#user_span1").html("Your browser doesn't seem to support Pointer Lock API");
        }
    };

    this.nextStep = function() {
        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(moveLeft) - Number(moveRight);
        direction.normalize(); // this ensures consistent movements in all directions
        if (moveForward || moveBackward) velocity.z -= direction.z * 400.0 * MOVESPEED * delta;
        if (moveLeft || moveRight) velocity.x -= direction.x * 400.0 * MOVESPEED * delta;
        if (onObject === true) {
            velocity.y = Math.max(0, velocity.y);
            canJump = true;
        }
        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;
    };
}