diff --git a/assets/_Game/Scenes/Default-theme.scene b/assets/_Game/Scenes/Default-theme.scene index 62bd730..ac39828 100644 --- a/assets/_Game/Scenes/Default-theme.scene +++ b/assets/_Game/Scenes/Default-theme.scene @@ -1562,6 +1562,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 33 }, @@ -1883,6 +1884,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 41 }, @@ -2466,6 +2468,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 49 }, @@ -3021,6 +3024,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 63 }, @@ -3370,6 +3374,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 77 }, @@ -3719,6 +3724,7 @@ "__type__": "6bb6fbw5PNPYq7zksYK1kHJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 86 }, @@ -7124,6 +7130,7 @@ "__type__": "ce7b7e0d6BHlaRFoKBZN0h/", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 135 }, @@ -7794,6 +7801,7 @@ "__type__": "e3b5fa7tUtAbK3rQJ/G2Rox", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 212 }, @@ -8260,6 +8268,7 @@ "__type__": "671bfEgTTVFgLo1v+x/wd06", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 221 }, @@ -11829,6 +11838,7 @@ "__type__": "58a5aCWE8VEqJK+0wznWL24", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 311 }, @@ -14643,6 +14653,7 @@ "__type__": "c5e2dm0qXVOuKP1ju7uyMtJ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 458 }, @@ -15877,6 +15888,7 @@ "__type__": "ecf07La1rNA8YjY0h97yfWf", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 237 }, @@ -17260,6 +17272,7 @@ "__type__": "204c1A707JPjYYnhqfMvkXj", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 586 }, @@ -17726,6 +17739,7 @@ "__type__": "fe619HtEX1OQq7oeACKrANd", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 608 }, @@ -18380,6 +18394,7 @@ "__type__": "02a884WNWtExrO21yAjQDWZ", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 221 }, @@ -19025,6 +19040,7 @@ "__type__": "bed15fuvPJLIp1O3BWg43ad", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 647 }, @@ -19668,6 +19684,7 @@ "__type__": "bed15fuvPJLIp1O3BWg43ad", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 663 }, @@ -20311,6 +20328,7 @@ "__type__": "bed15fuvPJLIp1O3BWg43ad", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 682 }, @@ -20954,6 +20972,7 @@ "__type__": "bed15fuvPJLIp1O3BWg43ad", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 701 }, @@ -21633,6 +21652,7 @@ "__type__": "85a1du42gFMrIHUG6qev0l/", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 722 }, @@ -22219,6 +22239,7 @@ "__type__": "85a1du42gFMrIHUG6qev0l/", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 737 }, @@ -22805,6 +22826,7 @@ "__type__": "85a1du42gFMrIHUG6qev0l/", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 752 }, @@ -23376,6 +23398,7 @@ "__type__": "85a1du42gFMrIHUG6qev0l/", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 767 }, @@ -23549,6 +23572,7 @@ "__type__": "ca8a0x4KJRGNJFfMRlEhSED", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 783 }, @@ -31054,6 +31078,7 @@ "__type__": "402d0NRh/pCFotZG+o5aE8p", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 788 }, @@ -33513,6 +33538,7 @@ "__type__": "1f970S32ylOnofatPpSgI1Z", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 998 }, @@ -35530,6 +35556,7 @@ "__type__": "1f970S32ylOnofatPpSgI1Z", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 1133 }, @@ -36013,6 +36040,7 @@ "__type__": "85b9aaRsZBAn5sUxS5RQ3EF", "_name": "", "_objFlags": 0, + "__editorExtras__": {}, "node": { "__id__": 9 }, @@ -36039,7 +36067,7 @@ "y": -1200, "z": 0 }, - "_timePlay": 10, + "_timePlay": 120, "_clockIcon": { "__uuid__": "f7bd5166-9d5f-4d43-a3d3-58ae9a4957fc@f9941", "__expectedType__": "cc.SpriteFrame" diff --git a/assets/_Game/Scripts/Extension/Extension.ts b/assets/_Game/Scripts/Extension/Extension.ts index 3032299..e2f4b02 100644 --- a/assets/_Game/Scripts/Extension/Extension.ts +++ b/assets/_Game/Scripts/Extension/Extension.ts @@ -1,12 +1,17 @@ import { + AudioSource, Component, + Event, + Game, IVec2Like, IVec3Like, Label, Node, NodeSpace, + Sprite, Vec2, Vec3, + game, randomRangeInt, toDegree, toRadian, @@ -14,8 +19,14 @@ import { import ObjectPool from '../Pool/ObjectPool'; declare module 'cc' { + interface Game { + timeScale: number; + } + interface Component { setNodeActive(isActive: boolean): void; + setNodeActive(event: Event, customEventData?: string): void; + setNodeActive(a: boolean | Event, b?: string): void; } interface Node { @@ -32,7 +43,7 @@ declare module 'cc' { setScaleX(x: number): void; setScaleY(y: number): void; setScaleZ(z: number): void; - releaseToPool(): void; + releaseToPool(): boolean; } interface Vec2 { @@ -48,7 +59,22 @@ declare module 'cc' { } interface Label { - setString(value: string | number); + setString(value: string | number): void; + } + + interface Sprite { + setFillRange(value: number): void; + } + + interface AudioSource { + getPlaybackRate(): number; + + /** + * Set playbackRate of this audio source + * + * Note: playbackRate control may be ineffective on some platforms. + */ + setPlaybackRate(value: number): void; } } @@ -64,10 +90,35 @@ declare global { } } +//#region GAME + +Game.prototype.timeScale = 1; +// @ts-ignore +game._calculateDT = function (useFixedDeltaTime: number) { + this._useFixedDeltaTime = useFixedDeltaTime; + if (useFixedDeltaTime) { + this._startTime = performance.now(); + return this.frameTime / 1000; + } + const now = performance.now(); + this._deltaTime = now > this._startTime ? (now - this._startTime) / 1000 : 0; + if (this._deltaTime > Game.DEBUG_DT_THRESHOLD) { + this._deltaTime = this.frameTime / 1000; + } + this._startTime = now; + return this._deltaTime * this.timeScale; +}; + +//#endregion + //#region COMPONENT -Component.prototype.setNodeActive = function (isActive: boolean) { - this.node.setActive(isActive); +Component.prototype.setNodeActive = function (a: boolean | Event, b?: string) { + if (a instanceof Event) { + this.node.active = b?.toLowerCase() === 'true'; + } else { + this.node.active = a; + } }; //#endregion @@ -127,7 +178,7 @@ Node.prototype.setScaleZ = function (z: number): void { }; Node.prototype.releaseToPool = function () { - ObjectPool.release(this); + return ObjectPool.release(this); }; //#endregion @@ -190,6 +241,14 @@ Label.prototype.setString = function (value: string | number) { //#endregion +//#region SPRITE + +Sprite.prototype.setFillRange = function (value: number) { + this.fillRange = value; +}; + +//#endregion + //#region STRING String.prototype.jsonParse = function () { @@ -222,3 +281,54 @@ Array.prototype.getRandom = function (weights?: number[]) { }; //#endregion + +//#region AUDIO SOURCE + +//support audio playbackRate +//@ts-ignore +AudioSource.prototype._playbackRate = 1; +//@ts-ignores +AudioSource.prototype._syncStates = function () { + if (this._player) { + this._player.loop = this._loop; + this._player.volume = this._volume; + // this._player._sourceNode.playbackRate = this._playbackRate; + + this._operationsBeforeLoading.forEach((opInfo): void => { + if (opInfo.op === 'SEEK') { + this._cachedCurrentTime = (opInfo.params && opInfo.params[0]) as number; + if (this._player) { + // eslint-disable-next-line @typescript-eslint/no-empty-function + this._player.seek(this._cachedCurrentTime).catch((e): void => {}); + } + } else { + this[opInfo.op]?.(); + } + }); + try { + this._player._player._sourceNode.playbackRate.value = this._playbackRate; + } catch (e) { + console.log(e); + } + this._operationsBeforeLoading.length = 0; + } +}; + +AudioSource.prototype.getPlaybackRate = function () { + return this._playbackRate; +}; + +AudioSource.prototype.setPlaybackRate = function (value: number) { + if (this._player) { + try { + this._player._player._sourceNode.playbackRate.value = value; + } catch (e) { + console.log(e); + } + this._playbackRate = this._player.playbackRate; + } else { + this._playbackRate = value; + } +}; + +//#endregion diff --git a/assets/_Game/Scripts/Manager/AudioManager.ts b/assets/_Game/Scripts/Manager/AudioManager.ts index 520684b..61e12c4 100644 --- a/assets/_Game/Scripts/Manager/AudioManager.ts +++ b/assets/_Game/Scripts/Manager/AudioManager.ts @@ -1,7 +1,12 @@ -import { _decorator, AudioClip, AudioSource, sys } from 'cc'; -import 'howler'; +import { _decorator, AudioClip, AudioSource } from 'cc'; -export class SfxSource { +interface ISoundOptions { + volume?: number; + loop?: boolean; + playbackRate?: number; +} + +export class SoundSource { private _source: AudioSource; public get playing() { @@ -41,6 +46,22 @@ export class SfxSource { this._mute = value; } + public get clip() { + return this._source.clip; + } + + public set clip(value: AudioClip) { + this._source.clip = value; + } + + public get playbackRate() { + return this._source.getPlaybackRate(); + } + + public set playbackRate(value: number) { + this._source.setPlaybackRate(value); + } + constructor(audioClip: AudioClip) { this._source = new AudioSource(); this._source.playOnAwake = false; @@ -65,8 +86,9 @@ export class SfxSource { } export default class AudioManager { - private static _audioSourcesSfx: Map = new Map(); - private static _audioSourceBgm: Howl; + private static readonly storageKey = 'gad-game-galaxy-seeker-mute'; + private static _audioSourcesSfx: Map = new Map(); + private static _audioSourceBgm: SoundSource; private static _isMute: boolean = false; public static get mute() { @@ -80,33 +102,44 @@ export default class AudioManager { } public static setMute(mute: boolean) { - this._isMute = mute; - this._audioSourceBgm.mute(this._isMute); + this._audioSourceBgm.mute = mute; this._audioSourcesSfx.forEach((source) => { - source.mute = this._isMute; + source.mute = mute; }); + + this._isMute = mute; } - public static playBGM(audio: AudioClip, opts?: { volume?: number; loop?: boolean; rate?: number }) { - this._audioSourceBgm?.stop(); - this._audioSourceBgm = new Howl({ - src: audio.nativeUrl, + public static playBGM(audio: AudioClip, opts?: ISoundOptions) { + const config: ISoundOptions = { + volume: 1, loop: true, - mute: this._isMute, + playbackRate: 1, ...opts, - }); + }; + if (this._audioSourceBgm) { + this._audioSourceBgm.stop(); + this._audioSourceBgm.clip = audio; + } else { + this._audioSourceBgm = new SoundSource(audio); + } + this._audioSourceBgm.loop = config.loop; + this._audioSourceBgm.volume = config.volume; + this._audioSourceBgm.playbackRate = config.playbackRate; + this._audioSourceBgm.mute = this._isMute; this._audioSourceBgm.play(); } public static setPlayRateBGM(rate: number) { - this._audioSourceBgm.rate(rate); + this._audioSourceBgm.playbackRate = rate; } - public static playSfx(audioClip: AudioClip, opts?: { volume?: number; loop?: boolean }) { + public static playSfx(audioClip: AudioClip, opts?: ISoundOptions) { let soundSource = this._audioSourcesSfx.get(audioClip); - const config = { + const config: ISoundOptions = { volume: 1, loop: false, + playbackRate: 1, ...opts, }; @@ -118,7 +151,7 @@ export default class AudioManager { return; } - soundSource = new SfxSource(audioClip); + soundSource = new SoundSource(audioClip); soundSource.loop = config.loop; soundSource.volume = config.volume; soundSource.mute = this._isMute; @@ -138,7 +171,7 @@ export default class AudioManager { this._audioSourcesSfx.forEach((sfx) => sfx.stop()); } - public static findAudioSourcesSfx(audioClip: AudioClip): SfxSource { + public static findAudioSourcesSfx(audioClip: AudioClip): SoundSource { return this._audioSourcesSfx.get(audioClip); } } diff --git a/assets/_Game/Scripts/Pool/ObjectPool.ts b/assets/_Game/Scripts/Pool/ObjectPool.ts index 7373418..af18150 100644 --- a/assets/_Game/Scripts/Pool/ObjectPool.ts +++ b/assets/_Game/Scripts/Pool/ObjectPool.ts @@ -1,4 +1,4 @@ -import { Component, Node, Prefab, director, instantiate } from 'cc'; +import { _decorator, Component, director, instantiate, Node, Prefab } from 'cc'; import IPoolable from './IPoolable'; export default class ObjectPool { @@ -6,13 +6,13 @@ export default class ObjectPool { private _actives: Node[] = []; private _prefab: Prefab; private _expandable; - private _poolHandlerComp: new () => any; + private _poolHandlerComp: (new () => any) | string; - public get actives() { + public get listActive() { return [...this._actives]; } - public get inActives() { + public get listInactive() { return [...this._inactive]; } @@ -32,7 +32,12 @@ export default class ObjectPool { return this.countInactive + this.countActive; } - constructor(prefab: Prefab, size: number, expandable = true, poolHandlerComp?: new () => any | string) { + constructor( + prefab?: Prefab, + size?: number, + expandable: boolean = true, + poolHandlerComp?: (new () => any) | string, + ) { if (!!!prefab) { console.error('prefab cant be null or undefine'); return; @@ -45,14 +50,14 @@ export default class ObjectPool { let obj = instantiate(this._prefab); // create node instance obj.removeFromParent(); this._inactive.push(obj); - ObjectPool._poolLookUp[obj.uuid] = this; + ObjectPool._poolLookUp.set(obj, this); } } //#region Static - private static _poolLookUp: { [key: string]: ObjectPool } = {}; - public static release(obj: Node) { - ObjectPool._poolLookUp[obj.uuid].release(obj); + private static _poolLookUp: Map = new Map(); + public static release(obj: Node): boolean { + return ObjectPool._poolLookUp.get(obj)?.release(obj); } //#endregion @@ -81,7 +86,7 @@ export default class ObjectPool { } else if (this._expandable) { // if not enough node in the pool, we call cc.instantiate to create node obj = instantiate(this._prefab); - ObjectPool._poolLookUp[obj.uuid] = this; + ObjectPool._poolLookUp.set(obj, this); } else { obj = this._actives.shift(); obj.removeFromParent(); @@ -90,45 +95,52 @@ export default class ObjectPool { obj.setParent(parent); this._actives.push(obj); // Invoke pool handler - const handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null; + let handler: Component = null; + if (typeof this._poolHandlerComp == 'string') { + handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null; + } else { + handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null; + } if (handler) { (handler as unknown as IPoolable)?.onGet(); } if (classConstructor) { - return handler == classConstructor ? handler : obj.getComponent(classConstructor); + return obj.getComponent(classConstructor); } return obj; } - public release(obj: Node): void; - public release(obj: T): void; - public release(obj: T | Node): void { + public release(obj: Node): boolean; + public release(obj: T): boolean; + public release(obj: T | Node): boolean { let node = obj instanceof Node ? obj : obj.node; const index = this._actives.indexOf(node); //check obj is belongs to pool - if (index === -1) return; + if (index === -1) return false; this._actives.splice(index, 1); this._inactive.push(node); // Invoke pool handler - const handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null; + let handler: Component = null; + if (typeof this._poolHandlerComp == 'string') { + handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null; + } else { + handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null; + } if (handler) { (handler as unknown as IPoolable)?.onRelease(); } // Remove from parent, but don't cleanup node.removeFromParent(); + return true; } public clear() { this.all.forEach((obj) => obj.destroy()); this._inactive = []; this._actives = []; - Object.keys(ObjectPool._poolLookUp).forEach((key) => { - if (ObjectPool._poolLookUp[key] === this) { - delete ObjectPool._poolLookUp[key]; - } - }); + ObjectPool._poolLookUp.clear(); } public releaseAll() { diff --git a/preview-template/index.ejs b/preview-template/index.ejs new file mode 100644 index 0000000..d302705 --- /dev/null +++ b/preview-template/index.ejs @@ -0,0 +1,50 @@ + + + + + + + <%=title%> + + + + + + + + + + + + + + + + <%- include(cocosToolBar, {config: config}) %> +
+
+
+
+ +
+
+
+
+
+
+ <%=tip_sceneIsEmpty%> +
+
+ +
+
+
+ <%- include(cocosTemplate, {}) %> + + + \ No newline at end of file