-
Notifications
You must be signed in to change notification settings - Fork 0
/
characterControls.js
142 lines (118 loc) · 4.71 KB
/
characterControls.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
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
132
133
134
135
136
137
138
139
140
141
142
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { A, D, DIRECTIONS, S, W } from './utils'
export class CharacterControls {
model: THREE.Group
mixer: THREE.AnimationMixer
animationsMap: Map<string, THREE.AnimationAction> = new Map() // Walk, Run, Idle
orbitControl: OrbitControls
camera: THREE.Camera
// state
toggleRun: boolean = true
currentAction: string
// temporary data
walkDirection = new THREE.Vector3()
rotateAngle = new THREE.Vector3(0, 1, 0)
rotateQuarternion: THREE.Quaternion = new THREE.Quaternion()
cameraTarget = new THREE.Vector3()
// constants
fadeDuration: number = 0.2
runVelocity = 5
walkVelocity = 2
constructor(model: THREE.Group,
mixer: THREE.AnimationMixer, animationsMap: Map<string, THREE.AnimationAction>,
orbitControl: OrbitControls, camera: THREE.Camera,
currentAction: string) {
this.model = model
this.mixer = mixer
this.animationsMap = animationsMap
this.currentAction = currentAction
this.animationsMap.forEach((value, key) => {
if (key == currentAction) {
value.play()
}
})
this.orbitControl = orbitControl
this.camera = camera
this.updateCameraTarget(0,0)
}
public switchRunToggle() {
this.toggleRun = !this.toggleRun
}
public update(delta: number, keysPressed: any) {
const directionPressed = DIRECTIONS.some(key => keysPressed[key] == true)
var play = '';
if (directionPressed && this.toggleRun) {
play = 'Run'
} else if (directionPressed) {
play = 'Walk'
} else {
play = 'Idle'
}
if (this.currentAction != play) {
const toPlay = this.animationsMap.get(play)
const current = this.animationsMap.get(this.currentAction)
current.fadeOut(this.fadeDuration)
toPlay.reset().fadeIn(this.fadeDuration).play();
this.currentAction = play
}
this.mixer.update(delta)
if (this.currentAction == 'Run' || this.currentAction == 'Walk') {
// calculate towards camera direction
var angleYCameraDirection = Math.atan2(
(this.camera.position.x - this.model.position.x),
(this.camera.position.z - this.model.position.z))
// diagonal movement angle offset
var directionOffset = this.directionOffset(keysPressed)
// rotate model
this.rotateQuarternion.setFromAxisAngle(this.rotateAngle, angleYCameraDirection + directionOffset)
this.model.quaternion.rotateTowards(this.rotateQuarternion, 0.2)
// calculate direction
this.camera.getWorldDirection(this.walkDirection)
this.walkDirection.y = 0
this.walkDirection.normalize()
this.walkDirection.applyAxisAngle(this.rotateAngle, directionOffset)
// run/walk velocity
const velocity = this.currentAction == 'Run' ? this.runVelocity : this.walkVelocity
// move model & camera
const moveX = this.walkDirection.x * velocity * delta
const moveZ = this.walkDirection.z * velocity * delta
this.model.position.x += moveX
this.model.position.z += moveZ
this.updateCameraTarget(moveX, moveZ)
}
}
private updateCameraTarget(moveX: number, moveZ: number) {
// move camera
this.camera.position.x += moveX
this.camera.position.z += moveZ
// update camera target
this.cameraTarget.x = this.model.position.x
this.cameraTarget.y = this.model.position.y + 1
this.cameraTarget.z = this.model.position.z
this.orbitControl.target = this.cameraTarget
}
private directionOffset(keysPressed: any) {
var directionOffset = 0 // w
if (keysPressed[W]) {
if (keysPressed[A]) {
directionOffset = Math.PI / 4 // w+a
} else if (keysPressed[D]) {
directionOffset = - Math.PI / 4 // w+d
}
} else if (keysPressed[S]) {
if (keysPressed[A]) {
directionOffset = Math.PI / 4 + Math.PI / 2 // s+a
} else if (keysPressed[D]) {
directionOffset = -Math.PI / 4 - Math.PI / 2 // s+d
} else {
directionOffset = Math.PI // s
}
} else if (keysPressed[A]) {
directionOffset = Math.PI / 2 // a
} else if (keysPressed[D]) {
directionOffset = - Math.PI / 2 // d
}
return directionOffset
}
}