Spaces:
Running
Running
File size: 4,205 Bytes
8194362 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
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)
}
}
|