@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.
- package/.cc-ex-component.md +12 -0
- package/assets/BaseEx.ts +636 -0
- package/assets/BaseEx.ts.meta +9 -0
- package/assets/ExTween.ts +146 -0
- package/assets/ExTween.ts.meta +9 -0
- package/assets.meta +9 -0
- package/index.ts +2 -0
- package/index.ts.meta +9 -0
- package/package.json +19 -0
- package/package.json.meta +11 -0
package/assets/BaseEx.ts
ADDED
|
@@ -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,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
|
+
}
|
package/assets.meta
ADDED
package/index.ts
ADDED
package/index.ts.meta
ADDED
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
|
+
}
|