Three.js Threejs/Physijs游戏MMO角色控制

Three.js Threejs/Physijs游戏MMO角色控制,three.js,game-engine,game-physics,physijs,Three.js,Game Engine,Game Physics,Physijs,我正在为我正在开发的游戏开发第三人称角色控制。我对目前的结果很满意。角色控制有很多简洁的功能,比如:如果一个物体在相机前面,它会向前移动,这样你仍然可以看到角色,但是当我把它旋转到一边,然后把我的播放器转离它时,相机会发出可怕的口吃声。我在JSFIDLE上上传了一个测试:我只在chrome上进行了测试,出于某种原因,结果部分在点击框架上画布边缘的空白区域之前不会得到按键 [我也是用--disable web security”启动chrome的,以忽略跨源代码] 但是一旦你点击了页面,按键就起作

我正在为我正在开发的游戏开发第三人称角色控制。我对目前的结果很满意。角色控制有很多简洁的功能,比如:如果一个物体在相机前面,它会向前移动,这样你仍然可以看到角色,但是当我把它旋转到一边,然后把我的播放器转离它时,相机会发出可怕的口吃声。我在JSFIDLE上上传了一个测试:我只在chrome上进行了测试,出于某种原因,结果部分在点击框架上画布边缘的空白区域之前不会得到按键

[我也是用--disable web security”启动chrome的,以忽略跨源代码]

但是一旦你点击了页面,按键就起作用了。这些控制装置是轨道控制装置的改进版本。因此,可以单击鼠标左键并旋转视图。此外,您还可以使用wasd键四处移动,当您移动/旋转时,相机视图应回到播放器后面

我为这一问题道歉,因为在JSFIDLE上工作非常困难。 (但旋转错误正在发生,所以它至少复制了这种情况。)

基本上,我试图让我的相机旋转回到我的角色后面,所以我有一些代码来修复第250行的旋转,但是随着角色的移动,相机会结巴

以下是我的理论,我认为相机的整体抖动与物理模拟有一定关系,可以使玩家稍微弹跳一下,但我不确定该怎么解决这个问题,如果有任何帮助,我们将不胜感激

下面是完整性代码,但我建议使用JSFiddle链接,我更容易看到它工作

