-
Notifications
You must be signed in to change notification settings - Fork 0
/
CharacterControls.js
170 lines (155 loc) · 5.43 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import * as THREE from './js/three.module.js'
import * as CANNON from './js/cannon-es.js'
/**
* 封装第三人称类
*/
export class CharacterControls {
constructor(model, mixer, animationsMap, orbitControl, camera, currentAction, model1) {
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.model1 = model1
this.toggleRun = true
// temporary data
this.walkDirection = new THREE.Vector3()
//旋转的轴 y轴
this.rotateAngle = new THREE.Vector3(0, 1, 0)
//四元数
this.rotateQuarternion = new THREE.Quaternion()
this.cameraTarget = new THREE.Vector3()
//动作切换时间
this.fadeDuration = 0.2
//跑步速度
this.runVelocity = 5
//走路速度
this.walkVelocity = 2
this.DIRECTIONS = ['w', 'a', 's', 'd']
}
switchRunToggle() {
this.toggleRun = !this.toggleRun
}
/**
* 计算wasd这4个按键后的旋转角度
* 计算规则:向前w 角度0 w+a 逆时针45° w+d 顺时针45°
* 向后s 角度逆时针180° s+a 逆时针135° s+d 顺时针135°
* 向左a 逆时针90°
* 向右d 顺时针90°
* @param keysPressed
*/
directionOffset(keysPressed) {
var directionOffset = 0 // w
if (keysPressed['w']) {
if (keysPressed['a']) {
directionOffset = Math.PI / 4
} else if (keysPressed['d']) {
directionOffset = -Math.PI / 4
}
} else if (keysPressed['s']) {
if (keysPressed['a']) {
directionOffset = Math.PI / 4 + Math.PI / 2
} else if (keysPressed['d']) {
directionOffset = -Math.PI / 4 - Math.PI / 2
} else {
directionOffset = Math.PI
}
} else if (keysPressed['a']) {
directionOffset = Math.PI / 2
} else if (keysPressed['d']) {
directionOffset = -Math.PI / 2
}
return directionOffset;
}
//动作更新
update(delta, keysPressed) {
//directionPressed 判断是否按下设定好的按键, 有的话为true
const directionPressed = this.DIRECTIONS.some(key => keysPressed[key] == true)
var play = '';
//如果按下 wasd这几个按键, 就改成走路或者跑步状态,否者就是停止状态
if (window.d > 50 || directionPressed && this.toggleRun) {
play = 'Run'
} else if (window.d > 0 || directionPressed) {
play = 'Walk'
} else {
play = 'Idle'
}
if (this.IsPhone()) {
if (window.d > 50) {
play = 'Run'
} else if (window.d > 0) {
play = 'Walk'
} else {
play = 'Idle'
}
} else {
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') {
//1: 先计算 相机和机器人的夹角
var angleYCameraDirection = Math.atan2((this.camera.position.x - this.model.position.x), (this.camera.position.z - this.model.position.z));
//2:然后计算 wasd按键后的旋转角度,写个函数来计算
var directionOffset = this.directionOffset(keysPressed)
if (this.IsPhone()) {
directionOffset = -(window.rad + Math.PI / 2);
}
// rotate model 旋转模型,算出四元数旋转的角度,然后旋转模型
// 从由 axis(轴) 和 angle(角度)所给定的旋转来设置该四元数。改编自 here 所述的方法。假定Axis已被归一化,angle以弧度来表示。
this.rotateQuarternion.setFromAxisAngle(this.rotateAngle, angleYCameraDirection + directionOffset)
//计算机器人旋转起来
// q - 目标四元数 step - 以弧度为单位的角度步长
this.model1.quaternion.rotateTowards(this.rotateQuarternion, 0.2)
//3. 让机器人和相机移动
this.camera.getWorldDirection(this.walkDirection)
this.walkDirection.y = 0
this.walkDirection.normalize()
// axis - 一个被归一化的Vector3。angle - 以弧度表示的角度。
this.walkDirection.applyAxisAngle(this.rotateAngle, directionOffset)
//velocity为机器人速度
const velocity = this.currentAction == 'Run' ? this.runVelocity : this.walkVelocity
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.camera.position.sub(this.orbitControl.target); //减去向量
this.orbitControl.target.copy(this.model.position);
this.camera.position.add(this.model.position);
this.model1.position.copy(this.model.position);
this.model1.position.y = this.model.position.y - 0.95;
this.model.quaternion.setFromAxisAngle(new CANNON.Vec3(-1, 0, 0), 0);
}
IsPhone() {
//获取浏览器navigator对象的userAgent属性(浏览器用于HTTP请求的用户代理头的值)
var info = navigator.userAgent;
//通过正则表达式的test方法判断是否包含“Mobile”字符串
var isPhone = /mobile/i.test(info);
//如果包含“Mobile”(是手机设备)则返回true
return isPhone;
}
}