Spaces:
Running
Running
| import { | |
| Object3D, | |
| PerspectiveCamera, | |
| Vector3, | |
| Quaternion, | |
| Matrix4, | |
| Ray, | |
| Sphere | |
| } from 'three' | |
| import Simulation from './Simulation' | |
| // For improved performance, we initialize certain variables only once instead of in the step function | |
| const __prevPosition = new Vector3() | |
| const __newVelocity = new Vector3() | |
| const __acceleration = new Vector3() | |
| const __gravityVector = new Vector3() | |
| const __direction = new Vector3() | |
| const __intersection = new Vector3() | |
| const __axis = new Vector3() | |
| const __rotation = new Quaternion() | |
| const __temp = new Vector3() | |
| const __ray = new Ray() | |
| export default class Player { | |
| constructor () { | |
| this.object = new Object3D() | |
| this.eyes = new PerspectiveCamera() | |
| this.object.add(this.eyes) | |
| this.velocity = new Vector3() | |
| this.eyeAngularVelocity = new Vector3() | |
| this.galaxy = 0 | |
| this.controllers = [] | |
| } | |
| lookAt (position) { | |
| // this.object.lookAt makes it look in the exact opposite __direction, for some reason | |
| const lookAtMatrix = new Matrix4() | |
| lookAtMatrix.lookAt(this.object.position, position, this.object.up) | |
| this.object.quaternion.setFromRotationMatrix(lookAtMatrix) | |
| this.object.quaternion.multiply(this.eyes.quaternion.clone().inverse()) | |
| } | |
| addController (controller) { | |
| this.controllers.push(controller) | |
| } | |
| handleInput () { | |
| for (let i = 0; i < this.controllers.length; i++) { | |
| this.controllers[i].update() | |
| } | |
| } | |
| step (delta) { | |
| const wormhole = Simulation.config.wormhole | |
| const wormholeSphere = new Sphere(wormhole.position, wormhole.radius) | |
| if (this.velocity.lengthSq() > 0.00001) { | |
| __prevPosition.copy(this.object.position) | |
| // 1. Compute wormhole curvature/gravity. | |
| __gravityVector.subVectors(wormhole.position, __prevPosition) | |
| const rayDistance = __gravityVector.length() - wormhole.radius * (1 - wormhole.gravityRatio) | |
| const amount = wormhole.gravityRatio / rayDistance | |
| __acceleration.copy(__gravityVector.normalize()).multiplyScalar(wormhole.radius * this.velocity.lengthSq() * amount * amount) | |
| // Apply curvature to velocity | |
| __newVelocity.copy(this.velocity).add(__acceleration.multiplyScalar(delta)) | |
| // Adjust new velocity (keep magnitude of old velocity) | |
| __newVelocity.normalize().multiplyScalar(this.velocity.length()) | |
| // Update the player's position and orientation accordingly | |
| this.object.position.addVectors(__prevPosition, __newVelocity.multiplyScalar(delta)) | |
| this.object.quaternion.multiplyQuaternions( | |
| __rotation.setFromUnitVectors(this.velocity.normalize(), __newVelocity.normalize()), | |
| this.object.quaternion | |
| ) | |
| this.velocity.copy(__newVelocity) | |
| // 2. Check if we're going through the wormhole | |
| __direction.copy(this.velocity).normalize() | |
| __ray.set(__prevPosition, __direction) | |
| const distanceTravelledSq = __direction.subVectors(this.object.position, __prevPosition).lengthSq() | |
| const at = __ray.intersectSphere(wormholeSphere, __intersection) | |
| if (at && at.distanceToSquared(__prevPosition) <= distanceTravelledSq) { | |
| // Rotate 180 degrees around __axis pointing at exit point | |
| __axis.subVectors(__intersection, wormhole.position).normalize() | |
| __rotation.setFromAxisAngle(__axis, Math.PI) | |
| this.object.quaternion.multiplyQuaternions(__rotation, this.object.quaternion) | |
| this.velocity.reflect(__axis).multiplyScalar(-1) | |
| // Set new position a tiny bit outside mirrored __intersection point | |
| this.object.position | |
| .copy(wormhole.position) | |
| .add( | |
| __temp.subVectors(wormhole.position, __intersection) | |
| .multiplyScalar(1.0001) | |
| ) | |
| this.galaxy = 1 - this.galaxy | |
| } | |
| } | |
| __rotation.set( | |
| this.eyeAngularVelocity.x * delta, | |
| this.eyeAngularVelocity.y * delta, | |
| this.eyeAngularVelocity.z * delta, | |
| 1 | |
| ).normalize() | |
| this.eyes.quaternion.multiply(__rotation) | |
| } | |
| update (delta) { | |
| this.handleInput() | |
| this.step(delta) | |
| // Object isn't actually part of a rendered scene, so we need to call this manually | |
| this.object.updateMatrixWorld(true) | |
| } | |
| } | |