THREE.PlayerControls = function (anchor, scene, player, camera, domElement) {

this.walking = false;
this.occ = false;
this.scene = scene;
this.occLastZoom = 0;
this.jumpRelease = true;
this.jumping = false;
this.falling = false;
this.moving = false;
this.turning = false;
this.anchor = anchor;
this.player = player;
this.camera = camera;
this.camera.position.set(0, 8.25, -20);
this.domElement = (domElement !== undefined) ? domElement : document;

this.anchor.add(this.camera);

// API
this.enabled = true;

this.center = new THREE.Vector3(0, 4, 0);

this.userZoom = true;
this.userZoomSpeed = 2.0;

this.userRotate = true;
this.userRotateSpeed = 1.0;

this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians

this.minDistance = 2;
this.maxDistance = 30;

this.keys = {
    LEFT: 65,
    STRAFFLEFT: 81,
    UP: 87,
    RIGHT: 68,
    STRAFFRIGHT: 69,
    DOWN: 83,
    JUMP: 32,
    SLASH: 191
};

// internals
var scope = this;

var EPS = 0.000001;
var PIXELS_PER_ROUND = 1800;

var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();

var zoomStart = new THREE.Vector2();
var zoomEnd = new THREE.Vector2();
var zoomDelta = new THREE.Vector2();

var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;

var lastPosition = new THREE.Vector3();

var STATE = {
    NONE: -1,
    ROTATE: 0,
    ZOOM: 1
};
var state = STATE.NONE;
var key_state = [];

// events
var changeEvent = {
    type: 'change'
};


this.rotateLeft = function (angle) {
    thetaDelta -= angle;
};

this.rotateRight = function (angle) {
    thetaDelta += angle;
};

this.rotateUp = function (angle) {
    phiDelta -= angle;
};

this.rotateDown = function (angle) {
    phiDelta += angle;
};

this.zoomIn = function (zoomScale) {
    if (zoomScale === undefined) {
        zoomScale = getZoomScale();
    }
    scale /= zoomScale;
};

this.zoomOut = function (zoomScale) {
    if (zoomScale === undefined) {
        zoomScale = getZoomScale();
    }
    scale *= zoomScale;
};

this.update = function (delta) {
    // detect falling
    if (this.scene.children.length > 0) {
        var originPoint = this.anchor.position.clone();
        var ray = new THREE.Raycaster(originPoint, new THREE.Vector3(0, -1, 0));
        var collisionResults = ray.intersectObjects(this.scene.children.filter(function (child) {
            return child.occ;
        }));
        if (collisionResults.length > 0) {
            if (collisionResults[0].distance < 1.25 && this.falling) {
                this.falling = false;
                this.jumping = false;
            } else if (collisionResults[0].distance > 2 + (this.jumping ? 1 : 0) && !this.falling) {
                this.falling = true;
            }
        }
    }

    // handle movement
    if (!this.falling) {
        if (key_state.indexOf(this.keys.JUMP) > -1 && this.jumpRelease && !this.jumping) {
            // jump
            var lv = this.anchor.getLinearVelocity();
            this.anchor.setLinearVelocity(new THREE.Vector3(lv.x, 15, lv.z));
            this.jumpRelease = false;
            this.jumping = true;
            //jump
        } else if (!this.jumping) {
            // move
            if (key_state.indexOf(this.keys.UP) > -1) {

                var rotation_matrix = new THREE.Matrix4().extractRotation(this.anchor.matrix);

                var speed = this.walking ? 2.5 : 10;
                var force_vector;

                // straffing?
                if (key_state.indexOf(this.keys.STRAFFLEFT) > -1 && key_state.indexOf(this.keys.STRAFFRIGHT) < 0) {
                    force_vector = new THREE.Vector3((2 * speed / 3), 0, (2 * speed / 3)).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, Math.PI / 4, 0);
                } else if (key_state.indexOf(this.keys.STRAFFRIGHT) > -1) {
                    force_vector = new THREE.Vector3((-2 * speed / 3), 0, (2 * speed / 3)).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, -Math.PI / 4, 0);
                } else {
                    force_vector = new THREE.Vector3(0, 0, speed).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, 0, 0);
                }

                this.anchor.setLinearVelocity(force_vector);
                this.moving = true;

                // forward
            } else if (key_state.indexOf(this.keys.DOWN) > -1) {
                var rotation_matrix = new THREE.Matrix4().extractRotation(this.anchor.matrix);

                var speed = this.walking ? -2.5 : -5;
                var force_vector;

                // straffing?
                if (key_state.indexOf(this.keys.STRAFFLEFT) > -1 && key_state.indexOf(this.keys.STRAFFRIGHT) < 0) {
                    force_vector = new THREE.Vector3((-2 * speed / 3), 0, (2 * speed / 3)).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, -Math.PI / 4, 0);
                } else if (key_state.indexOf(this.keys.STRAFFRIGHT) > -1) {
                    force_vector = new THREE.Vector3((2 * speed / 3), 0, (2 * speed / 3)).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, Math.PI / 4, 0);
                } else {
                    force_vector = new THREE.Vector3(0, 0, speed).applyMatrix4(rotation_matrix);
                    this.player.rotation.set(0, 0, 0);
                }

                this.anchor.setLinearVelocity(force_vector);
                this.moving = true;

                //back
            } else if (key_state.indexOf(this.keys.STRAFFLEFT) > -1) {
                var rotation_matrix = new THREE.Matrix4().extractRotation(this.anchor.matrix);

                var speed = this.walking ? 2.5 : 10;
                var force_vector = new THREE.Vector3(speed, 0, 0).applyMatrix4(rotation_matrix);
                this.player.rotation.set(0, Math.PI / 2, 0);

                this.anchor.setLinearVelocity(force_vector);
                this.moving = true;

                //straff
            } else if (key_state.indexOf(this.keys.STRAFFRIGHT) > -1) {
                var rotation_matrix = new THREE.Matrix4().extractRotation(this.anchor.matrix);

                var speed = this.walking ? 2.5 : 10;
                var force_vector = new THREE.Vector3(-speed, 0, 0).applyMatrix4(rotation_matrix);
                this.player.rotation.set(0, -Math.PI / 2, 0);

                this.anchor.setLinearVelocity(force_vector);
                this.moving = true;

                //straff
            } else if (this.moving) {
                this.player.rotation.set(0, 0, 0);
                this.anchor.setLinearVelocity(new THREE.Vector3(0, 0, 0));
                this.moving = false;
            }

            //turn
            if (key_state.indexOf(this.keys.LEFT) > -1 && key_state.indexOf(this.keys.RIGHT) < 0) {
                this.anchor.setAngularVelocity(new THREE.Vector3(0, 1.5, 0));
                this.turning = true;
                //turning
            } else if (key_state.indexOf(this.keys.RIGHT) > -1) {
                this.anchor.setAngularVelocity(new THREE.Vector3(0, -1.5, 0));
                this.turning = true;
                //turning
            } else if (this.turning) {
                this.anchor.setAngularVelocity(new THREE.Vector3(0, 0, 0));
                this.turning = false;
            }

            //idle
        }

        if (key_state.indexOf(this.keys.JUMP) == -1) {
            this.jumpRelease = true;
        }
    } else {
        //falling
    }

    var position = this.camera.position;
    var offset = position.clone().sub(this.center);

    // angle from z-axis around y-axis
    var theta = Math.atan2(offset.x, offset.z);

    // angle from y-axis
    var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y);

    theta += thetaDelta;
    phi += phiDelta;

    if ((this.moving || this.turning) && state != STATE.ROTATE) {
        // fix camera rotation
        if (theta < 0) theta -= Math.max(delta, (-1 * Math.PI) + theta);
        else theta += Math.min(delta, Math.PI - theta);

        // fix pitch (should be an option or it could get anoying)
        //phi = 9*Math.PI/24;
    }

    // restrict phi to be between desired limits
    phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi));

    // restrict phi to be betwee EPS and PI-EPS
    phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));

    var radius;
    if (this.occ) {
        this.occLastZoom = Math.max(this.minDistance, Math.min(this.maxDistance, this.occLastZoom * scale));
        radius = this.occLastZoom;
    } else {
        radius = offset.length() * scale;
    }

    // restrict radius to be between desired limits
    radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius));

    // check for objects infront of camera
    var projector = new THREE.Projector();
    var vector = new THREE.Vector3(0, 0, 1);
    projector.unprojectVector(vector, camera);
    var point = new THREE.Vector3(this.anchor.position.x + this.center.x, this.anchor.position.y + this.center.y, this.anchor.position.z + this.center.z);
    var vec = camera.position.clone().sub(vector).normalize()

    var checkray = new THREE.Raycaster(point, vec, this.minDistance, this.maxDistance);
    var checkcollisionResults = checkray.intersectObjects(this.scene.children.filter(function (child) {
        return child.occ;
    }));
    if (checkcollisionResults.length > 0) {
        var min = radius;
        for (var i = 0; i < checkcollisionResults.length; i++) {
            if (min > checkcollisionResults[i].distance) min = checkcollisionResults[i].distance;
        }
        if (min < radius) {
            if (!this.occ) {
                this.occ = true;
                this.occLastZoom = radius;
            }
            radius = min;
        } else {
            this.occ = false;
        }
    }

    offset.x = radius * Math.sin(phi) * Math.sin(theta);
    offset.y = radius * Math.cos(phi);
    offset.z = radius * Math.sin(phi) * Math.cos(theta);

    if (radius < 5) {
        this.player.material.opacity = Math.max(0, radius / 5.0);
        this.center.y = 4 + ((5 - radius) / 2.5);
    } else {
        if (this.player.material.opacity != 1.0) {
            this.player.material.opacity = 1.0;
            this.center.y = 4;
        }
    }

    position.copy(this.center).add(offset);
    this.camera.lookAt(this.center);

    thetaDelta = 0;
    phiDelta = 0;
    scale = 1;

    if (lastPosition.distanceTo(this.camera.position) > 0) {
        this.dispatchEvent(changeEvent);
        lastPosition.copy(this.camera.position);
    }
};

