@cc-component/cc-ex-component 1.0.0

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.
@@ -0,0 +1,12 @@
1
+ # 系统组件添加常用扩展方法
2
+
3
+ ## 前置条件
4
+ [游戏引擎](https://www.cocos.com/en/creator-download)
5
+ [开发框架](https://github.com/a1076559139/cocos-creator-frame-3d)
6
+
7
+ ## 使用案例
8
+ ```TS
9
+ import {} from 'db://pkg/@gamex/cc-ex-component';
10
+
11
+ ...
12
+ ```
@@ -0,0 +1,636 @@
1
+ import { sp } from "cc";
2
+ import { Component } from "cc";
3
+ import { director } from "cc";
4
+ import { UITransform } from "cc";
5
+ import { Tween, Node } from 'cc';
6
+ import { TweenManager } from "./ExTween";
7
+ import { Slider } from "cc";
8
+ import { ProgressBar, tween, Sprite, view, v3, Button, Label, Animation } from "cc";
9
+ import { Color } from "cc";
10
+
11
+ declare global {
12
+ interface String {
13
+ toMap<K, V>(): Map<K, V>;
14
+ /**转数组 */
15
+ toArray<T>(): T[];
16
+ /**对象 */
17
+ toObj<T>(): T;
18
+ /**是JSON */
19
+ isJSON(): boolean;
20
+ toBool(): boolean;
21
+ toNumber(): number;
22
+ /**添加颜色-富文本 */
23
+ addColor(colorHex: string): string
24
+ /**添加颜色 -富文本*/
25
+ addSize(font: number): string
26
+ }
27
+ interface Any {
28
+ toMap<K, V>(): Map<K, V>;
29
+ /**对象转map */
30
+ toMapObj<K, V>(): Map<K, V>;
31
+ }
32
+ interface Number {
33
+ toDay(): { days: number, hours: number, minutes: number, seconds: number };
34
+ }
35
+
36
+ interface Map<K, V> {
37
+ toObject(): Object;
38
+ }
39
+
40
+ interface Array<T> {
41
+ first(): T;
42
+ last(): T;
43
+ /**
44
+ * 将一维数组按指定大小分组成二维数组
45
+ * @param arr 原始一维数组
46
+ * @param chunkSize 每组的元素数量
47
+ * @returns 分组后的二维数组
48
+ */
49
+ chunkArray(chunkSize: number): T[][];
50
+
51
+ }
52
+ }
53
+ interface Window {
54
+ /**抖音添加到桌面按钮 */
55
+ tt_button: boolean;
56
+ /**抖音订阅 */
57
+ tt_button_ding_yue: boolean;
58
+ /**抖音订阅视频流 */
59
+ tt_button_ding_yue_feed: boolean;
60
+
61
+ /**微信订阅 */
62
+ wx_button_ding_yue: boolean;
63
+
64
+ }
65
+
66
+
67
+
68
+ // 扩展 Node 接口,声明自定义属性
69
+ declare module 'cc' {
70
+ interface window {
71
+
72
+ }
73
+ interface Asset {
74
+ /**资源路径 */
75
+ asset_path: string;
76
+ }
77
+
78
+ interface Node {
79
+ asset_path: string;
80
+ /**暂停所有spine动画 */
81
+ pauseSpines(): void;
82
+ resumeSpines(): void;
83
+ //暂停所有schedule
84
+ pauseSchedule(): void;
85
+ resumeSchedule(): void;
86
+
87
+ /**暂停所有的spine 和 tween 和schedule
88
+ * key 是指定twenn的分组key,不传参则 不暂停tween,使用TweenGame 收集tween
89
+ */
90
+ pauseAll(key?: string, speed?: number): void;
91
+ resumeAll(key?: string, speed?: number): void;
92
+ /**置灰节点 */
93
+ interactableColor(enable: boolean, is_anim?: boolean);
94
+ /**原始颜色--私有 */
95
+ original_color: Color;
96
+ /**原始颜色进度--私有 */
97
+ original_pro: number;
98
+ }
99
+
100
+ interface UITransform {
101
+ /**在盒子内或者盒子外
102
+ * box2- 目标盒子
103
+ * inBox-true:盒子内---false:盒子外
104
+ */
105
+ inBox(box2: UITransform, inBox: boolean): boolean;
106
+ getBoxRect(box: UITransform): { minX: number, maxX: number, minY: number, maxY: number };
107
+ }
108
+
109
+ interface Tween<T> {
110
+ pause(speed?: number): void;
111
+ resume(speed?: number): void;
112
+ }
113
+
114
+ interface Slider {
115
+ addActionSlider(callBack: (slider: Slider) => void): void;
116
+ }
117
+
118
+
119
+ interface ProgressBar {
120
+ pro(progress: number, max: number, anim_time?: number);
121
+ }
122
+ interface Animation {
123
+ stopSample();
124
+ }
125
+ interface Sprite {
126
+ fitHeight(): void;
127
+ /**颜色 */
128
+ fromHEX(hex: string);
129
+ }
130
+ interface Node {
131
+ enable(enable: boolean, time?: number): void;
132
+ }
133
+ interface Label {
134
+ /**动画播放 */
135
+ play(param: {
136
+ startValue: number,
137
+ endValue: number,
138
+ duration: number,
139
+ formatter?: (value: number) => string,
140
+ onComplete?: () => void
141
+ })
142
+ _currentTween;
143
+ /**颜色 */
144
+ fromHEX(hex: string);
145
+ }
146
+ namespace sp {
147
+ interface Skeleton {
148
+ /**颜色 */
149
+ fromHEX(hex: string);
150
+ }
151
+ }
152
+ }
153
+ /**
154
+ * 扩展 UITransform 接口,添加 isBoxInsideAnotherBox 方法
155
+ */
156
+ UITransform.prototype.inBox = function (this: UITransform, box2: UITransform, inBox: boolean): boolean {
157
+ // 获取 box 和 box2 的边界框
158
+ const rect1 = this.getBoxRect(this)
159
+ const rect2 = this.getBoxRect(box2)
160
+ // 检查 box 的四个边是否都在 box2 的边界框内
161
+ let isInside = false;
162
+ if (inBox) {
163
+ isInside =
164
+ rect1.minX <= rect2.minX && // box 左边界在 box2 左边界右侧
165
+ rect1.maxX >= rect2.maxX && // box 右边界在 box2 右边界左侧
166
+ rect1.minY <= rect2.minY && // box 下边界在 box2 下边界上侧
167
+ rect1.maxY >= rect2.maxY; // box 上边界在 box2 上边界下侧
168
+ } else {
169
+ isInside =
170
+ rect1.minX > rect2.maxX ||
171
+ rect1.maxX < rect2.minX || // box 右边界在 box2 右边界左侧
172
+ rect1.minY > rect2.maxY || // box 下边界在 box2 下边界上侧
173
+ rect1.maxY < rect2.minY; // box 上边界在 box2 上边界下侧
174
+ }
175
+ return isInside;
176
+ };
177
+
178
+ UITransform.prototype.getBoxRect = function (box: UITransform) {
179
+ const min_x = box.node.worldPosition.x - box.width * 0.5
180
+ const max_x = box.node.worldPosition.x + box.width * 0.5
181
+ const minY = box.node.worldPosition.y - box.height * 0.5
182
+ const maxY = box.node.worldPosition.y + box.height * 0.5
183
+ return { minX: min_x, maxX: max_x, minY: minY, maxY: maxY }
184
+ };
185
+
186
+
187
+
188
+
189
+ // 备份原始tick方法
190
+ Object.defineProperties(Tween.prototype, {
191
+ _paused: {
192
+ value: false,
193
+ writable: true,
194
+ configurable: true,
195
+ },
196
+ pause: {
197
+ value: function (this, speed?: number) {
198
+ if (this._finalAction && typeof this._finalAction['_speed'] !== 'undefined') {
199
+ this._finalAction['_speed'] = speed ? speed : 0;
200
+ this._paused = true;
201
+ }
202
+ return this;
203
+ },
204
+ writable: true,
205
+ configurable: true,
206
+ },
207
+ resume: {
208
+ value: function (this, speed?: number) {
209
+ if (this._finalAction && typeof this._finalAction['_speed'] !== 'undefined') {
210
+ this._finalAction['_speed'] = speed ? speed : 1;;
211
+ this._paused = false;
212
+ }
213
+ return this;
214
+ },
215
+ writable: true,
216
+ configurable: true,
217
+ },
218
+ isPaused: {
219
+ value: function () {
220
+ return this._paused === true;
221
+ },
222
+ writable: false,
223
+ configurable: true,
224
+ },
225
+ });
226
+
227
+ Object.defineProperties(Node.prototype, {
228
+ pauseAll: {
229
+ value: function (this: Node, key?: string, speed?: number) {
230
+ //@ts-ignore
231
+ const node_list = this.getChildrens();
232
+ node_list.forEach((node: Node) => {
233
+ node.components.forEach((component: any) => {
234
+ if (component instanceof sp.Skeleton) {
235
+ component["old_timeScale"] = component.timeScale;
236
+ component.timeScale = speed ? speed : 0;
237
+ }
238
+ else {
239
+ if (speed) {
240
+ component["old_timeScale_sched"] = speed;
241
+ director.getScheduler().setTimeScale(speed)
242
+ } else {
243
+ director.getScheduler().pauseTarget(component);
244
+ }
245
+ }
246
+ });
247
+ });
248
+ //暂停所有的tween
249
+ if (key) {
250
+ TweenManager.pause(key, speed)
251
+ }
252
+ return this;
253
+ },
254
+ writable: true,
255
+ },
256
+ resumeAll: {
257
+ value: function (this: Node, key?: string, speed?: number) {
258
+ //@ts-ignore
259
+ const node_list = this.getChildrens();
260
+ node_list.forEach((node: Node) => {
261
+ node.components.forEach((component: any) => {
262
+ if (component instanceof sp.Skeleton) {
263
+ const old_timeScale = component["old_timeScale"];
264
+ component.timeScale = old_timeScale !== undefined || old_timeScale !== null ? old_timeScale : speed;
265
+ component["old_timeScale"] = null;
266
+ } else {
267
+ if (speed) {
268
+ director.getScheduler().setTimeScale(speed)
269
+ } else {
270
+ if (component["old_timeScale_sched"]) {
271
+ director.getScheduler().setTimeScale(1)
272
+ component["old_timeScale_sched"] = null;
273
+ };
274
+ director.getScheduler().resumeTarget(component);
275
+ }
276
+ }
277
+ });
278
+ });
279
+ //暂停所有的tween
280
+ if (key) {
281
+ TweenManager.resume(key, speed)
282
+ }
283
+ return this;
284
+ },
285
+ writable: true,
286
+ },
287
+ pauseSpines: {
288
+ value: function (this: Node) {
289
+ this.getComponentsInChildren(sp.Skeleton).forEach(skel => {
290
+ skel["old_timeScale"] = skel.timeScale;
291
+ skel.timeScale = 0;
292
+ });
293
+ return this;
294
+ },
295
+ writable: true,
296
+ },
297
+ resumeSpines: {
298
+ value: function (this: Node) {
299
+ this.getComponentsInChildren(sp.Skeleton).forEach(skel => {
300
+ const old_timeScale = skel["old_timeScale"];
301
+ skel.timeScale = old_timeScale !== undefined || old_timeScale !== null ? old_timeScale : 1;
302
+ skel["old_timeScale"] = null
303
+ });
304
+ return this;
305
+ },
306
+ writable: true,
307
+ },
308
+ pauseSchedule: {
309
+ value: function (this: Node) {
310
+ //@ts-ignore
311
+ const node_list = this.getChildrens();
312
+ node_list.forEach((node: Node) => {
313
+ node.components.forEach((component: any) => {
314
+ director.getScheduler().pauseTarget(component);
315
+ });
316
+ });
317
+ return this;
318
+ },
319
+ writable: true,
320
+ },
321
+ resumeSchedule: {
322
+ value: function (this: Node) {
323
+ //@ts-ignore
324
+ const node_list = this.getChildrens();
325
+ node_list.forEach((node: Node) => {
326
+ director.getScheduler().resumeTargets(node.components as any[]);
327
+ });
328
+ return this;
329
+ },
330
+ writable: true,
331
+ },
332
+ // 私有遍历工具方法
333
+ getChildrens: {
334
+ value: function (this: Node): Node[] {
335
+ const result: Node[] = [];
336
+ function collect(node: Node) {
337
+ result.push(node);
338
+ node.children.forEach(collect);
339
+ }
340
+ collect(this);
341
+ return result;
342
+ },
343
+ writable: true,
344
+ },
345
+ });
346
+
347
+
348
+ Object.defineProperties(Slider.prototype, {
349
+ addActionSlider: {
350
+ value: function (this: Slider, callBack: (slider: Slider) => void) {
351
+ this.node.on('slide', callBack, this);
352
+ return this;
353
+ },
354
+ writable: true,
355
+ configurable: true,
356
+ }
357
+ });
358
+
359
+
360
+ //.
361
+
362
+
363
+ // 实现字符串扩展方法
364
+ String.prototype.toMap = function <K, V>(): Map<K, V> {
365
+ try {
366
+ // 解析JSON字符串
367
+ if (!this.isJSON()) {
368
+ return new Map<K, V>();
369
+ }
370
+ const parsedData = JSON.parse(this.toString());
371
+ const resultMap = new Map<K, V>();
372
+
373
+ // 处理数组格式 [{ "103": 4 }, { "104": 5 }]
374
+ if (Array.isArray(parsedData)) {
375
+ parsedData.forEach(obj => {
376
+ if (typeof obj === 'object' && obj !== null) {
377
+ Object.entries(obj).forEach(([key, value]) => {
378
+ resultMap.set(key as unknown as K, value as unknown as V);
379
+ });
380
+ }
381
+ });
382
+ }
383
+ // 处理对象格式 { "103": 4, "104": 5 }
384
+ else if (typeof parsedData === 'object' && parsedData !== null) {
385
+ Object.entries(parsedData).forEach(([key, value]) => {
386
+ resultMap.set(key as unknown as K, value as unknown as V);
387
+ });
388
+ }
389
+
390
+ return resultMap;
391
+ } catch (error) {
392
+ console.error("JSON解析错误:", error);
393
+ return new Map<K, V>();
394
+ }
395
+ };
396
+
397
+ // 实现字符串扩展方法 toArray
398
+ String.prototype.toArray = function <T>(): T[] {
399
+ try {
400
+ // 解析JSON字符串
401
+ const parsedData = JSON.parse(this.toString());
402
+ return parsedData;
403
+ } catch (error) {
404
+ console.error("JSON解析错误:", error);
405
+ return [];
406
+ }
407
+ };
408
+
409
+ // 实现字符串扩展方法 toObj
410
+ String.prototype.toObj = function <T>(): T {
411
+ try {
412
+ // 解析JSON字符串
413
+ const parsedData = JSON.parse(this.toString());
414
+ return parsedData;
415
+ } catch (error) {
416
+ console.error("JSON解析错误:", error);
417
+ return {} as T;
418
+ }
419
+ };
420
+ // 实现字符串扩展方法 isJSON
421
+ String.prototype.isJSON = function (): boolean {
422
+ const str = this.toString()
423
+ // 检查是否为字符串类型
424
+ if (typeof str !== 'string') {
425
+ return false;
426
+ }
427
+
428
+ // 检查是否为空字符串
429
+ if (str.trim().length === 0) {
430
+ return false;
431
+ }
432
+
433
+ try {
434
+ const parsed = JSON.parse(str);
435
+ // 确保解析结果是对象或数组(JSON的顶级必须是对象或数组)
436
+ return (typeof parsed === 'object' && parsed !== null) || Array.isArray(parsed);
437
+ } catch (e) {
438
+ return false;
439
+ }
440
+ };
441
+
442
+ // 实现字符串扩展方法 toBool
443
+ String.prototype.toBool = function (): boolean {
444
+ return this.toString().toLowerCase() === 'true';
445
+ };
446
+
447
+
448
+
449
+ // 扩展 Number 原型,添加毫秒转天时分秒的方法
450
+ Number.prototype.toDay = function (): { days: number, hours: number, minutes: number, seconds: number } {
451
+ let milliseconds = this as number;
452
+
453
+ const days = Math.floor(milliseconds / 86400000); // 计算天数
454
+ milliseconds %= 86400000; // 剩余毫秒
455
+
456
+ const hours = Math.floor(milliseconds / 3600000); // 计算小时数
457
+ milliseconds %= 3600000; // 剩余毫秒
458
+
459
+ const minutes = Math.floor(milliseconds / 60000); // 计算分钟数
460
+ milliseconds %= 60000; // 剩余毫秒
461
+
462
+ const seconds = Math.floor(milliseconds / 1000); // 计算秒数
463
+
464
+ return { days, hours, minutes, seconds };
465
+ };
466
+
467
+ ProgressBar.prototype.pro = function (this: ProgressBar, progress: number, max: number, anim_time?: number): void {
468
+ const com_max_pro = this.totalLength//getComponent(UITransform).width
469
+ const max_progress = com_max_pro;
470
+ const s = max_progress / max;
471
+ const pro = progress * s / max_progress;
472
+
473
+ if (anim_time) {
474
+ tween(this).to(anim_time, {
475
+ progress: pro
476
+ }).start();
477
+
478
+ } else {
479
+ this.progress = pro;
480
+
481
+ }
482
+ };
483
+
484
+ Animation.prototype.stopSample = function (this: Animation): void {
485
+ this.stop();
486
+ // 停止动画并重置到第一帧
487
+ const animState = this.getState(this.defaultClip.name);
488
+ if (animState) {
489
+ animState.time = 0;
490
+ animState.sample(); // 强制采样第一帧
491
+ }
492
+ };
493
+ // 扩展 Sprite 原型,添加 fitHeight 方法
494
+ Sprite.prototype.fitHeight = function (this: Sprite): void {
495
+ const screen = view.getVisibleSize(); // 获取屏幕可见区域的尺寸
496
+ const screenHeight = screen.height;
497
+
498
+ const uiTransform = this.node.getComponent(UITransform)!; // 获取节点的 UITransform 组件
499
+ if (!uiTransform) {
500
+ console.error("当前 Sprite 节点缺少 UITransform 组件");
501
+ return;
502
+ }
503
+
504
+ const originalSize = uiTransform.contentSize; // 获取图片原始尺寸
505
+
506
+ // 计算缩放比例
507
+ const scaleRatio = screenHeight / originalSize.height;
508
+
509
+ // 设置新的尺寸(保持宽高比)
510
+ uiTransform.setContentSize(originalSize.width * scaleRatio, screenHeight);
511
+
512
+ // 如果需要居中对齐,可以调整节点位置
513
+ this.node.setPosition(v3(0, 0, 0));
514
+ };
515
+ // 扩展 Sprite 原型,添加 fitHeight 方法
516
+ Node.prototype.enable = function (this: Node, enable: boolean, time?: number): void {
517
+ if (this.isValid) {
518
+ const btn = this.getComponent(Button);
519
+ if (btn) {
520
+ if (time) {
521
+ btn.interactable = enable;
522
+ if (!enable) {
523
+ setTimeout(() => {
524
+ if (btn && btn.isValid)
525
+ btn.interactable = true;
526
+ }, time)
527
+ }
528
+ } else {
529
+ btn.interactable = enable;
530
+ }
531
+ }
532
+ }
533
+ };
534
+
535
+ Map.prototype.toObject = function (): Object {
536
+ const obj = {};
537
+ for (const [key, value] of this.entries()) {
538
+ obj[key] = value;
539
+ }
540
+ return obj;
541
+ };
542
+
543
+ Label.prototype.play = function (
544
+ this: Label,
545
+ param: {
546
+ startValue: number,
547
+ endValue: number,
548
+ duration: number,
549
+ formatter: (value: number) => string,
550
+ onComplete?: () => void
551
+ }
552
+ ): void {
553
+ const label = this;
554
+
555
+ // 如果已有动画,先停止
556
+ if (label._currentTween) {
557
+ label._currentTween.stop();
558
+ }
559
+ // 使用 tween 动画
560
+ const obj: { value: number } = { value: param.startValue }
561
+ label._currentTween = tween(obj)
562
+ .to(
563
+ param.duration,
564
+ { value: param.endValue },
565
+ {
566
+ onUpdate(target: { value: number }) {
567
+ label.string = param.formatter(target.value);
568
+ },
569
+ easing: "quadOut",
570
+ }
571
+ )
572
+ .call(() => {
573
+ param.onComplete?.();
574
+ label._currentTween = null; // 清空引用
575
+ })
576
+ .start();
577
+ };
578
+
579
+
580
+
581
+ Object.defineProperty(Array.prototype, 'first', {
582
+ value: function () {
583
+ return this[0];
584
+ },
585
+ enumerable: false,
586
+ writable: false,
587
+ configurable: true
588
+ });
589
+ Object.defineProperty(Array.prototype, 'last', {
590
+ value: function () {
591
+ return this[this.length - 1];
592
+ },
593
+ enumerable: false,
594
+ writable: false,
595
+ configurable: true
596
+ });
597
+ Object.defineProperty(Array.prototype, 'chunkArray', {
598
+ value: function <T>(this: T[], chunkSize: number): T[][] {
599
+ const arr = this;
600
+ const result: T[][] = [];
601
+ for (let i = 0; i < arr.length; i += chunkSize) {
602
+ result.push(arr.slice(i, i + chunkSize));
603
+ }
604
+ return result;
605
+ },
606
+ enumerable: false,
607
+ writable: false,
608
+ configurable: true
609
+ });
610
+
611
+
612
+ // 实现字符串扩展方法
613
+ String.prototype.toNumber = function <K, V>(): number {
614
+ return Number(this) ?? 0;
615
+ };
616
+ // 实现字符串扩展方法
617
+ String.prototype.addColor = function (colorHex: string): string {
618
+ return `<color=${colorHex}>${this}</color>`
619
+ };
620
+ // 实现字符串扩展方法
621
+ String.prototype.addSize = function (font: number): string {
622
+ return `<size=${font}>${this}</size>`
623
+ };
624
+ Label.prototype.fromHEX = function (this: Label, hex: string): void {
625
+ const label = this;
626
+ label.color = (new Color()).fromHEX(hex)
627
+ };
628
+ Sprite.prototype.fromHEX = function (this: Sprite, hex: string): void {
629
+ const label = this;
630
+ label.color = (new Color()).fromHEX(hex)
631
+ };
632
+ sp.Skeleton.prototype.fromHEX = function (this: sp.Skeleton, hex: string): void {
633
+ const label = this;
634
+ label.color = (new Color()).fromHEX(hex)
635
+ };
636
+ export { };
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.23",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "2114b6dd-3bd1-43c6-8bbd-7de5eee953b2",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
@@ -0,0 +1,146 @@
1
+ import { __private, ITweenOption } from 'cc';
2
+ import { tween, Tween } from 'cc';
3
+ import { _decorator, Node } from 'cc';
4
+ import { GameConfig } from 'db://assets/start/Interface/GameConfig';
5
+ const { ccclass } = _decorator;
6
+
7
+ @ccclass('ExTween')
8
+ export class ExTween extends Tween<any> {
9
+ key: string;
10
+ constructor(target: Node, key: string) {
11
+ super(target);
12
+ this.key = key;
13
+ TweenManager.addTween(key, this);
14
+ }
15
+ to(duration: number, props: __private._cocos_tween_tween__ConstructorType<any>, opts?: ITweenOption): Tween<any> {
16
+ super.to(duration, props, opts);
17
+ return this
18
+ }
19
+ by(duration: number, props: __private._cocos_tween_tween__ConstructorType<any>, opts?: ITweenOption): Tween<any> {
20
+ super.by(duration, props, opts);
21
+ return this
22
+ }
23
+ union(): Tween<any> {
24
+ return super.union()
25
+ }
26
+
27
+ call(callback: Function): Tween<any> {
28
+ const wrappedCallback = () => {
29
+ // 调用用户回调
30
+ callback();
31
+ };
32
+ super.call(wrappedCallback);
33
+ return this;
34
+ }
35
+ stop(): Tween<any> {
36
+ super.stop();
37
+ return this;
38
+ }
39
+ start(): Tween<any> {
40
+ this.call(() => {
41
+ // console.log(`全部结束 ${this.key}`);
42
+ TweenManager.removeTween(this.key, this);
43
+ });
44
+ super.start();
45
+ this.pause(GameConfig.gameSpeed)//设置速度
46
+
47
+ return this
48
+ }
49
+
50
+ }
51
+
52
+ export class TweenManager {
53
+ // 字典,key对应一个数组,保存属于该key的所有ExTween实例
54
+ private static _tweensDict: Record<string, ExTween[]> = {};
55
+
56
+ /**
57
+ * 添加一个 tween 到对应 key 的数组中
58
+ * @param key 分组key,比如 node 名称或者自定义字符串
59
+ * @param tw Tween 实例
60
+ */
61
+ static addTween(key: string, tw: ExTween) {
62
+ if (!this._tweensDict[key]) {
63
+ this._tweensDict[key] = [];
64
+ }
65
+ this._tweensDict[key].push(tw);
66
+ }
67
+
68
+ /**
69
+ * 获取指定 key 下的所有 tween
70
+ * @param key 分组key
71
+ * @returns Tween数组,如果不存在则返回空数组
72
+ */
73
+ static getTweensByKey(key: string): ExTween[] {
74
+ return this._tweensDict[key] || [];
75
+ }
76
+
77
+ /**
78
+ * 从指定 key 的数组中移除某个 tween 实例
79
+ * @param key 分组key
80
+ * @param tw 要移除的 Tween 实例
81
+ */
82
+ static removeTween(key: string, tw: ExTween) {
83
+ const arr = this._tweensDict[key];
84
+ if (!arr) return;
85
+ const index = arr.indexOf(tw);
86
+ if (index !== -1) {
87
+ arr.splice(index, 1);
88
+ // 如果移除后该key对应的数组为空,则删除该key
89
+ if (arr.length === 0) {
90
+ delete this._tweensDict[key];
91
+ }
92
+ }
93
+ }
94
+
95
+ /**
96
+ * 停止并移除指定 key 下的所有 tween
97
+ * @param key 分组key
98
+ */
99
+ static stopAllByKey(key: string) {
100
+ const arr = this._tweensDict[key];
101
+ if (!arr) return;
102
+ // 停止所有 tween
103
+ arr.forEach(tw => tw.stop());
104
+ // 删除该key对应的数组
105
+ delete this._tweensDict[key];
106
+ }
107
+
108
+ /**
109
+ * 【新增】停止并移除指定 key 下的所有 tween(同 stopAllByKey)
110
+ * 逻辑上也可以叫移除所有,停掉后数组清空并删除key
111
+ * @param key 分组key
112
+ */
113
+ static removeAllByKey(key: string) {
114
+ const arr = this._tweensDict[key];
115
+ if (!arr) return;
116
+ // 逐个停止 tween
117
+ arr.forEach(tw => tw?.stop());
118
+ // 清空数组长度
119
+ arr.length = 0;
120
+ // 删除key对应的数组引用
121
+ delete this._tweensDict[key];
122
+ }
123
+
124
+ /**
125
+ * 停止并移除所有已管理的 tween(遍历字典所有key)
126
+ */
127
+ static stopAll() {
128
+ for (const key in this._tweensDict) {
129
+ this._tweensDict[key].forEach(tw => tw.stop());
130
+ }
131
+ this._tweensDict = {};
132
+ }
133
+
134
+ static pause(key: string, speed?: number) {
135
+ this._tweensDict[key]?.forEach(tw => tw?.pause(speed));
136
+ }
137
+ static resume(key: string, speed?: number) {
138
+ this._tweensDict[key]?.forEach(tw => tw?.resume(speed));
139
+ }
140
+ }
141
+
142
+ // 创建 tween 时传入 key,比如 node.name 或者你想的其他分类key
143
+ export function TweenGame(node: any, key: string): ExTween {
144
+ const tw = new ExTween(node, key);
145
+ return tw
146
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.23",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "24e7cfb8-9b50-466d-98d7-937a8be553c6",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
package/assets.meta ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "1.2.0",
3
+ "importer": "directory",
4
+ "imported": true,
5
+ "uuid": "eaf5bea5-6b92-4d35-92ff-dd5a4164e092",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
package/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ // 负责导出assets下的模块,如: export { default } from './assets/xxx.ts'
2
+ export { } from './assets/BaseEx';
package/index.ts.meta ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.23",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "0649bb79-0fd1-45d2-ba6b-56ece4f941f0",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@cc-component/cc-ex-component",
3
+ "version": "1.0.0",
4
+ "engine": ">=3.8.0",
5
+ "description": "系统组件添加常用扩展方法",
6
+ "main": "index.ts",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://gitee.com/cocos2d-zp/cococs-creator-frame-3d"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "registry": "https://registry.npmjs.org"
17
+ },
18
+ "license": "MIT"
19
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "ver": "2.0.0",
3
+ "importer": "json",
4
+ "imported": true,
5
+ "uuid": "cdfc94f9-bb5a-4211-ab24-e5799614c31a",
6
+ "files": [
7
+ ".json"
8
+ ],
9
+ "subMetas": {},
10
+ "userData": {}
11
+ }