2013-12-01 2 views
1

Я работаю над персонажем для контроля над третьим лицом для игры, которую я разрабатываю. Я доволен результатами до сих пор. Элементы управления персонажами имеют множество опрятных функций, таких как: если объект находится перед камерой, он будет двигаться вперед, чтобы вы все еще могли видеть персонажа, однако камера заикается ужасно, когда я поворачиваю ее в сторону, а затем выключает плеер от него. Я загрузил тест на JSFiddle: http://jsfiddle.net/nA8SV/ Я тестировал это только в хроме, и по какой-то причине часть результатов не получает нажатия клавиш, пока вы не нажмете на пустое пространство, граничащее с холстом на этом фрейме.Тройс/Физики Игра MMO Контроль персонажа

[также я начал хром с «--disable-веб-безопасности» игнорировать перекрестное происхождение]

Но как только вы нажмете на страницу ключевые прессы работы. Элементы управления представляют собой модифицированную версию элементов управления орбиты. Таким образом, вы можете щелкнуть левой кнопкой мыши и повернуть вид. Кроме того, вы можете использовать клавиши «Вниз», чтобы перемещаться, и изображение камеры должно возвращаться за игроком, когда вы двигаетесь/вращаетесь.

Приносим извинения за ошибку. Это было очень трудно получить на JSFiddle. (Но ошибка вращения происходит, поэтому она, по крайней мере, воспроизводит это.)

В основном я пытаюсь вернуть свою камеру обратно за свой персонаж, поэтому у меня есть код, который фиксирует поворот на линии 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); 
} 

Thank you !!!

+0

Не забывайте о cannon.js. Легкая реализация, быстрая скорость ... –

ответ

4

Хорошо, я закончил это самостоятельно, но это был очень сложный процесс.

Я потратил так много времени на это. Я попытался начать полностью и в конечном итоге переписал все мои объекты управления по-разному без успеха, на самом деле с этим подходом все стало немного хуже. И я узнал кое-что:

Обновление управления после рендеринга вызывает ужасное заикание (или ухудшает физику заикания). Я должен не обращать внимания на то, где я поставил свою функцию обновления, но это должно быть перед рендерингом.

Я также начал смотреть демоверсии для Physijs, чтобы увидеть, какие настройки они использовали, чтобы добиться чего-то плавного. этот конкретный (http://chandlerprall.github.io/Physijs/examples/body.html)

Я настраивал свои настройки трения и массы, и я начал использовать BoxMesh для пола вместо самолета, что, похоже, помогает с колебаниями.

Наконец я изменил класс управления плеером немного:

вместо прямой камеры на игрока, я начал использовать гироскоп для буфера вращения.

this.camera_anchor_gyro = new THREE.Gyroscope(); 
this.camera_anchor_gyro.add(this.camera); 
this.anchor.add(this.camera_anchor_gyro); 

рядом я хотел повернуть camera_anchor_gyro вместо камеры, чтобы совпасть ротацию, и это стало огромной головной болью, пока я не узнал о: http://en.wikipedia.org/wiki/Gimbal_lock

так я скоро добавил это после того, как гироскоп материала:

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; 
} 

Я обновил свою скрипку http://jsfiddle.net/nA8SV/2/, и это работает намного лучше. но есть еще небольшая проблема заикания, но мне придется продолжать расследование.

Смежные вопросы