function roundTothree(num) {
    return +(Math.round(num + "e+3") + "e-3");
}

function getZoomScale() {
    return Math.pow(0.95, scope.userZoomSpeed);
}

function onMouseDown(event) {
    if (scope.enabled === false) return;
    if (scope.userRotate === false) return;

    event.preventDefault();

    if (state === STATE.NONE) {
        if (event.button === 0) state = STATE.ROTATE;
    }

    if (state === STATE.ROTATE) {
        rotateStart.set(event.clientX, event.clientY);
    }

    document.addEventListener('mousemove', onMouseMove, false);
    document.addEventListener('mouseup', onMouseUp, false);
}

function onMouseMove(event) {
    if (scope.enabled === false) return;
    event.preventDefault();

    if (state === STATE.ROTATE) {
        rotateEnd.set(event.clientX, event.clientY);
        rotateDelta.subVectors(rotateEnd, rotateStart);
        scope.rotateLeft(2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed);
        scope.rotateUp(2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed);
        rotateStart.copy(rotateEnd);
    } else if (state === STATE.ZOOM) {
        zoomEnd.set(event.clientX, event.clientY);
        zoomDelta.subVectors(zoomEnd, zoomStart);
        if (zoomDelta.y > 0) {
            scope.zoomIn();
        } else {
            scope.zoomOut();
        }
        zoomStart.copy(zoomEnd);
    }
}

