interstellar / src /Player.js
Pim Schreurs
Modernize the whole codebase; improve rendering
8194362
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)
}
}