-
Notifications
You must be signed in to change notification settings - Fork 0
/
ThirdPersonCamera.js
106 lines (85 loc) · 3.53 KB
/
ThirdPersonCamera.js
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
class FirstPersonCamera {
constructor(camera, objects) {
this.camera_ = camera;
this.input_ = new InputController();
this.rotation_ = new THREE.Quaternion();
this.translation_ = new THREE.Vector3(0, 2, 0);
this.phi_ = 0;
this.phiSpeed_ = 8;
this.theta_ = 0;
this.thetaSpeed_ = 5;
this.headBobActive_ = false;
this.headBobTimer_ = 0;
this.objects_ = objects;
}
update(timeElapsedS) {
this.updateRotation_(timeElapsedS);
this.updateCamera_(timeElapsedS);
this.updateTranslation_(timeElapsedS);
this.updateHeadBob_(timeElapsedS);
this.input_.update(timeElapsedS);
}
updateCamera_(_) {
this.camera_.quaternion.copy(this.rotation_);
this.camera_.position.copy(this.translation_);
this.camera_.position.y += Math.sin(this.headBobTimer_ * 10) * 1.5;
const forward = new THREE.Vector3(0, 0, -1);
forward.applyQuaternion(this.rotation_);
const dir = forward.clone();
forward.multiplyScalar(100);
forward.add(this.translation_);
let closest = forward;
const result = new THREE.Vector3();
const ray = new THREE.Ray(this.translation_, dir);
for (let i = 0; i < this.objects_.length; ++i) {
if (ray.intersectBox(this.objects_[i], result)) {
if (result.distanceTo(ray.origin) < closest.distanceTo(ray.origin)) {
closest = result.clone();
}
}
}
this.camera_.lookAt(closest);
}
updateHeadBob_(timeElapsedS) {
if (this.headBobActive_) {
const wavelength = Math.PI;
const nextStep = 1 + Math.floor(((this.headBobTimer_ + 0.000001) * 10) / wavelength);
const nextStepTime = nextStep * wavelength / 10;
this.headBobTimer_ = Math.min(this.headBobTimer_ + timeElapsedS, nextStepTime);
if (this.headBobTimer_ == nextStepTime) {
this.headBobActive_ = false;
}
}
}
updateTranslation_(timeElapsedS) {
const forwardVelocity = (this.input_.key(KEYS.w) ? 1 : 0) + (this.input_.key(KEYS.s) ? -1 : 0)
const strafeVelocity = (this.input_.key(KEYS.a) ? 1 : 0) + (this.input_.key(KEYS.d) ? -1 : 0)
const qx = new THREE.Quaternion();
qx.setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.phi_);
const forward = new THREE.Vector3(0, 0, -1);
forward.applyQuaternion(qx);
forward.multiplyScalar(forwardVelocity * timeElapsedS * 10);
const left = new THREE.Vector3(-1, 0, 0);
left.applyQuaternion(qx);
left.multiplyScalar(strafeVelocity * timeElapsedS * 10);
this.translation_.add(forward);
this.translation_.add(left);
if (forwardVelocity != 0 || strafeVelocity != 0) {
this.headBobActive_ = true;
}
}
updateRotation_(timeElapsedS) {
const xh = this.input_.current_.mouseXDelta / window.innerWidth;
const yh = this.input_.current_.mouseYDelta / window.innerHeight;
this.phi_ += -xh * this.phiSpeed_;
this.theta_ = clamp(this.theta_ + -yh * this.thetaSpeed_, -Math.PI / 3, Math.PI / 3);
const qx = new THREE.Quaternion();
qx.setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.phi_);
const qz = new THREE.Quaternion();
qz.setFromAxisAngle(new THREE.Vector3(1, 0, 0), this.theta_);
const q = new THREE.Quaternion();
q.multiply(qx);
q.multiply(qz);
this.rotation_.copy(q);
}
}