function onMouseUp(event) {
    if (scope.enabled === false) return;
    if (scope.userRotate === false) return;

    document.removeEventListener('mousemove', onMouseMove, false);
    document.removeEventListener('mouseup', onMouseUp, false);

    state = STATE.NONE;
}

function onMouseWheel(event) {
    if (scope.enabled === false) return;
    if (scope.userZoom === false) return;

    var delta = 0;

    if (event.wheelDelta) { // WebKit / Opera / Explorer 9
        delta = event.wheelDelta;
    } else if (event.detail) { // Firefox
        delta = -event.detail;
    }

    if (delta > 0) {
        scope.zoomOut();
    } else {
        scope.zoomIn();
    }
}

function onKeyDown(event) {
    console.log('onKeyDown')
    if (scope.enabled === false) return;
    switch (event.keyCode) {
        case scope.keys.UP:
            var index = key_state.indexOf(scope.keys.UP);
            if (index == -1) key_state.push(scope.keys.UP);
            break;
        case scope.keys.DOWN:
            var index = key_state.indexOf(scope.keys.DOWN);
            if (index == -1) key_state.push(scope.keys.DOWN);
            break;
        case scope.keys.LEFT:
            var index = key_state.indexOf(scope.keys.LEFT);
            if (index == -1) key_state.push(scope.keys.LEFT);
            break;
        case scope.keys.STRAFFLEFT:
            var index = key_state.indexOf(scope.keys.STRAFFLEFT);
            if (index == -1) key_state.push(scope.keys.STRAFFLEFT);
            break;
        case scope.keys.RIGHT:
            var index = key_state.indexOf(scope.keys.RIGHT);
            if (index == -1) key_state.push(scope.keys.RIGHT);
            break;
        case scope.keys.STRAFFRIGHT:
            var index = key_state.indexOf(scope.keys.STRAFFRIGHT);
            if (index == -1) key_state.push(scope.keys.STRAFFRIGHT);
            break;
        case scope.keys.JUMP:
            var index = key_state.indexOf(scope.keys.JUMP);
            if (index == -1) key_state.push(scope.keys.JUMP);
            break;
    }
}

function onKeyUp(event) {
    switch (event.keyCode) {
        case scope.keys.UP:
            var index = key_state.indexOf(scope.keys.UP);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.DOWN:
            var index = key_state.indexOf(scope.keys.DOWN);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.LEFT:
            var index = key_state.indexOf(scope.keys.LEFT);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.STRAFFLEFT:
            var index = key_state.indexOf(scope.keys.STRAFFLEFT);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.RIGHT:
            var index = key_state.indexOf(scope.keys.RIGHT);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.STRAFFRIGHT:
            var index = key_state.indexOf(scope.keys.STRAFFRIGHT);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.JUMP:
            var index = key_state.indexOf(scope.keys.JUMP);
            if (index > -1) key_state.splice(index, 1);
            break;
        case scope.keys.SLASH:
            scope.walking = !scope.walking;
            break;

    }
}

