@soonspacejs/plugin-patrol-controls 2.13.7 → 2.13.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
- # @soonspacejs/plugin-patrol-controls
2
-
3
- > Patrol-controls plugin for SoonSpace.js
4
-
5
- Document: [http://www.xwbuilders.com:8800/plugin/patrol-controls.html](http://www.xwbuilders.com:8800/plugin/patrol-controls.html)
1
+ # @soonspacejs/plugin-patrol-controls
2
+
3
+ > Patrol-controls plugin for SoonSpace.js
4
+
5
+ Document: [http://www.xwbuilders.com:8800/plugin/patrol-controls.html](http://www.xwbuilders.com:8800/plugin/patrol-controls.html)
@@ -0,0 +1,121 @@
1
+ import { PerspectiveCamera, OrthographicCamera } from 'three';
2
+ import SoonSpace from 'soonspacejs';
3
+ import type { CameraViewpointData, Position } from 'soonspacejs';
4
+ import type { Node } from 'soonspacejs';
5
+ import type { Topology } from 'soonspacejs';
6
+ import type { Tween } from 'three/examples/jsm/libs/tween.module.js';
7
+ export type ProgressParams = {
8
+ patrolled: number;
9
+ total: number;
10
+ percent: number;
11
+ };
12
+ export interface DefaultOptions {
13
+ eyeHeight: number;
14
+ /**
15
+ * 巡检速度
16
+ */
17
+ naviSpeed: number;
18
+ /**
19
+ * 相机转向速度
20
+ */
21
+ rotateSpeed: number;
22
+ /**
23
+ * 是否飞向起始点位置
24
+ */
25
+ flyToStartPoint: boolean;
26
+ /**
27
+ * 更新回调
28
+ */
29
+ onUpdate: (realTimePosition: Position, nextNode: Node, toNextNodeDistance: number) => void;
30
+ /**
31
+ * 巡检进度
32
+ */
33
+ onProgress: (params: ProgressParams) => void;
34
+ /**
35
+ * 结束回调
36
+ */
37
+ onEnd: (endPosition: Position) => void;
38
+ }
39
+ export type StartOptions = Partial<DefaultOptions>;
40
+ export type ResetOptions = Pick<StartOptions, 'eyeHeight' | 'naviSpeed' | 'rotateSpeed'>;
41
+ export default class PatrolControlsPlugin {
42
+ readonly ssp: SoonSpace;
43
+ camera: PerspectiveCamera | OrthographicCamera;
44
+ options: DefaultOptions;
45
+ states: {
46
+ moveDuration: number;
47
+ rotateDuration: number;
48
+ };
49
+ nodes: Node[];
50
+ nextPointIndex: number;
51
+ /**
52
+ * y 轴加上 eyeHeight 的节点之间距离
53
+ */
54
+ _nodeDistances: number[];
55
+ _totalDistance: number;
56
+ /**
57
+ * 0 - 1
58
+ */
59
+ _updatePercent: number;
60
+ _needsUpdateProgress: boolean;
61
+ isPaused: boolean;
62
+ isStoped: boolean;
63
+ _positionTween: Tween<{
64
+ distance: number;
65
+ }> | null;
66
+ _rotationTween: Tween<{
67
+ t: number;
68
+ }> | null;
69
+ _cameraViewpointData: CameraViewpointData | null;
70
+ constructor(ssp: SoonSpace);
71
+ /**
72
+ * 开始巡检
73
+ *
74
+ * @param path
75
+ * @param options
76
+ */
77
+ start(path: Topology, options: StartOptions): void;
78
+ /**
79
+ * 设置巡检进度
80
+ * @param percent 0 - 1(不包含 1)
81
+ */
82
+ setProgress(percent: number): void;
83
+ /**
84
+ * 设置巡检参数
85
+ * @param options
86
+ * @returns
87
+ */
88
+ setOptions(options: ResetOptions): void;
89
+ /**
90
+ * 暂停巡检
91
+ */
92
+ pause(): void;
93
+ /**
94
+ * 恢复巡检
95
+ */
96
+ resume(): void;
97
+ /**
98
+ * 中断巡检
99
+ */
100
+ stop(): void;
101
+ private init;
102
+ private initOptions;
103
+ /**
104
+ * 计算两点之间的弧度
105
+ * @param sourcePoint
106
+ * @param targetPoint
107
+ * @returns
108
+ */
109
+ private computedRotation;
110
+ /**
111
+ * 计算下一弧度
112
+ * @returns
113
+ */
114
+ private computeNextRotation;
115
+ /**
116
+ * 开始巡检
117
+ * @returns
118
+ */
119
+ private patrolStart;
120
+ private patrolStop;
121
+ }
package/dist/index.esm.js CHANGED
@@ -1,357 +1 @@
1
- import { Vector3, Matrix4, Quaternion } from 'three';
2
-
3
- const EPS = 1e-5;
4
- class PatrolControlsPlugin {
5
- constructor(ssp) {
6
- this.ssp = ssp;
7
- this.options = {
8
- naviSpeed: 1,
9
- rotateSpeed: 1,
10
- eyeHeight: 150,
11
- flyToStartPoint: true,
12
- onUpdate: () => { },
13
- onProgress: () => { },
14
- onEnd: () => { },
15
- };
16
- this.states = {
17
- moveDuration: 0,
18
- rotateDuration: 0,
19
- };
20
- // 路径节点列表
21
- this.nodes = [];
22
- this.nextPointIndex = 0;
23
- /**
24
- * y 轴加上 eyeHeight 的节点之间距离
25
- */
26
- this._nodeDistances = [];
27
- this._totalDistance = 0;
28
- /**
29
- * 0 - 1
30
- */
31
- this._updatePercent = 0;
32
- this._needsUpdateProgress = false;
33
- this.isPaused = false;
34
- this.isStoped = true;
35
- this._positionTween = null;
36
- this._rotationTween = null;
37
- this._cameraViewpointData = null;
38
- const { cameraManager, } = this.ssp.viewport;
39
- this.camera = cameraManager.mainCamera;
40
- }
41
- /**
42
- * 开始巡检
43
- *
44
- * @param path
45
- * @param options
46
- */
47
- start(path, options) {
48
- if (!this.isStoped) {
49
- this.ssp.utils.warn('巡检已经开始!');
50
- return;
51
- }
52
- this.ssp.controls.saveState();
53
- this.ssp.controls.enabled = false;
54
- this.init(path);
55
- this.initOptions(options);
56
- this.patrolStart();
57
- }
58
- /**
59
- * 设置巡检进度
60
- * @param percent 0 - 1(不包含 1)
61
- */
62
- setProgress(percent) {
63
- var _a, _b;
64
- this._updatePercent = Math.min(Math.max(percent, 0), 1);
65
- this._needsUpdateProgress = true;
66
- (_a = this._positionTween) === null || _a === void 0 ? void 0 : _a.stop();
67
- (_b = this._rotationTween) === null || _b === void 0 ? void 0 : _b.stop();
68
- }
69
- /**
70
- * 设置巡检参数
71
- * @param options
72
- * @returns
73
- */
74
- setOptions(options) {
75
- if (this.isStoped)
76
- return;
77
- const { naviSpeed, rotateSpeed, } = options;
78
- if (naviSpeed && this._positionTween) {
79
- const newMoveDuration = this.states.moveDuration * this.options.naviSpeed / naviSpeed;
80
- this._positionTween.duration(newMoveDuration);
81
- this.states.moveDuration = newMoveDuration;
82
- }
83
- if (rotateSpeed && this._rotationTween) {
84
- const newRotateDuration = this.states.rotateDuration * this.options.rotateSpeed / rotateSpeed;
85
- this._rotationTween.duration(newRotateDuration);
86
- this.states.rotateDuration = newRotateDuration;
87
- }
88
- this.initOptions(options);
89
- }
90
- /**
91
- * 暂停巡检
92
- */
93
- pause() {
94
- var _a, _b;
95
- if (this.isPaused || this.isStoped)
96
- return;
97
- /**
98
- * 保存巡检相机视角数据
99
- */
100
- this._cameraViewpointData = this.ssp.getCameraViewpoint();
101
- this.isPaused = true;
102
- (_a = this._positionTween) === null || _a === void 0 ? void 0 : _a.pause();
103
- (_b = this._rotationTween) === null || _b === void 0 ? void 0 : _b.pause();
104
- }
105
- /**
106
- * 恢复巡检
107
- */
108
- resume() {
109
- var _a, _b;
110
- if (!this.isPaused || this.isStoped)
111
- return;
112
- if (this._cameraViewpointData) {
113
- this.ssp.setCameraViewpoint(this._cameraViewpointData);
114
- }
115
- this.isPaused = false;
116
- (_a = this._positionTween) === null || _a === void 0 ? void 0 : _a.resume();
117
- (_b = this._rotationTween) === null || _b === void 0 ? void 0 : _b.resume();
118
- }
119
- /**
120
- * 中断巡检
121
- */
122
- stop() {
123
- if (this.isStoped)
124
- return;
125
- this.patrolStop();
126
- this.ssp.controls.reset();
127
- this.ssp.controls.enabled = true;
128
- }
129
- init(path) {
130
- this.isPaused = false;
131
- this.isStoped = false;
132
- this.nextPointIndex = 0;
133
- // initPoints
134
- this.nodes = [...path.nodes];
135
- }
136
- initOptions(options) {
137
- const { eyeHeight, naviSpeed, rotateSpeed, flyToStartPoint = true, onUpdate, onProgress, onEnd, } = options;
138
- eyeHeight && (this.options.eyeHeight = eyeHeight);
139
- naviSpeed && (this.options.naviSpeed = naviSpeed);
140
- rotateSpeed && (this.options.rotateSpeed = rotateSpeed);
141
- this.options.flyToStartPoint = flyToStartPoint;
142
- onUpdate && (this.options.onUpdate = onUpdate);
143
- onProgress && (this.options.onProgress = onProgress);
144
- onEnd && (this.options.onEnd = onEnd);
145
- this._nodeDistances.length = 0;
146
- this._nodeDistances.push(0);
147
- this._totalDistance = 0;
148
- // compute node distance,加上 eyeHeight
149
- for (let i = 0, len = this.nodes.length; i < len - 1; i++) {
150
- const currentNode = this.nodes[i], nextNode = this.nodes[i + 1];
151
- if (currentNode && nextNode) {
152
- const currentWorldPosition = currentNode.getWorldPosition(new Vector3()), nextWorldPosition = nextNode.getWorldPosition(new Vector3());
153
- currentWorldPosition.y += this.options.eyeHeight;
154
- nextWorldPosition.y += this.options.eyeHeight;
155
- const distance = currentWorldPosition.distanceTo(nextWorldPosition);
156
- this._nodeDistances.push(distance);
157
- this._totalDistance += distance;
158
- }
159
- }
160
- }
161
- /**
162
- * 计算两点之间的弧度
163
- * @param sourcePoint
164
- * @param targetPoint
165
- * @returns
166
- */
167
- computedRotation(sourcePoint, targetPoint) {
168
- const matrix4 = new Matrix4();
169
- matrix4.lookAt(sourcePoint, targetPoint, this.camera.up);
170
- const nextRotation = new Quaternion().setFromRotationMatrix(matrix4);
171
- return nextRotation;
172
- }
173
- /**
174
- * 计算下一弧度
175
- * @returns
176
- */
177
- computeNextRotation(index = this.nextPointIndex) {
178
- var _a, _b;
179
- const currentPoint = (_a = this.nodes[index]) === null || _a === void 0 ? void 0 : _a.getWorldPosition(new Vector3());
180
- const nextPoint = (_b = this.nodes[index + 1]) === null || _b === void 0 ? void 0 : _b.getWorldPosition(new Vector3());
181
- return (currentPoint && nextPoint) ? this.computedRotation(currentPoint, nextPoint) : new Quaternion();
182
- }
183
- /**
184
- * 开始巡检
185
- * @returns
186
- */
187
- async patrolStart() {
188
- return new Promise(async (resolve) => {
189
- var _a;
190
- const { controls, } = this.ssp;
191
- const { onUpdate, onProgress, onEnd, } = this.options;
192
- if (this.nextPointIndex >= this.nodes.length) {
193
- // 巡检结束时
194
- onEnd === null || onEnd === void 0 ? void 0 : onEnd(this.camera.position.clone());
195
- resolve(true);
196
- }
197
- else {
198
- /**
199
- * 更新进度
200
- */
201
- if (this._needsUpdateProgress) {
202
- let percentDistance = this._totalDistance * this._updatePercent;
203
- for (let i = 0, len = this._nodeDistances.length; i < len; i++) {
204
- percentDistance -= this._nodeDistances[i];
205
- if (percentDistance < 0) {
206
- /**
207
- * 更新 index
208
- */
209
- this.nextPointIndex = i;
210
- /**
211
- * 更新相机位置
212
- */
213
- percentDistance += this._nodeDistances[i];
214
- const percent = (percentDistance / this._nodeDistances[i]) || 0;
215
- const prevNode = this.nodes[i - 1], nextNode = this.nodes[i];
216
- const cameraPosition = new Vector3();
217
- /**
218
- * 其他点
219
- */
220
- const prevPosition = prevNode.getWorldPosition(new Vector3()), nextPosition = nextNode.getWorldPosition(new Vector3());
221
- prevPosition.y += this.options.eyeHeight;
222
- nextPosition.y += this.options.eyeHeight;
223
- const diffPosition = new Vector3()
224
- .subVectors(nextPosition, prevPosition)
225
- .multiplyScalar(percent);
226
- cameraPosition.copy(prevPosition).add(diffPosition);
227
- controls.setPosition(cameraPosition.x, cameraPosition.y, cameraPosition.z);
228
- controls.setTarget(nextPosition.x, nextPosition.y, nextPosition.z);
229
- break;
230
- }
231
- }
232
- this._needsUpdateProgress = false;
233
- }
234
- const nextNode = this.nodes[this.nextPointIndex];
235
- const nextNodePosition = nextNode.getWorldPosition(new Vector3());
236
- // 增加眼睛高度
237
- nextNodePosition.setY(nextNodePosition.y + this.options.eyeHeight);
238
- // 相机位置与下一点的距离
239
- const positionDist = controls.getPosition(new Vector3()).distanceTo(nextNodePosition);
240
- /**
241
- * @todo 移动持续时间
242
- */
243
- this.states.moveDuration = this.nextPointIndex === 0 ? 1000 : positionDist / this.options.naviSpeed / 0.6;
244
- controls.setTarget(nextNodePosition.x, nextNodePosition.y, nextNodePosition.z);
245
- // 路径行行进
246
- if (this.nextPointIndex === 0 && !this.options.flyToStartPoint) {
247
- controls.dollyTo(EPS);
248
- }
249
- else {
250
- try {
251
- await this.ssp.animation({ distance: controls.distance, }, { distance: EPS, }, {
252
- duration: this.states.moveDuration,
253
- }, ({ distance, }) => {
254
- var _a;
255
- if (this.isPaused) {
256
- (_a = this._positionTween) === null || _a === void 0 ? void 0 : _a.pause();
257
- return;
258
- }
259
- controls.dollyTo(distance);
260
- onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(controls.getPosition(new Vector3()), nextNode, distance);
261
- /**
262
- * progress
263
- */
264
- if (this._nodeDistances[this.nextPointIndex] > 0) {
265
- let patrolled = this._nodeDistances.slice(0, this.nextPointIndex + 1).reduce((accumulator, currentValue) => accumulator + currentValue, 0);
266
- patrolled -= distance;
267
- onProgress === null || onProgress === void 0 ? void 0 : onProgress({
268
- patrolled,
269
- total: this._totalDistance,
270
- percent: patrolled / this._totalDistance,
271
- });
272
- }
273
- }, tween => {
274
- this._positionTween = tween;
275
- });
276
- }
277
- catch (_b) {
278
- /**
279
- * stop
280
- */
281
- }
282
- }
283
- // 节点转弯
284
- if (this.nextPointIndex < this.nodes.length - 1) {
285
- const nextRotation = this.computeNextRotation();
286
- const rotationDist = this.camera.quaternion.angleTo(nextRotation);
287
- /**
288
- * @todo
289
- */
290
- this.states.rotateDuration = this.nextPointIndex === 0 ? 1000 : rotationDist * 300 / this.options.rotateSpeed;
291
- const currentPosition = controls.getPosition(new Vector3());
292
- const nextPoint = (_a = this.nodes[this.nextPointIndex + 1]) === null || _a === void 0 ? void 0 : _a.getWorldPosition(new Vector3());
293
- nextPoint.y += this.options.eyeHeight;
294
- try {
295
- await this.ssp.animation({ t: 0, }, { t: 1, }, {
296
- duration: this.states.rotateDuration,
297
- }, ({ t, }) => {
298
- var _a;
299
- if (this.isPaused) {
300
- (_a = this._rotationTween) === null || _a === void 0 ? void 0 : _a.pause();
301
- return;
302
- }
303
- const diff1 = nextNodePosition
304
- .clone()
305
- .sub(currentPosition)
306
- .normalize();
307
- const diff2 = nextPoint
308
- .clone()
309
- .sub(nextNodePosition)
310
- .normalize();
311
- const { x, y, z, } = diff1
312
- .lerp(diff2, t)
313
- .add(nextNodePosition);
314
- controls.setTarget(x, y, z);
315
- }, tween => {
316
- this._rotationTween = tween;
317
- });
318
- }
319
- catch (_c) {
320
- /**
321
- * stop
322
- */
323
- }
324
- }
325
- if (!this._needsUpdateProgress)
326
- this.nextPointIndex++;
327
- if (!this.isStoped) {
328
- await this.patrolStart();
329
- }
330
- }
331
- });
332
- }
333
- patrolStop() {
334
- var _a, _b;
335
- this.options = {
336
- naviSpeed: 1,
337
- rotateSpeed: 1,
338
- eyeHeight: 150,
339
- flyToStartPoint: true,
340
- onUpdate: () => { },
341
- onProgress: () => { },
342
- onEnd: () => { },
343
- };
344
- this.nodes = [];
345
- this.nextPointIndex = 0;
346
- this.isPaused = false;
347
- this.isStoped = true;
348
- this._needsUpdateProgress = false;
349
- (_a = this._positionTween) === null || _a === void 0 ? void 0 : _a.stop();
350
- (_b = this._rotationTween) === null || _b === void 0 ? void 0 : _b.stop();
351
- this._positionTween = null;
352
- this._rotationTween = null;
353
- }
354
- }
355
-
356
- export { PatrolControlsPlugin as default };
357
- //# sourceMappingURL=index.esm.js.map
1
+ import{Vector3 as t,Matrix4 as s,Quaternion as i}from"three";const e=1e-5;class o{constructor(t){this.ssp=t,this.options={naviSpeed:1,rotateSpeed:1,eyeHeight:150,flyToStartPoint:!0,onUpdate:()=>{},onProgress:()=>{},onEnd:()=>{}},this.states={moveDuration:0,rotateDuration:0},this.nodes=[],this.nextPointIndex=0,this._nodeDistances=[],this._totalDistance=0,this._updatePercent=0,this._needsUpdateProgress=!1,this.isPaused=!1,this.isStoped=!0,this._positionTween=null,this._rotationTween=null,this._cameraViewpointData=null;const{cameraManager:s}=this.ssp.viewport;this.camera=s.mainCamera}start(t,s){this.isStoped?(this.ssp.controls.saveState(),this.ssp.controls.enabled=!1,this.init(t),this.initOptions(s),this.patrolStart()):this.ssp.utils.warn("巡检已经开始!")}setProgress(t){var s,i;this._updatePercent=Math.min(Math.max(t,0),1),this._needsUpdateProgress=!0,null===(s=this._positionTween)||void 0===s||s.stop(),null===(i=this._rotationTween)||void 0===i||i.stop()}setOptions(t){if(this.isStoped)return;const{naviSpeed:s,rotateSpeed:i}=t;if(s&&this._positionTween){const t=this.states.moveDuration*this.options.naviSpeed/s;this._positionTween.duration(t),this.states.moveDuration=t}if(i&&this._rotationTween){const t=this.states.rotateDuration*this.options.rotateSpeed/i;this._rotationTween.duration(t),this.states.rotateDuration=t}this.initOptions(t)}pause(){var t,s;this.isPaused||this.isStoped||(this._cameraViewpointData=this.ssp.getCameraViewpoint(),this.isPaused=!0,null===(t=this._positionTween)||void 0===t||t.pause(),null===(s=this._rotationTween)||void 0===s||s.pause())}resume(){var t,s;this.isPaused&&!this.isStoped&&(this._cameraViewpointData&&this.ssp.setCameraViewpoint(this._cameraViewpointData),this.isPaused=!1,null===(t=this._positionTween)||void 0===t||t.resume(),null===(s=this._rotationTween)||void 0===s||s.resume())}stop(){this.isStoped||(this.patrolStop(),this.ssp.controls.reset(),this.ssp.controls.enabled=!0)}init(t){this.isPaused=!1,this.isStoped=!1,this.nextPointIndex=0,this.nodes=[...t.nodes]}initOptions(s){const{eyeHeight:i,naviSpeed:e,rotateSpeed:o,flyToStartPoint:n=!0,onUpdate:a,onProgress:h,onEnd:r}=s;i&&(this.options.eyeHeight=i),e&&(this.options.naviSpeed=e),o&&(this.options.rotateSpeed=o),this.options.flyToStartPoint=n,a&&(this.options.onUpdate=a),h&&(this.options.onProgress=h),r&&(this.options.onEnd=r),this._nodeDistances.length=0,this._nodeDistances.push(0),this._totalDistance=0;for(let s=0,i=this.nodes.length;s<i-1;s++){const i=this.nodes[s],e=this.nodes[s+1];if(i&&e){const s=i.getWorldPosition(new t),o=e.getWorldPosition(new t);s.y+=this.options.eyeHeight,o.y+=this.options.eyeHeight;const n=s.distanceTo(o);this._nodeDistances.push(n),this._totalDistance+=n}}}computedRotation(t,e){const o=new s;o.lookAt(t,e,this.camera.up);return(new i).setFromRotationMatrix(o)}computeNextRotation(s=this.nextPointIndex){var e,o;const n=null===(e=this.nodes[s])||void 0===e?void 0:e.getWorldPosition(new t),a=null===(o=this.nodes[s+1])||void 0===o?void 0:o.getWorldPosition(new t);return n&&a?this.computedRotation(n,a):new i}async patrolStart(){return new Promise((async s=>{var i;const{controls:o}=this.ssp,{onUpdate:n,onProgress:a,onEnd:h}=this.options;if(this.nextPointIndex>=this.nodes.length)null==h||h(this.camera.position.clone()),s(!0);else{if(this._needsUpdateProgress){let s=this._totalDistance*this._updatePercent;for(let i=0,e=this._nodeDistances.length;i<e;i++)if(s-=this._nodeDistances[i],s<0){this.nextPointIndex=i,s+=this._nodeDistances[i];const e=s/this._nodeDistances[i]||0,n=this.nodes[i-1],a=this.nodes[i],h=new t,r=n.getWorldPosition(new t),d=a.getWorldPosition(new t);r.y+=this.options.eyeHeight,d.y+=this.options.eyeHeight;const p=(new t).subVectors(d,r).multiplyScalar(e);h.copy(r).add(p),o.setPosition(h.x,h.y,h.z),o.setTarget(d.x,d.y,d.z);break}this._needsUpdateProgress=!1}const s=this.nodes[this.nextPointIndex],h=s.getWorldPosition(new t);h.setY(h.y+this.options.eyeHeight);const r=o.getPosition(new t).distanceTo(h);if(this.states.moveDuration=0===this.nextPointIndex?1e3:r/this.options.naviSpeed/.6,o.setTarget(h.x,h.y,h.z),0!==this.nextPointIndex||this.options.flyToStartPoint)try{await this.ssp.animation({distance:o.distance},{distance:e},{duration:this.states.moveDuration},(({distance:i})=>{var e;if(this.isPaused)null===(e=this._positionTween)||void 0===e||e.pause();else if(o.dollyTo(i),null==n||n(o.getPosition(new t),s,i),this._nodeDistances[this.nextPointIndex]>0){let t=this._nodeDistances.slice(0,this.nextPointIndex+1).reduce(((t,s)=>t+s),0);t-=i,null==a||a({patrolled:t,total:this._totalDistance,percent:t/this._totalDistance})}}),(t=>{this._positionTween=t}))}catch(t){}else o.dollyTo(e);if(this.nextPointIndex<this.nodes.length-1){const s=this.computeNextRotation(),e=this.camera.quaternion.angleTo(s);this.states.rotateDuration=0===this.nextPointIndex?1e3:300*e/this.options.rotateSpeed;const n=o.getPosition(new t),a=null===(i=this.nodes[this.nextPointIndex+1])||void 0===i?void 0:i.getWorldPosition(new t);a.y+=this.options.eyeHeight;try{await this.ssp.animation({t:0},{t:1},{duration:this.states.rotateDuration},(({t:t})=>{var s;if(this.isPaused)return void(null===(s=this._rotationTween)||void 0===s||s.pause());const i=h.clone().sub(n).normalize(),e=a.clone().sub(h).normalize(),{x:r,y:d,z:p}=i.lerp(e,t).add(h);o.setTarget(r,d,p)}),(t=>{this._rotationTween=t}))}catch(t){}}this._needsUpdateProgress||this.nextPointIndex++,this.isStoped||await this.patrolStart()}}))}patrolStop(){var t,s;this.options={naviSpeed:1,rotateSpeed:1,eyeHeight:150,flyToStartPoint:!0,onUpdate:()=>{},onProgress:()=>{},onEnd:()=>{}},this.nodes=[],this.nextPointIndex=0,this.isPaused=!1,this.isStoped=!0,this._needsUpdateProgress=!1,null===(t=this._positionTween)||void 0===t||t.stop(),null===(s=this._rotationTween)||void 0===s||s.stop(),this._positionTween=null,this._rotationTween=null}}export{o as default};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@soonspacejs/plugin-patrol-controls",
3
3
  "pluginName": "PatrolControlsPlugin",
4
- "version": "2.13.7",
4
+ "version": "2.13.8",
5
5
  "description": "Patrol-controls plugin for SoonSpace.js",
6
6
  "main": "dist/index.esm.js",
7
7
  "module": "dist/index.esm.js",
@@ -13,8 +13,8 @@
13
13
  ],
14
14
  "author": "xunwei",
15
15
  "license": "UNLICENSED",
16
- "gitHead": "550040550bf20ec0015982ff1159d0cfe9b35ed3",
16
+ "gitHead": "d6b6f55e087ba0621e8bb404fc63c99fd4389660",
17
17
  "peerDependencies": {
18
- "soonspacejs": "2.13.7"
18
+ "soonspacejs": "2.13.8"
19
19
  }
20
20
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { PerspectiveCamera, OrthographicCamera, Vector3, Matrix4, Quaternion, } from 'three'\r\nimport SoonSpace from 'soonspacejs'\r\nimport type { CameraViewpointData, Position, } from 'soonspacejs'\r\nimport type { Node, } from 'soonspacejs'\r\nimport type { Topology, } from 'soonspacejs'\r\nimport type { Tween, } from 'three/examples/jsm/libs/tween.module.js'\r\n\r\nconst EPS = 1e-5\r\n\r\nexport type ProgressParams = {\r\n patrolled: number;\r\n total: number;\r\n percent: number;\r\n}\r\n\r\nexport interface DefaultOptions {\r\n /*\r\n * 眼睛高度\r\n */\r\n eyeHeight: number;\r\n /**\r\n * 巡检速度\r\n */\r\n naviSpeed: number;\r\n /**\r\n * 相机转向速度\r\n */\r\n rotateSpeed: number;\r\n /**\r\n * 是否飞向起始点位置\r\n */\r\n flyToStartPoint: boolean;\r\n /**\r\n * 更新回调\r\n */\r\n onUpdate: ( realTimePosition: Position, nextNode: Node, toNextNodeDistance: number ) => void;\r\n /**\r\n * 巡检进度\r\n */\r\n onProgress: ( params: ProgressParams ) => void;\r\n /**\r\n * 结束回调\r\n */\r\n onEnd: ( endPosition: Position ) => void;\r\n}\r\n\r\nexport type StartOptions = Partial<DefaultOptions>\r\n\r\nexport type ResetOptions = Pick<StartOptions, 'eyeHeight' | 'naviSpeed' | 'rotateSpeed'>\r\n\r\nexport default class PatrolControlsPlugin {\r\n\r\n camera: PerspectiveCamera | OrthographicCamera\r\n\r\n options: DefaultOptions = {\r\n naviSpeed: 1,\r\n rotateSpeed: 1,\r\n eyeHeight: 150,\r\n flyToStartPoint: true,\r\n onUpdate: () => { },\r\n onProgress: () => {},\r\n onEnd: () => { },\r\n }\r\n\r\n states = {\r\n moveDuration: 0,\r\n rotateDuration: 0,\r\n }\r\n\r\n // 路径节点列表\r\n nodes: Node[] = []\r\n nextPointIndex = 0\r\n /**\r\n * y 轴加上 eyeHeight 的节点之间距离\r\n */\r\n _nodeDistances: number[] = []\r\n _totalDistance = 0\r\n\r\n /**\r\n * 0 - 1\r\n */\r\n _updatePercent = 0\r\n _needsUpdateProgress = false\r\n\r\n isPaused = false\r\n isStoped = true\r\n\r\n _positionTween: Tween<{distance: number}> | null = null\r\n _rotationTween: Tween<{t: number}> | null = null\r\n _cameraViewpointData: CameraViewpointData | null = null\r\n\r\n constructor ( readonly ssp: SoonSpace ) {\r\n\r\n const { cameraManager, } = this.ssp.viewport\r\n\r\n this.camera = cameraManager.mainCamera\r\n \r\n }\r\n\r\n /**\r\n * 开始巡检\r\n * \r\n * @param path \r\n * @param options \r\n */\r\n start ( path: Topology, options: StartOptions ) {\r\n\r\n if ( !this.isStoped ) {\r\n\r\n this.ssp.utils.warn( '巡检已经开始!' )\r\n\r\n return\r\n \r\n }\r\n\r\n this.ssp.controls.saveState()\r\n this.ssp.controls.enabled = false\r\n\r\n this.init( path )\r\n this.initOptions( options )\r\n this.patrolStart()\r\n\r\n }\r\n\r\n /**\r\n * 设置巡检进度\r\n * @param percent 0 - 1(不包含 1)\r\n */\r\n setProgress ( percent: number ) {\r\n\r\n this._updatePercent = Math.min( Math.max( percent, 0 ), 1 )\r\n this._needsUpdateProgress = true\r\n this._positionTween?.stop()\r\n this._rotationTween?.stop()\r\n\r\n }\r\n\r\n /**\r\n * 设置巡检参数\r\n * @param options \r\n * @returns \r\n */\r\n setOptions ( options: ResetOptions ) {\r\n\r\n if ( this.isStoped ) return\r\n\r\n const { naviSpeed, rotateSpeed, } = options\r\n\r\n if ( naviSpeed && this._positionTween ) {\r\n\r\n const newMoveDuration = this.states.moveDuration * this.options.naviSpeed / naviSpeed\r\n\r\n this._positionTween.duration( newMoveDuration )\r\n this.states.moveDuration = newMoveDuration\r\n \r\n }\r\n\r\n if ( rotateSpeed && this._rotationTween ) {\r\n\r\n const newRotateDuration = this.states.rotateDuration * this.options.rotateSpeed / rotateSpeed\r\n\r\n this._rotationTween.duration( newRotateDuration )\r\n this.states.rotateDuration = newRotateDuration\r\n \r\n }\r\n\r\n this.initOptions( options )\r\n\r\n }\r\n\r\n /**\r\n * 暂停巡检\r\n */\r\n pause () {\r\n\r\n if ( this.isPaused || this.isStoped ) return\r\n\r\n /**\r\n * 保存巡检相机视角数据\r\n */\r\n this._cameraViewpointData = this.ssp.getCameraViewpoint()\r\n\r\n this.isPaused = true\r\n this._positionTween?.pause()\r\n this._rotationTween?.pause()\r\n\r\n }\r\n\r\n /**\r\n * 恢复巡检\r\n */\r\n resume () {\r\n\r\n if ( !this.isPaused || this.isStoped ) return\r\n\r\n if ( this._cameraViewpointData ) {\r\n\r\n this.ssp.setCameraViewpoint( this._cameraViewpointData )\r\n \r\n }\r\n\r\n this.isPaused = false\r\n this._positionTween?.resume()\r\n this._rotationTween?.resume()\r\n\r\n }\r\n\r\n /**\r\n * 中断巡检\r\n */\r\n stop () {\r\n\r\n if ( this.isStoped ) return\r\n\r\n this.patrolStop()\r\n\r\n this.ssp.controls.reset()\r\n this.ssp.controls.enabled = true\r\n\r\n }\r\n\r\n private init ( path: Topology ) {\r\n\r\n this.isPaused = false\r\n this.isStoped = false\r\n this.nextPointIndex = 0\r\n\r\n // initPoints\r\n this.nodes = [ ...path.nodes ]\r\n \r\n }\r\n\r\n private initOptions ( options: StartOptions ) {\r\n\r\n const { eyeHeight, naviSpeed, rotateSpeed, flyToStartPoint = true, onUpdate, onProgress, onEnd, } = options\r\n\r\n eyeHeight && ( this.options.eyeHeight = eyeHeight )\r\n naviSpeed && ( this.options.naviSpeed = naviSpeed )\r\n rotateSpeed && ( this.options.rotateSpeed = rotateSpeed )\r\n\r\n this.options.flyToStartPoint = flyToStartPoint\r\n\r\n onUpdate && ( this.options.onUpdate = onUpdate )\r\n onProgress && ( this.options.onProgress = onProgress )\r\n onEnd && ( this.options.onEnd = onEnd )\r\n\r\n this._nodeDistances.length = 0\r\n this._nodeDistances.push( 0 )\r\n this._totalDistance = 0\r\n\r\n // compute node distance,加上 eyeHeight\r\n for ( let i = 0, len = this.nodes.length;i < len - 1;i++ ) {\r\n\r\n const currentNode = this.nodes[ i ], nextNode = this.nodes[ i + 1 ]\r\n\r\n if ( currentNode && nextNode ) {\r\n\r\n const currentWorldPosition = currentNode.getWorldPosition( new Vector3() ),\r\n nextWorldPosition = nextNode.getWorldPosition( new Vector3() )\r\n\r\n currentWorldPosition.y += this.options.eyeHeight\r\n nextWorldPosition.y += this.options.eyeHeight\r\n\r\n const distance = currentWorldPosition.distanceTo( nextWorldPosition )\r\n\r\n this._nodeDistances.push( distance )\r\n this._totalDistance += distance\r\n \r\n }\r\n \r\n }\r\n\r\n }\r\n\r\n /**\r\n * 计算两点之间的弧度\r\n * @param sourcePoint \r\n * @param targetPoint \r\n * @returns \r\n */\r\n private computedRotation ( sourcePoint: Vector3, targetPoint: Vector3 ): Quaternion {\r\n \r\n const matrix4 = new Matrix4()\r\n\r\n matrix4.lookAt( sourcePoint, targetPoint, this.camera.up )\r\n\r\n const nextRotation = new Quaternion().setFromRotationMatrix( matrix4 )\r\n\r\n return nextRotation\r\n \r\n }\r\n\r\n /**\r\n * 计算下一弧度\r\n * @returns \r\n */\r\n private computeNextRotation ( index = this.nextPointIndex ): Quaternion {\r\n\r\n const currentPoint = this.nodes[ index ]?.getWorldPosition( new Vector3() )\r\n const nextPoint = this.nodes[ index + 1 ]?.getWorldPosition( new Vector3() )\r\n\r\n return ( currentPoint && nextPoint ) ? this.computedRotation( currentPoint, nextPoint ) : new Quaternion()\r\n\r\n }\r\n\r\n /**\r\n * 开始巡检\r\n * @returns \r\n */\r\n private async patrolStart (): Promise<boolean> {\r\n\r\n return new Promise( async resolve => {\r\n\r\n const { controls, } = this.ssp\r\n\r\n const {\r\n onUpdate,\r\n onProgress,\r\n onEnd,\r\n } = this.options\r\n\r\n if ( this.nextPointIndex >= this.nodes.length ) {\r\n\r\n // 巡检结束时\r\n onEnd?.( this.camera.position.clone() )\r\n resolve( true )\r\n \r\n } else {\r\n\r\n /**\r\n * 更新进度\r\n */\r\n if ( this._needsUpdateProgress ) {\r\n\r\n let percentDistance = this._totalDistance * this._updatePercent\r\n\r\n for ( let i = 0, len = this._nodeDistances.length;i < len;i++ ) {\r\n\r\n percentDistance -= this._nodeDistances[ i ]\r\n\r\n if ( percentDistance < 0 ) {\r\n\r\n /**\r\n * 更新 index\r\n */\r\n this.nextPointIndex = i\r\n\r\n /**\r\n * 更新相机位置\r\n */\r\n percentDistance += this._nodeDistances[ i ]\r\n\r\n const percent = ( percentDistance / this._nodeDistances[ i ] ) || 0\r\n\r\n const prevNode = this.nodes[ i - 1 ], nextNode = this.nodes[ i ]\r\n\r\n const cameraPosition = new Vector3()\r\n\r\n /**\r\n * 其他点\r\n */\r\n const prevPosition = prevNode.getWorldPosition( new Vector3() ),\r\n nextPosition = nextNode.getWorldPosition( new Vector3() )\r\n\r\n prevPosition.y += this.options.eyeHeight\r\n nextPosition.y += this.options.eyeHeight\r\n\r\n const diffPosition = new Vector3()\r\n .subVectors( nextPosition, prevPosition )\r\n .multiplyScalar( percent )\r\n\r\n cameraPosition.copy( prevPosition ).add( diffPosition )\r\n\r\n controls.setPosition( cameraPosition.x, cameraPosition.y, cameraPosition.z )\r\n controls.setTarget( nextPosition.x, nextPosition.y, nextPosition.z )\r\n\r\n break\r\n \r\n }\r\n \r\n }\r\n\r\n this._needsUpdateProgress = false\r\n \r\n }\r\n\r\n const nextNode = this.nodes[ this.nextPointIndex ]\r\n const nextNodePosition = nextNode.getWorldPosition( new Vector3() )\r\n\r\n // 增加眼睛高度\r\n nextNodePosition.setY( nextNodePosition.y + this.options.eyeHeight )\r\n \r\n // 相机位置与下一点的距离\r\n const positionDist = controls.getPosition( new Vector3() ).distanceTo( nextNodePosition )\r\n\r\n /**\r\n * @todo 移动持续时间\r\n */\r\n this.states.moveDuration = this.nextPointIndex === 0 ? 1000 : positionDist / this.options.naviSpeed / 0.6\r\n\r\n controls.setTarget( nextNodePosition.x, nextNodePosition.y, nextNodePosition.z )\r\n\r\n // 路径行行进\r\n if ( this.nextPointIndex === 0 && !this.options.flyToStartPoint ) {\r\n\r\n controls.dollyTo( EPS )\r\n\r\n } else {\r\n\r\n try {\r\n\r\n await this.ssp.animation(\r\n { distance: controls.distance, },\r\n { distance: EPS, },\r\n {\r\n duration: this.states.moveDuration,\r\n },\r\n ( { distance, } ) => {\r\n \r\n if ( this.isPaused ) {\r\n \r\n this._positionTween?.pause()\r\n \r\n return\r\n \r\n }\r\n\r\n controls.dollyTo( distance )\r\n\r\n onUpdate?.( controls.getPosition( new Vector3() ), nextNode, distance )\r\n \r\n /**\r\n * progress\r\n */\r\n if ( this._nodeDistances[ this.nextPointIndex ] > 0 ) {\r\n\r\n let patrolled = this._nodeDistances.slice( 0, this.nextPointIndex + 1 ).reduce( ( accumulator, currentValue ) => accumulator + currentValue, 0 )\r\n\r\n patrolled -= distance\r\n \r\n onProgress?.( {\r\n patrolled, \r\n total: this._totalDistance,\r\n percent: patrolled / this._totalDistance,\r\n } )\r\n \r\n }\r\n \r\n },\r\n tween => {\r\n \r\n this._positionTween = tween\r\n \r\n }\r\n )\r\n \r\n } catch {\r\n \r\n /**\r\n * stop\r\n */\r\n\r\n }\r\n\r\n }\r\n\r\n // 节点转弯\r\n if ( this.nextPointIndex < this.nodes.length - 1 ) {\r\n\r\n const nextRotation = this.computeNextRotation()\r\n const rotationDist = this.camera.quaternion.angleTo( nextRotation )\r\n\r\n /**\r\n * @todo \r\n */\r\n this.states.rotateDuration = this.nextPointIndex === 0 ? 1000 : rotationDist * 300 / this.options.rotateSpeed\r\n\r\n const currentPosition = controls.getPosition( new Vector3() )\r\n const nextPoint = this.nodes[ this.nextPointIndex + 1 ]?.getWorldPosition( new Vector3() )\r\n\r\n nextPoint.y += this.options.eyeHeight\r\n \r\n try {\r\n\r\n await this.ssp.animation(\r\n { t: 0, },\r\n { t: 1, },\r\n {\r\n duration: this.states.rotateDuration,\r\n },\r\n ( { t, } ) => {\r\n \r\n if ( this.isPaused ) {\r\n \r\n this._rotationTween?.pause()\r\n\r\n return\r\n \r\n }\r\n\r\n const diff1 = nextNodePosition\r\n .clone()\r\n .sub( currentPosition )\r\n .normalize()\r\n const diff2 = nextPoint\r\n .clone()\r\n .sub( nextNodePosition )\r\n .normalize()\r\n \r\n const { x, y, z, } = diff1\r\n .lerp( diff2, t )\r\n .add( nextNodePosition )\r\n\r\n controls.setTarget( x, y, z )\r\n \r\n },\r\n tween => {\r\n \r\n this._rotationTween = tween\r\n \r\n }\r\n )\r\n \r\n } catch {\r\n\r\n /**\r\n * stop\r\n */\r\n\r\n }\r\n\r\n }\r\n\r\n if ( !this._needsUpdateProgress ) this.nextPointIndex++\r\n\r\n if ( !this.isStoped ) {\r\n\r\n await this.patrolStart()\r\n\r\n }\r\n\r\n }\r\n\r\n } )\r\n\r\n }\r\n\r\n private patrolStop () {\r\n\r\n this.options = {\r\n naviSpeed: 1,\r\n rotateSpeed: 1,\r\n eyeHeight: 150,\r\n flyToStartPoint: true,\r\n onUpdate: () => { },\r\n onProgress: () => {},\r\n onEnd: () => { },\r\n }\r\n\r\n this.nodes = []\r\n this.nextPointIndex = 0\r\n this.isPaused = false\r\n this.isStoped = true\r\n\r\n this._needsUpdateProgress = false\r\n\r\n this._positionTween?.stop()\r\n this._rotationTween?.stop()\r\n\r\n this._positionTween = null\r\n this._rotationTween = null\r\n \r\n }\r\n\r\n}\r\n"],"names":[],"mappings":"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"}