this.domElement.addEventListener('contextmenu', function (event) {
    event.preventDefault();
}, false);
this.domElement.addEventListener('mousedown', onMouseDown, false);
this.domElement.addEventListener('mousewheel', onMouseWheel, false);
this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
window.addEventListener('keydown', onKeyDown, false);
window.addEventListener('keyup', onKeyUp, false);
};

THREE.PlayerControls.prototype = Object.create(THREE.EventDispatcher.prototype);


// end player controlls
Physijs.scripts.worker = 'https://rawgithub.com/chandlerprall/Physijs/master/physijs_worker.js';
Physijs.scripts.ammo = 'http://chandlerprall.github.io/Physijs/examples/js/ammo.js';

// standard global variables
var container, scene, camera, renderer, controls;
//var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();

// MAIN //
window.onload = function() {
console.log('loaded')

// SCENE //
scene = new Physijs.Scene();
scene.setGravity(new THREE.Vector3(0, -32, 0));
scene.addEventListener(
    'update',

function () {
    scene.simulate();
});

// CAMERA //
var SCREEN_WIDTH = window.innerWidth,
    SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45,
    ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT,
    NEAR = 1,
    FAR = 1000;
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);

// RENDERER //
renderer = new THREE.WebGLRenderer({
    antialias: true
});
renderer.shadowMapEnabled = true;
// to antialias the shadow
renderer.shadowMapSoft = true;

renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

container = document.getElementById('container');
container.appendChild(renderer.domElement);

// EVENTS //
//THREEx.WindowResize(renderer, camera);

// LIGHT //
var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
hemiLight.color.setHSL(0.6, 1, 0.6);
hemiLight.groundColor.setHSL(0.095, 1, 0.75);
hemiLight.position.set(0, 500, 0);
scene.add(hemiLight);

var light = new THREE.DirectionalLight(0xffffff, 1);
light.color.setHSL(0.1, 1, 0.95);
light.position.set(-1, 1.75, 1);
light.position.multiplyScalar(50);
light.castShadow = true;
light.shadowMapWidth = 2048;
light.shadowMapHeight = 2048;
light.shadowDarkness = 0.5;
var d = 50;
light.shadowCameraLeft = -d;
light.shadowCameraRight = d;
light.shadowCameraTop = d;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 3500;
light.shadowBias = -0.0001;
light.shadowDarkness = 0.35;
scene.add(light);

// GEOMETRY //
var checkerboard = new THREE.ImageUtils.loadTexture('http://www.cns.nyu.edu/lcv/texture/artificial-periodic/checkerboard.o.jpg');
checkerboard.wrapS = checkerboard.wrapT = THREE.RepeatWrapping;
checkerboard.repeat.set(4, 4);

var checkerboard2 = new THREE.ImageUtils.loadTexture('http://www.cns.nyu.edu/lcv/texture/artificial-periodic/checkerboard.o.jpg');

var cubeMaterial = Physijs.createMaterial(
new THREE.MeshLambertMaterial({
    map: checkerboard2
}),
1.0, // high friction
0.0 // low restitution
);
var cubeGeometry = new THREE.CubeGeometry(10, 5, 10, 1, 1, 1);
var cube = new Physijs.BoxMesh(
cubeGeometry,
cubeMaterial,
1);

cube.position.set(-10, 1, -10);
cube.castShadow = true;
cube.receiveShadow = true;
cube.occ = true;
scene.add(cube);


var cubeMaterial2 = Physijs.createMaterial(
new THREE.MeshLambertMaterial({
    map: checkerboard2
}),
1.0, // high friction
0.0 // low restitution
);
var cubeGeometry2 = new THREE.CubeGeometry(10, 5, 10, 1, 1, 1);
var cube2 = new Physijs.BoxMesh(
cubeGeometry2,
cubeMaterial2,
1);

cube2.position.set(-10, 7, -1);
cube2.castShadow = true;
cube2.receiveShadow = true;
cube2.occ = true;
scene.add(cube2);

var cubeMaterial3 = Physijs.createMaterial(
new THREE.MeshLambertMaterial({
    map: checkerboard2
}),
1.0, // high friction
0.0 // low restitution
);
var cubeGeometry3 = new THREE.CubeGeometry(10, 5, 10, 1, 1, 1);
var cube3 = new Physijs.BoxMesh(
cubeGeometry3,
cubeMaterial3,
1);

cube3.position.set(-10, 13, 8);
cube3.castShadow = true;
cube3.receiveShadow = true;
cube3.occ = true;
scene.add(cube3);

var cone = new Physijs.ConeMesh(
new THREE.CylinderGeometry(0, 5, 4, 30, 30, true),
Physijs.createMaterial(
new THREE.MeshLambertMaterial({
    map: checkerboard2
}),
1.0, // high friction
0.0 // low restitution
),
0);
cone.position.set(0, 2, 0);
scene.castShadow = true;
scene.receiveShadow = true;
cone.occ = true;
scene.add(cone);


// FLOOR //
var floorMaterial = new THREE.MeshLambertMaterial({
    map: checkerboard
});
var floorGeometry = new THREE.PlaneGeometry(100, 100, 1, 1);
var floor = new Physijs.PlaneMesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.castShadow = false;
floor.receiveShadow = true;
floor.occ = true;
scene.add(floor);

// SKY //
var skyBoxGeometry = new THREE.CubeGeometry( 1000, 1000, 1000 );
var skyBox = new THREE.Mesh(skyBoxGeometry, new THREE.MeshLambertMaterial({
    color: '#3333bb'
}));
scene.add(skyBox);

// fog must be added to scene before first render
scene.fog = new THREE.FogExp2(0x999999, 0.001);


var bounding = new Physijs.SphereMesh(
new THREE.SphereGeometry(0.75, 4, 4),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({
    color: '#ff0000'
}),
1.0, // high friction
0.0 // low restitution
),
0.1);

var player = new THREE.Mesh(
new THREE.CubeGeometry(1, 6, 1, 1, 1, 1),
new THREE.MeshLambertMaterial({
    color: '#00ff00'
}),
1);
player.position.set(0, 3, 0);

bounding.position.set(10, 0.75, -10);
bounding.add(player);

scene.add(bounding);
bounding.setAngularFactor(new THREE.Vector3(0, 0, 0));
controls = new THREE.PlayerControls(bounding, scene, player, camera, renderer.domElement);

// animation loop / game loop
scene.simulate();
animate();
};

function animate() {
requestAnimationFrame(animate);
render();
update();
}

function update() {
// delta = change in time since last call (in seconds)
var delta = clock.getDelta();
THREE.AnimationHandler.update(delta);
if (controls) controls.update(delta);
}

function render() {
    renderer.render(scene, camera);
}
THREE.playerControl=功能(锚定、场景、播放器、相机、DomeElement){
这是错误的;
this.occ=假;
这个场景=场景;
这个.oczoom=0;
this.jumpRelease=true;
这个跳跃=错误;
这是错误的;
this.moving=false;
这是错误的;
this.anchor=锚;
this.player=player;
这个。照相机=照相机;
本相机位置设置(0,8.25,-20);
this.domElement=(domElement!==未定义)?domElement:文档;
this.anchor.add(this.camera);
//原料药
this.enabled=true;
this.center=新的三个向量3(0,4,0);
this.userZoom=true;
this.userZoomSpeed=2.0;
this.userRotate=true;
this.userRotateSpeed=1.0;
this.minPolarAngle=0;//弧度
this.maxPolarAngle=Math.PI;//弧度
这个。MindDistance=2;
这个.maxDistance=30;
此参数为0.keys={
左:65,
扫射:81,
上升:87,
右:68,
斯特拉夫赖特:69,
下降:83,
跳跃:32,
斜杠:191
};
//内部构件
var范围=此;
var EPS=0.000001;
每轮可变像素=1800;
var rotateStart=new THREE.Vector2();
var rotateEnd=new THREE.Vector2();
var rotateDelta=new THREE.Vector2();
var zoomStart=new THREE.Vector2();
var zoomEnd=new THREE.Vector2();
var zoomDelta=new THREE.Vector2();
var-phiDelta=0;
var thetaDelta=0;
var量表=1;
var lastPosition=new THREE.Vector3();
变量状态={
无:-1,
旋转:0,
缩放:1
};
var state=state.NONE;
var key_state=[];
//事件
var changeEvent={
键入:“更改”
};
this.rotateLeft=函数(角度){
thetaDelta-=角度;
};
this.rotateRight=函数(角度){
thetaDelta+=角度;
};
this.rotateUp=函数(角度){
φδ-=角度;
};
this.rotateDown=函数(角度){
φδ+=角度;
};
this.zoomIn=函数(zoomScale){
如果(缩放===未定义){
zoomScale=getZoomScale();
}
比例/=动物比例;
};
this.zoomOut=函数(zoomScale){
如果(缩放===未定义){
zoomScale=getZoomScale();
}
比例*=动物比例;
};
this.update=函数(增量){
//探测坠落
如果(this.scene.children.length>0){
var originPoint=this.anchor.position.clone();
var ray=新三点光线投射器(原点,新三点矢量3(0,-1,0));
var collisionResults=ray.intersectObjects(this.scene.children.filter)(函数(child)){
返回child.occ;
}));
如果(collisionResults.length>0){
if(碰撞结果[0]。距离<1.25&&this.falling){
这是错误的;
这个跳跃=错误;
}else if(碰撞结果[0]。距离>2+(this.jumping?1:0)和&!this.falling){
这是真的;
}
}
}
//手柄运动
如果(!这个,掉下去){
if(key_state.indexOf(this.keys.JUMP)>-1和this.jumpRelease和this.jumping){
//跳跃
var lv=this.anchor.getLinearVelocity();
this.anchor.setLinearVelocity(新的3.Vector3(lv.x,15,lv.z));
this.jumpRelease=false;
这是真的;
//跳跃
}否则,如果(!这个。跳跃){
//移动
if(key_state.indexOf(this.keys.UP)>-1){
var rotation_matrix=new THREE.Matrix4().extractRotation(this.anchor.matrix);
var速度=这个。步行?2.5:10;
var-force_向量;
//扫射?
if(key\u state.indexOf(this.keys.STRAFFLEFT)>-1&&key\u state.indexOf(this.keys.STRAFFRIGHT)<0){
力向量=新的三个。向量3((2*速度/3),0,(2*速度/3))。应用矩阵X4(旋转矩阵);
this.player.rotation.set(0,Math.PI/4,0);
}else if(key_state.indexOf(this.keys.STRAFFRIGHT)>-1){
力矢量=新的三个。矢量3((-2*速度/3),0,(2*速度/3))。应用矩阵X4(旋转矩阵);
this.player.rotation.set(0,-Math.PI/4,0);
}否则{
力向量=新的三个。向量3(0,0,速度)。应用矩阵X4(旋转矩阵);
这个.player.rotation.set(0,0,0);
}
this.anchor.setLinearVelocity(力向量);
这个,移动=
this.camera_anchor_gyro = new THREE.Gyroscope();
this.camera_anchor_gyro.add(this.camera);
this.anchor.add(this.camera_anchor_gyro);
this.anchor.rotation.order = "YXZ";
this.camera_anchor_gyro.rotation.order = "YXZ";
this.camera.rotation.order = "YXZ";
if ((this.moving || this.turning) && state != STATE.ROTATE) {
    var curr_rot = new THREE.Euler(0, 0, 0, "YXZ").setFromRotationMatrix(this.camera.matrixWorld).y;
    var dest_rot = new THREE.Euler(0, 0, 0, "YXZ").setFromRotationMatrix(this.anchor.matrixWorld).y;
    var dest_rot = dest_rot + (dest_rot > 0 ? -Math.PI : Math.PI);
    var step = shortestArc(curr_rot,dest_rot)*delta*2;
    this.camera_anchor_gyro.rotation.y += step;//Math.max(-delta, diff);

    // fix pitch (should be an option or it could get anoying)
    //phi = 9*Math.PI/24;
}