13
									
								
								assets/Script/Engine.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "89004b78-f84d-4134-8e8c-f51c5c3800df", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "a69fe64f-177f-4e4b-83f0-1f418203d85f", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "f9edb32f-c4ab-4e5d-8270-71fa609e1db7", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								assets/Script/Engine/CatanEngine/CSharp/String.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								assets/Script/Engine/CatanEngine/CSharp/String.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | interface StringConstructor {   | ||||||
|  |     IsNullOrEmpty: (value: string) => boolean; | ||||||
|  |     Format: (format: string, ...args: any[]) => string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String.IsNullOrEmpty = function (value: string): boolean {   | ||||||
|  |     return value === undefined || value === null || value.trim() === ''; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | String.Format = function (format: string, ...args: any[]): string { | ||||||
|  |     return format.replace(/{(\d+)}/g, (match, index) => { | ||||||
|  |         let value = args[index]; | ||||||
|  |         if (value === null || value === undefined) return ''; | ||||||
|  |         return '' + value; | ||||||
|  |     }); | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/CatanEngine/CSharp/String.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/CatanEngine/CSharp/String.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "0c3d1ca6-bdaf-4a00-b209-6ef460802cdc", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp/System.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp/System.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "01b35dee-e6e0-4a6e-a73c-3b49c37f1c5f", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										125
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/Action.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/Action.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | /** | ||||||
|  |  * 回呼函數: fnname (arg: TArg): void | ||||||
|  |  */ | ||||||
|  | interface ActionCallback<TArg> { | ||||||
|  |     (arg: TArg): void; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | interface Struct<TArg> { | ||||||
|  |     callback: ActionCallback<TArg>; | ||||||
|  |     target: any; | ||||||
|  |     once?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class Action<TArg> { | ||||||
|  |     private _queue: Struct<TArg>[] = []; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 | ||||||
|  |      * @param callback 回呼函數: fnname (arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallback(callback: ActionCallback<TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 (一次性) | ||||||
|  |      * @param callback 回呼函數: fnname (arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallbackOnce(callback: ActionCallback<TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget, | ||||||
|  |             once: true | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param callback  | ||||||
|  |      */ | ||||||
|  |     RemoveByCallback(callback: ActionCallback<TArg>) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.callback === callback) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     RemoveByBindTarget(bindTarget: any) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.target === bindTarget) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除全部事件 | ||||||
|  |      */ | ||||||
|  |     RemoveAllCallbacks() { | ||||||
|  |         this._queue.forEach(q => q.callback = undefined); | ||||||
|  |         this._queue.length = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 發送事件 | ||||||
|  |      * @param arg 參數 | ||||||
|  |      */ | ||||||
|  |     DispatchCallback(arg: TArg) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             let cleanRemoved = false; | ||||||
|  |             this._queue.slice().forEach(q => { | ||||||
|  |                 if (!q.callback) { | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (q.target) { | ||||||
|  |                     q.callback.call(q.target, arg); | ||||||
|  |                 } else { | ||||||
|  |                     q.callback(arg); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (q.once) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             if (cleanRemoved) { | ||||||
|  |                 index = this._queue.length; | ||||||
|  |                 if (index > 0) { | ||||||
|  |                     while (index--) { | ||||||
|  |                         let q = this._queue[index]; | ||||||
|  |                         if (!q.callback) { | ||||||
|  |                             this._queue.splice(index, 1); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "ea9bf762-40a7-4bab-b949-8d5b3d4289e2", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | import { Action } from "./Action"; | ||||||
|  | import { ActionWithType } from "./ActionWithType"; | ||||||
|  | import { ActionWithType2 } from "./ActionWithType2"; | ||||||
|  |  | ||||||
|  | const {ccclass, property} = cc._decorator; | ||||||
|  |  | ||||||
|  | enum CustomType { | ||||||
|  |     Ex1, Ex2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class CustomEvent extends ActionWithType<CustomType, number> {} | ||||||
|  | class CustomEvent2 extends ActionWithType2<CustomType, number> {} | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class NewClass extends cc.Component { | ||||||
|  |     callback: Action<number> = new Action<number>(); | ||||||
|  |     customCallback: CustomEvent = new CustomEvent(); | ||||||
|  |     customCallback2: CustomEvent2 = new CustomEvent2(); | ||||||
|  |  | ||||||
|  |     private num: number = 0; | ||||||
|  |  | ||||||
|  |     start () { | ||||||
|  |         this.callback.AddCallback(this.CB, this); | ||||||
|  |         this.callback.AddCallbackOnce(this.OnceCB, this); | ||||||
|  |  | ||||||
|  |         this.customCallback.AddCallback(CustomType.Ex1, this.CBType, this); | ||||||
|  |         this.customCallback.AddCallbackOnce(CustomType.Ex2, this.OnceCBType, this); | ||||||
|  |  | ||||||
|  |         this.customCallback2.AddCallback(CustomType.Ex2, this.CBTypeAllin1, this); | ||||||
|  |         this.customCallback2.AddCallbackOnce(CustomType.Ex1, this.CBTypeAllin1, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     DispatchClick() { | ||||||
|  |         this.num++; | ||||||
|  |  | ||||||
|  |         this.callback.DispatchCallback(this.num); | ||||||
|  |  | ||||||
|  |         this.customCallback.DispatchCallback(CustomType.Ex1, this.num); | ||||||
|  |         this.customCallback.DispatchCallback(CustomType.Ex2, this.num); | ||||||
|  |  | ||||||
|  |         this.customCallback2.DispatchCallback(CustomType.Ex1, this.num); | ||||||
|  |         this.customCallback2.DispatchCallback(CustomType.Ex2, this.num); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     RemoveEventClick() { | ||||||
|  |         this.callback.RemoveByCallback(this.CB); | ||||||
|  |         // this.callback.RemoveByCallback(this.OnceCB); | ||||||
|  |         // this.callback.RemoveByBindTarget(this); | ||||||
|  |         // this.callback.RemoveAll(); | ||||||
|  |  | ||||||
|  |         // this.callbackWithType.RemoveByCallback(this.CBType); | ||||||
|  |         // this.callbackWithType.RemoveByCallback(this.OnceCBType); | ||||||
|  |         this.customCallback.RemoveByType(CustomType.Ex1); | ||||||
|  |         // this.callbackWithType.RemoveByType(CustomType.Ex2); | ||||||
|  |         // this.callbackWithType.RemoveByBindTarget(this); | ||||||
|  |         // this.callbackWithType.RemoveAll(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     OnceCB(x: number) { | ||||||
|  |         cc.log(`OnceCB [${this.num}]`); | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     CB(x: number) { | ||||||
|  |         cc.log(`CB [${this.num}]`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     OnceCBType(x: number) { | ||||||
|  |         cc.log(`OnceCBType [${this.num}]`); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     CBType(x: number) { | ||||||
|  |         cc.log(`CBType [${this.num}]`); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     CBTypeAllin1(type: CustomType,x: number) { | ||||||
|  |         // switch (type) { | ||||||
|  |         //     case CustomType.Ex1: | ||||||
|  |         //         break; | ||||||
|  |         //     case CustomType.Ex2: | ||||||
|  |         //         break; | ||||||
|  |         // } | ||||||
|  |          | ||||||
|  |         cc.log(`CBTypeAllin1 [${CustomType[type]}][${this.num}]`); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "cc645b73-6192-414d-a5bc-4220c24e322d", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										166
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/ActionWithType.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/ActionWithType.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,166 @@ | |||||||
|  | /** | ||||||
|  |  * 回呼函數: fnname (arg: TArg): void | ||||||
|  |  */ | ||||||
|  | interface ActionCallback<TArg> { | ||||||
|  |     (arg: TArg): void; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | interface Struct<TType, TArg> { | ||||||
|  |     callback: ActionCallback<TArg>; | ||||||
|  |     target: any; | ||||||
|  |     type: TType; | ||||||
|  |     once?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class ActionWithType<TType, TArg> { | ||||||
|  |     private _queue: Struct<TType, TArg>[] = []; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 | ||||||
|  |      * @param callback 回呼函數: fnname (arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallback(type: TType, callback: ActionCallback<TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TType, TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget, | ||||||
|  |             type: type | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 (一次性) | ||||||
|  |      * @param callback 回呼函數: fnname (arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallbackOnce(type: TType, callback: ActionCallback<TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TType, TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget, | ||||||
|  |             type: type, | ||||||
|  |             once: true | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param callback  | ||||||
|  |      */ | ||||||
|  |     RemoveByCallback(callback: ActionCallback<TArg>) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.callback === callback) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     RemoveByBindTarget(bindTarget: any) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.target === bindTarget) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      */ | ||||||
|  |     RemoveByType(type: TType) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.type === type) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      * @param callback  | ||||||
|  |      */ | ||||||
|  |     RemoveCallback(type:TType, callback: ActionCallback<TArg>) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || (q.type === type && q.callback === callback)) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除全部事件 | ||||||
|  |      */ | ||||||
|  |     RemoveAllCallbacks() { | ||||||
|  |         this._queue.forEach(q => q.callback = undefined); | ||||||
|  |         this._queue.length = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 發送事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      * @param arg 參數 | ||||||
|  |      */ | ||||||
|  |     DispatchCallback(type: TType, arg: TArg) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             let cleanRemoved = false; | ||||||
|  |             this._queue.slice().forEach(q => { | ||||||
|  |                 if (!q.callback) | ||||||
|  |                 { | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 if (q.type !== type) return; | ||||||
|  |  | ||||||
|  |                 if (q.target) { | ||||||
|  |                     q.callback.call(q.target, arg); | ||||||
|  |                 } else { | ||||||
|  |                     q.callback(arg); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 if (q.once) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             if (cleanRemoved) { | ||||||
|  |                 index = this._queue.length; | ||||||
|  |                 if (index > 0) { | ||||||
|  |                     while (index--) { | ||||||
|  |                         let q = this._queue[index]; | ||||||
|  |                         if (!q.callback) { | ||||||
|  |                             this._queue.splice(index, 1); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "61d770ec-24e2-425b-b66b-2b03e192e45b", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,166 @@ | |||||||
|  | /** | ||||||
|  |  * 回呼函數: fnname (type: TType, arg: TArg): void | ||||||
|  |  */ | ||||||
|  | interface ActionCallback<TType, TArg> { | ||||||
|  |     (type: TType, arg: TArg): void; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | interface Struct<TType, TArg> { | ||||||
|  |     callback: ActionCallback<TType, TArg>; | ||||||
|  |     target: any; | ||||||
|  |     type: TType; | ||||||
|  |     once?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class ActionWithType2<TType, TArg> { | ||||||
|  |     private _queue: Struct<TType, TArg>[] = []; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 | ||||||
|  |      * @param callback 回呼函數: fnname (type: TType, arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallback(type: TType, callback: ActionCallback<TType, TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TType, TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget, | ||||||
|  |             type: type | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 監聽事件 (一次性) | ||||||
|  |      * @param callback 回呼函數: fnname (type: TType, arg: TArg): void | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     AddCallbackOnce(type: TType, callback: ActionCallback<TType, TArg>, bindTarget?: any) { | ||||||
|  |         let q = <Struct<TType, TArg>> { | ||||||
|  |             callback: callback, | ||||||
|  |             target: bindTarget, | ||||||
|  |             type: type, | ||||||
|  |             once: true | ||||||
|  |         }; | ||||||
|  |         this._queue.push(q); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param callback  | ||||||
|  |      */ | ||||||
|  |     RemoveByCallback(callback: ActionCallback<TType, TArg>) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.callback === callback) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param bindTarget 回呼時this綁定的對象 | ||||||
|  |      */ | ||||||
|  |     RemoveByBindTarget(bindTarget: any) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.target === bindTarget) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      */ | ||||||
|  |     RemoveByType(type: TType) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || q.type === type) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      * @param callback  | ||||||
|  |      */ | ||||||
|  |     RemoveCallback(type:TType, callback: ActionCallback<TType, TArg>) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             while (index--) { | ||||||
|  |                 let q = this._queue[index]; | ||||||
|  |                 if (!q.callback || (q.type === type && q.callback === callback)) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     this._queue.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 移除全部事件 | ||||||
|  |      */ | ||||||
|  |     RemoveAllCallbacks() { | ||||||
|  |         this._queue.forEach(q => q.callback = undefined); | ||||||
|  |         this._queue.length = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 發送事件 | ||||||
|  |      * @param type 事件類型 | ||||||
|  |      * @param arg 參數 | ||||||
|  |      */ | ||||||
|  |     DispatchCallback(type: TType, arg: TArg) { | ||||||
|  |         let index = this._queue.length; | ||||||
|  |         if (index > 0) { | ||||||
|  |             let cleanRemoved = false; | ||||||
|  |             this._queue.slice().forEach(q => { | ||||||
|  |                 if (!q.callback) | ||||||
|  |                 { | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 if (q.type !== type) return; | ||||||
|  |  | ||||||
|  |                 if (q.target) { | ||||||
|  |                     q.callback.call(q.target, type, arg); | ||||||
|  |                 } else { | ||||||
|  |                     q.callback(type, arg); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 if (q.once) { | ||||||
|  |                     q.callback = undefined; | ||||||
|  |                     cleanRemoved = true; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             if (cleanRemoved) { | ||||||
|  |                 index = this._queue.length; | ||||||
|  |                 if (index > 0) { | ||||||
|  |                     while (index--) { | ||||||
|  |                         let q = this._queue[index]; | ||||||
|  |                         if (!q.callback) { | ||||||
|  |                             this._queue.splice(index, 1); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "ed703ebd-efd4-4ec9-9b84-de748ef8f9e8", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/Text.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/CSharp/System/Text.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "09d69d12-a6d1-4bb1-bcfe-faa811632467", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,86 @@ | |||||||
|  | export module Encoding.UTF8 { | ||||||
|  |  | ||||||
|  | 	export function GetBytes(str: string) { | ||||||
|  | 		let len = str.length, resPos = -1; | ||||||
|  | 		let resArr = new Uint8Array(len * 3); | ||||||
|  | 		for (let point = 0, nextcode = 0, i = 0; i !== len;) { | ||||||
|  | 			point = str.charCodeAt(i), i += 1; | ||||||
|  | 			if (point >= 0xD800 && point <= 0xDBFF) { | ||||||
|  | 				if (i === len) { | ||||||
|  | 					resArr[resPos += 1] = 0xef; | ||||||
|  | 					resArr[resPos += 1] = 0xbf; | ||||||
|  | 					resArr[resPos += 1] = 0xbd; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				nextcode = str.charCodeAt(i); | ||||||
|  | 				if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) { | ||||||
|  | 					point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000; | ||||||
|  | 					i += 1; | ||||||
|  | 					if (point > 0xffff) { | ||||||
|  | 						resArr[resPos += 1] = (0x1e << 3) | (point >>> 18); | ||||||
|  | 						resArr[resPos += 1] = (0x2 << 6) | ((point >>> 12) & 0x3f); | ||||||
|  | 						resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); | ||||||
|  | 						resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					resArr[resPos += 1] = 0xef; | ||||||
|  | 					resArr[resPos += 1] = 0xbf; | ||||||
|  | 					resArr[resPos += 1] = 0xbd; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (point <= 0x007f) { | ||||||
|  | 				resArr[resPos += 1] = (0x0 << 7) | point; | ||||||
|  | 			} else if (point <= 0x07ff) { | ||||||
|  | 				resArr[resPos += 1] = (0x6 << 5) | (point >>> 6); | ||||||
|  | 				resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); | ||||||
|  | 			} else { | ||||||
|  | 				resArr[resPos += 1] = (0xe << 4) | (point >>> 12); | ||||||
|  | 				resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); | ||||||
|  | 				resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return resArr.subarray(0, resPos + 1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	export function GetString(array: Uint8Array) { | ||||||
|  | 		let str = ""; | ||||||
|  | 		let i = 0, len = array.length; | ||||||
|  | 		while (i < len) { | ||||||
|  | 			let c = array[i++]; | ||||||
|  | 			switch (c >> 4) { | ||||||
|  | 				case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: | ||||||
|  | 					str += String.fromCharCode(c); | ||||||
|  | 					break; | ||||||
|  | 				case 12: case 13: | ||||||
|  | 					str += String.fromCharCode(((c & 0x1F) << 6) | (array[i++] & 0x3F)); | ||||||
|  | 					break; | ||||||
|  | 				case 14: | ||||||
|  | 					str += String.fromCharCode(((c & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | ((array[i++] & 0x3F) << 0)); | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return str; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	export function b64EncodeUnicode(str) { | ||||||
|  | 		return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { | ||||||
|  | 			return String.fromCharCode('0x' + p1); | ||||||
|  | 		})); | ||||||
|  | 	} | ||||||
|  | 	export function b64DecodeUnicode(str) { | ||||||
|  | 		return decodeURIComponent(atob(str).split('').map(function (c) { | ||||||
|  | 			return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); | ||||||
|  | 		}).join('')); | ||||||
|  | 	} | ||||||
|  | 	export function isBase64(str) { | ||||||
|  | 		if (str === '' || str.trim() === '') { return false; } | ||||||
|  | 		try { | ||||||
|  | 			return btoa(atob(str)) == str; | ||||||
|  | 		} catch (err) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "43bf5724-e939-4189-b981-c32ef694e5a5", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "9f510f2b-83d8-4097-8683-32d6134323fb", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,43 @@ | |||||||
|  | const CANCEL = Symbol(); | ||||||
|  |  | ||||||
|  | export interface CancellationToken { | ||||||
|  |     readonly IsCancellationRequested: boolean; | ||||||
|  |     ThrowIfCancellationRequested(): void; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class CancellationTokenSource { | ||||||
|  |     readonly Token: CancellationToken; | ||||||
|  |  | ||||||
|  |     constructor() { | ||||||
|  |         this.Token = new CancellationTokenImpl(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Cancel() { | ||||||
|  |         this.Token[CANCEL](); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class TaskCancelledException extends Error { | ||||||
|  |     constructor() { | ||||||
|  |         super("Task Cancelled"); | ||||||
|  |         Reflect.setPrototypeOf(this, TaskCancelledException.prototype); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class CancellationTokenImpl implements CancellationToken { | ||||||
|  |     IsCancellationRequested: boolean; | ||||||
|  |  | ||||||
|  |     constructor() { | ||||||
|  |         this.IsCancellationRequested = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ThrowIfCancellationRequested() { | ||||||
|  |         if (this.IsCancellationRequested) { | ||||||
|  |             throw new TaskCancelledException(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [CANCEL]() { | ||||||
|  |         this.IsCancellationRequested = true; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "9a414131-91a8-4d02-9921-9d1ee01764c3", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/Core.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/Core.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "fbfe97a8-24ca-4f67-b049-323652c7194b", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,17 @@ | |||||||
|  | import { BaseEnumerator } from "./BaseEnumerator"; | ||||||
|  |  | ||||||
|  | export class ActionEnumerator extends BaseEnumerator { | ||||||
|  |     private _action: Function; | ||||||
|  |  | ||||||
|  |     constructor(action: Function) { | ||||||
|  |         super(); | ||||||
|  |         this._action = action; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     next(value?: any): IteratorResult<any> { | ||||||
|  |         if (this._action) { | ||||||
|  |             this._action(); | ||||||
|  |         } | ||||||
|  |         return { done: true, value: undefined }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "3cf9e5c3-520f-48a9-8821-9be76d519765", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,87 @@ | |||||||
|  | import { IEnumeratorV2, IEnumeratorV2Started } from "../IEnumeratorV2"; | ||||||
|  | import { CoroutineExecutor } from "./CoroutineExecutor"; | ||||||
|  |  | ||||||
|  | export abstract class BaseEnumerator implements IEnumeratorV2 { | ||||||
|  |     public nextEnumerator: BaseEnumerator; | ||||||
|  |  | ||||||
|  |     abstract next(value?: any): IteratorResult<any>; | ||||||
|  |      | ||||||
|  |     Start(target?: any): IEnumeratorV2Started { | ||||||
|  |         let executor = LazyLoad.EnumeratorExecutor(this, target); | ||||||
|  |         CoroutineExecutor.instance.StartCoroutine(executor); | ||||||
|  |         return executor; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Then(iterator: Iterator<any>): IEnumeratorV2 { | ||||||
|  |         if (!iterator) return this; | ||||||
|  |  | ||||||
|  |         if (iterator instanceof BaseEnumerator) { | ||||||
|  |             BaseEnumerator.getLastEnumerator(this).nextEnumerator = iterator; | ||||||
|  |             return this; | ||||||
|  |         } else { | ||||||
|  |             let enumerator = LazyLoad.SingleEnumerator(iterator); | ||||||
|  |             BaseEnumerator.getLastEnumerator(this).nextEnumerator = enumerator; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     ThenSerial(...iterators: Iterator<any>[]): IEnumeratorV2 { | ||||||
|  |         let last = BaseEnumerator.getLastEnumerator(this); | ||||||
|  |         for (let iterator of iterators) { | ||||||
|  |             if (iterator instanceof BaseEnumerator) { | ||||||
|  |                 last.nextEnumerator = iterator; | ||||||
|  |             } else { | ||||||
|  |                 let enumerator = LazyLoad.SingleEnumerator(iterator); | ||||||
|  |                 last.nextEnumerator = enumerator; | ||||||
|  |             } | ||||||
|  |             last = last.nextEnumerator; | ||||||
|  |         } | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ThenParallel(...iterators: Iterator<any>[]): IEnumeratorV2 { | ||||||
|  |         return this.Then(LazyLoad.ParallelEnumerator(...iterators)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ThenAction(action: Function, delaySeconds?:number): IEnumeratorV2 { | ||||||
|  |         if (delaySeconds > 0) { | ||||||
|  |             return this.ThenSerial(LazyLoad.WaitTimeEnumerator(delaySeconds), LazyLoad.ActionEnumerator(action)); | ||||||
|  |         } else { | ||||||
|  |             return this.Then(LazyLoad.ActionEnumerator(action)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ThenWaitTime(seconds: number): IEnumeratorV2 { | ||||||
|  |         return this.Then(LazyLoad.WaitTimeEnumerator(seconds)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static getLastEnumerator(enumerator: BaseEnumerator): BaseEnumerator { | ||||||
|  |         let next = enumerator; | ||||||
|  |         while (next.nextEnumerator) { | ||||||
|  |             next = next.nextEnumerator; | ||||||
|  |         } | ||||||
|  |         return next; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module LazyLoad { | ||||||
|  |     export function EnumeratorExecutor(enumerator: BaseEnumerator, target: any) { | ||||||
|  |         return new (require("./EnumeratorExecutor") as typeof import("./EnumeratorExecutor")).EnumeratorExecutor(enumerator, target); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     export function SingleEnumerator(iterator: Iterator<any>) { | ||||||
|  |         return new (require("./SingleEnumerator") as typeof import("./SingleEnumerator")).SingleEnumerator(iterator); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     export function ParallelEnumerator(...iterators: Iterator<any>[]) { | ||||||
|  |         return new (require("./ParallelEnumerator") as typeof import("./ParallelEnumerator")).ParallelEnumerator(iterators); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     export function WaitTimeEnumerator(seconds: number) { | ||||||
|  |         return new (require("./WaitTimeEnumerator") as typeof import("./WaitTimeEnumerator")).WaitTimeEnumerator(seconds); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     export function ActionEnumerator(action: Function) { | ||||||
|  |         return new (require("./ActionEnumerator") as typeof import("./ActionEnumerator")).ActionEnumerator(action); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "4084537c-c7e8-4d47-b283-39be77ef9685", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,95 @@ | |||||||
|  | import { EnumeratorExecutor } from "./EnumeratorExecutor"; | ||||||
|  |  | ||||||
|  | export class CoroutineExecutor { | ||||||
|  |     private static _instance: CoroutineExecutor;  | ||||||
|  |     static get instance() { | ||||||
|  |         return CoroutineExecutor._instance = CoroutineExecutor._instance || new CoroutineExecutor(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _executors: EnumeratorExecutor[] = []; | ||||||
|  |     private _nextExecutors: EnumeratorExecutor[] = []; | ||||||
|  |     private _isRunning: boolean = false; | ||||||
|  |     private _cleanRemoved: boolean = false; | ||||||
|  |     private _scheduler: cc.Scheduler; | ||||||
|  |      | ||||||
|  |     constructor() { | ||||||
|  |         this._scheduler = cc.director.getScheduler(); | ||||||
|  |         this._scheduler.enableForTarget(this); | ||||||
|  |         this._scheduler.scheduleUpdate(this, 0, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     StartCoroutine(executor: EnumeratorExecutor) { | ||||||
|  |         executor.next(0); | ||||||
|  |         //TODO: 這邊要考量next後馬上接BaseEnumerator/Iterator的情形 | ||||||
|  |          | ||||||
|  |         if (!this._isRunning) { | ||||||
|  |             this._executors.push(executor); | ||||||
|  |  | ||||||
|  |             if (this._scheduler.isTargetPaused(this)) { | ||||||
|  |                 this._scheduler.resumeTarget(this); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             this._nextExecutors.push(executor); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     StopCoroutineBy(target: any) { | ||||||
|  |         if (!target) return; | ||||||
|  |  | ||||||
|  |         for (let r of this._executors) { | ||||||
|  |             if (target === r.target) { | ||||||
|  |                 r.Stop(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         for (let r of this._nextExecutors) { | ||||||
|  |             if (target === r.target) { | ||||||
|  |                 r.Stop(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update(delta: number) { | ||||||
|  |         if (this._nextExecutors.length) { | ||||||
|  |             this._executors.push(...this._nextExecutors); | ||||||
|  |             this._nextExecutors.length = 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._cleanRemoved) { | ||||||
|  |             // 移除[doneFlag=true]的協程 | ||||||
|  |             let index = this._executors.length; | ||||||
|  |             while (index--) { | ||||||
|  |                 let r = this._executors[index]; | ||||||
|  |                 if (r.doneFlag) { | ||||||
|  |                     this._executors.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             this._cleanRemoved = false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._executors.length == 0) { | ||||||
|  |             if (CC_DEBUG) { | ||||||
|  |                 cc.log("[CoroutineV2] All coroutines done"); | ||||||
|  |             } | ||||||
|  |             this._scheduler.pauseTarget(this); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._isRunning = true; | ||||||
|  |  | ||||||
|  |         // 執行協程 | ||||||
|  |         for (let r of this._executors) { | ||||||
|  |             if (r.doneFlag || r.pauseFlag || r.childFlag)  | ||||||
|  |             { | ||||||
|  |                 if (r.doneFlag) { | ||||||
|  |                     this._cleanRemoved = true; | ||||||
|  |                 } | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             r.next(delta); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._isRunning = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "f25b1e42-90d8-4fc0-9925-6e7e92296d57", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,169 @@ | |||||||
|  | import { IEnumeratorV2Started } from "../IEnumeratorV2"; | ||||||
|  | import { BaseEnumerator } from "./BaseEnumerator"; | ||||||
|  | import { SingleEnumerator } from "./SingleEnumerator"; | ||||||
|  |  | ||||||
|  | export class EnumeratorExecutor implements IEnumeratorV2Started { | ||||||
|  |     public Current: any; | ||||||
|  |  | ||||||
|  |     public target: any; | ||||||
|  |     public pauseFlag: boolean; | ||||||
|  |     public doneFlag: boolean; | ||||||
|  |     public childFlag: boolean; | ||||||
|  |     public asyncFlag: boolean; | ||||||
|  |     public error: any; | ||||||
|  |  | ||||||
|  |     private _executor: EnumeratorExecutor; | ||||||
|  |     private _enumerator: BaseEnumerator; | ||||||
|  |  | ||||||
|  |     constructor(enumerator: BaseEnumerator, target: any) { | ||||||
|  |         this.target = target; | ||||||
|  |         this._enumerator = enumerator; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     next(delta?: any): IteratorResult<any> { | ||||||
|  |         if (this._executor && this._executor.doneFlag) { | ||||||
|  |             this._executor = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.doneFlag || (!this._enumerator && !this._executor)) { | ||||||
|  |             this.doneFlag = true; | ||||||
|  |             return { done: true, value: undefined }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.asyncFlag || this.pauseFlag) return { done: false, value: undefined }; | ||||||
|  |  | ||||||
|  |         let result: IteratorResult<any>; | ||||||
|  |  | ||||||
|  |         if (this._executor) { | ||||||
|  |             result = this._executor.next(delta); | ||||||
|  |             this.Current = this._executor.Current; | ||||||
|  |             if (this._executor.doneFlag) { | ||||||
|  |                 this._executor = null; | ||||||
|  |             } else { | ||||||
|  |                 result.done = false; | ||||||
|  |                 return result; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (!this._enumerator) { | ||||||
|  |             this.doneFlag = true; | ||||||
|  |             return { done: true, value: undefined }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             result = this._enumerator.next(delta); | ||||||
|  |             let value = result.value; | ||||||
|  |             let done = result.done; | ||||||
|  |  | ||||||
|  |             if (value) { | ||||||
|  |                 // Iterator | ||||||
|  |                 if (typeof value[Symbol.iterator] === 'function') { | ||||||
|  |                     value = new SingleEnumerator(<Iterator<any>>value); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (value instanceof BaseEnumerator) { | ||||||
|  |                     if (!done) { | ||||||
|  |                         BaseEnumerator.getLastEnumerator(value).nextEnumerator = this._enumerator; | ||||||
|  |                     } | ||||||
|  |                     this._enumerator = value; | ||||||
|  |                     result = this._enumerator.next(delta); | ||||||
|  |                     value = result.value; | ||||||
|  |                     done = result.done; | ||||||
|  |                      | ||||||
|  |                     if (value) { | ||||||
|  |                         // Iterator again | ||||||
|  |                         if (typeof value[Symbol.iterator] === 'function') { | ||||||
|  |                             value = new SingleEnumerator(<Iterator<any>>value); | ||||||
|  |                         }  | ||||||
|  |                          | ||||||
|  |                         if (value instanceof BaseEnumerator) { | ||||||
|  |                             if (!done) { | ||||||
|  |                                 BaseEnumerator.getLastEnumerator(value).nextEnumerator = this._enumerator; | ||||||
|  |                             } | ||||||
|  |                             this._enumerator = value; | ||||||
|  |                             result.done = false; | ||||||
|  |                             done = false; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 if (value instanceof EnumeratorExecutor) { | ||||||
|  |                     if (done) { | ||||||
|  |                         this._enumerator = this._enumerator.nextEnumerator; | ||||||
|  |                     } | ||||||
|  |                     value.childFlag = true; | ||||||
|  |                     result.done = false; | ||||||
|  |                     done = false; | ||||||
|  |                     this._executor = value; | ||||||
|  |                 } else if (Promise.resolve(value) === value) { | ||||||
|  |                     this.asyncFlag = true; | ||||||
|  |                     result.done = false; | ||||||
|  |                     done = false; | ||||||
|  |                     (<Promise<any>>value) | ||||||
|  |                         .then(v => { | ||||||
|  |                             this.asyncFlag = false; | ||||||
|  |                             this.Current = v; | ||||||
|  |                             if (done) { | ||||||
|  |                                 this._enumerator = this._enumerator.nextEnumerator; | ||||||
|  |                             } | ||||||
|  |                         }) | ||||||
|  |                         .catch(e => { | ||||||
|  |                             this.asyncFlag = false; | ||||||
|  |                             this.doneFlag = true; | ||||||
|  |                             this._enumerator = null; | ||||||
|  |                             this.error = e; | ||||||
|  |                             if (e instanceof Error) { | ||||||
|  |                                 cc.error(e.stack); | ||||||
|  |                             } else { | ||||||
|  |                                 cc.error(`Error: ${JSON.stringify(e)}`); | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 this.Current = value; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (done) { | ||||||
|  |                 this._enumerator = this._enumerator.nextEnumerator; | ||||||
|  |                 if (this._enumerator) { | ||||||
|  |                     result.done = false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         catch (e) | ||||||
|  |         { | ||||||
|  |             this.doneFlag = true; | ||||||
|  |             this.error = e; | ||||||
|  |             if (e instanceof Error) { | ||||||
|  |                 cc.error(e.stack); | ||||||
|  |             } else { | ||||||
|  |                 cc.error(`Error: ${JSON.stringify(e)}`); | ||||||
|  |             } | ||||||
|  |             result = { done: true, value: e }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Stop(): void { | ||||||
|  |         this.doneFlag = true; | ||||||
|  |         if (this._executor) { | ||||||
|  |             this._executor.Stop(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Pause(): void { | ||||||
|  |         this.pauseFlag = true; | ||||||
|  |         if (this._executor) { | ||||||
|  |             this._executor.Pause(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Resume(): void { | ||||||
|  |         this.pauseFlag = false; | ||||||
|  |         if (this._executor) { | ||||||
|  |             this._executor.Resume(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "91cb70ed-e6f9-4ce0-b7c5-1720087b3bd7", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,46 @@ | |||||||
|  | import { BaseEnumerator } from "./BaseEnumerator"; | ||||||
|  | import { EnumeratorExecutor } from "./EnumeratorExecutor"; | ||||||
|  | import { SingleEnumerator } from "./SingleEnumerator"; | ||||||
|  |  | ||||||
|  | export class ParallelEnumerator extends BaseEnumerator { | ||||||
|  |     private _executors: EnumeratorExecutor[] = []; | ||||||
|  |  | ||||||
|  |     constructor(iterators: Iterator<any>[]) { | ||||||
|  |         super(); | ||||||
|  |         if (iterators && iterators.length) { | ||||||
|  |             for (let iterator of iterators) { | ||||||
|  |                 if (iterator instanceof BaseEnumerator) { | ||||||
|  |                     this._executors.push(new EnumeratorExecutor(iterator, null)); | ||||||
|  |                 } else { | ||||||
|  |                     this._executors.push(new EnumeratorExecutor(new SingleEnumerator(iterator), null)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     next(value?: any): IteratorResult<any> { | ||||||
|  |         if (this._executors.length) { | ||||||
|  |             // 先移除[doneFlag=true]協程 | ||||||
|  |             let index = this._executors.length; | ||||||
|  |             while (index--) { | ||||||
|  |                 let r = this._executors[index]; | ||||||
|  |                 if (r.doneFlag) { | ||||||
|  |                     this._executors.splice(index, 1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (this._executors.length == 0) { | ||||||
|  |                 return { done: true, value: undefined }; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // 執行協程 | ||||||
|  |             for (let r of this._executors) { | ||||||
|  |                 r.next(value); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return { done: false, value: undefined }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return { done: true, value: undefined }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "017ebc9a-5152-4f94-bbaf-e3b914e87b41", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,18 @@ | |||||||
|  | import { BaseEnumerator } from "./BaseEnumerator"; | ||||||
|  |  | ||||||
|  | export class SingleEnumerator extends BaseEnumerator { | ||||||
|  |     private _iterator: Iterator<any>; | ||||||
|  |  | ||||||
|  |     constructor(iterator: Iterator<any>) { | ||||||
|  |         super(); | ||||||
|  |         this._iterator = iterator; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     next(value?: any): IteratorResult<any> { | ||||||
|  |         if (!this._iterator) { | ||||||
|  |             return { done: true, value: undefined }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return this._iterator.next(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c439d019-2da8-48b8-a65b-bff928d0fda8", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | import { BaseEnumerator } from "./BaseEnumerator"; | ||||||
|  |  | ||||||
|  | export class WaitTimeEnumerator extends BaseEnumerator { | ||||||
|  |     private _seconds: number; | ||||||
|  |  | ||||||
|  |     constructor(seconds: number) { | ||||||
|  |         super(); | ||||||
|  |         this._seconds = seconds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     next(value?: any): IteratorResult<any> { | ||||||
|  |         let delta = value as number; | ||||||
|  |         this._seconds -= delta; | ||||||
|  |  | ||||||
|  |         if (this._seconds <= 0) { | ||||||
|  |             return { done: true, value: 0 }; | ||||||
|  |         } else { | ||||||
|  |             return { done: false, value: this._seconds }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "a3038e6f-1bb4-4aff-a686-b69209df3592", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										199
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/CoroutineExample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/CoroutineExample.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | |||||||
|  | import { CoroutineV2 } from "./CoroutineV2"; | ||||||
|  | import { IEnumeratorV2Started } from "./IEnumeratorV2"; | ||||||
|  |  | ||||||
|  | const {ccclass, property} = cc._decorator; | ||||||
|  |  | ||||||
|  | class A { | ||||||
|  |     private numbers: number[] = [1, 2]; | ||||||
|  |     private index = 0; | ||||||
|  |  | ||||||
|  |     [Symbol.iterator](): IterableIterator<any> { | ||||||
|  |         return this; | ||||||
|  |     }     | ||||||
|  |      | ||||||
|  |     next(value?: any): IteratorResult<any> { | ||||||
|  |         if (this.index < this.numbers.length) { | ||||||
|  |             let value = this.numbers[this.index++]; | ||||||
|  |             cc.log(`A=> ${value}`); | ||||||
|  |             return { | ||||||
|  |                 done: false, | ||||||
|  |                 value: value | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return { done: true, value: undefined }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class CoroutineExample extends cc.Component { | ||||||
|  |     private _routine: IEnumeratorV2Started; | ||||||
|  |     private _obj: Object = { "a": true }; | ||||||
|  |     private _obj2: Object = { "b": true }; | ||||||
|  |  | ||||||
|  |     private _num: number = 3; | ||||||
|  |  | ||||||
|  |     button1Clicked() { | ||||||
|  |         // this._routine = CoroutineV2 | ||||||
|  |         //                     .Parallel(this.Coroutine1(1, 3), this.Coroutine1(4, 6)) | ||||||
|  |         //                     .ThenWaitTime(2) | ||||||
|  |         //                     .Then(this.Coroutine1(7, 9)) | ||||||
|  |         //                     .ThenWaitTime(2) | ||||||
|  |         //                     .ThenAction(() => cc.log("action callback 1")) | ||||||
|  |         //                     .ThenWaitTime(2) | ||||||
|  |         //                     .ThenAction(this.actionCallback) | ||||||
|  |         //                     //.Start(this); | ||||||
|  |         //                     .Start(this); | ||||||
|  |         // this._routine = CoroutineV2.Single(this.FunA()).Start(this); | ||||||
|  |  | ||||||
|  |         this._routine = CoroutineV2.Single(this.Test1_1()).Start(this); | ||||||
|  |         // this._routine = CoroutineV2.Single(this.Test2_1()).Start(this); | ||||||
|  |     }  | ||||||
|  |  | ||||||
|  |     *Test1_1() { | ||||||
|  |         yield null; | ||||||
|  |         yield *this.Test1_2(); | ||||||
|  |         // CoroutineV2.Single(this.Test1_3()).Start(this); | ||||||
|  |         yield this.Test1_3(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test1_2() { | ||||||
|  |         yield null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test1_3() { | ||||||
|  |         yield this.Test1_3_1(); | ||||||
|  |         yield CoroutineV2.Single(this.Test1_4()).Start(this._obj); | ||||||
|  |         // yield CoroutineV2.Single(this.Test1_4()); //.Start(this); | ||||||
|  |         // yield *this.Test1_4(); | ||||||
|  |         cc.log("main wait 3"); | ||||||
|  |         yield CoroutineV2.WaitTime(2); | ||||||
|  |         cc.log("done"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test1_3_1() { | ||||||
|  |         yield this.Test1_3_2(); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_1.1"); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_1.2"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test1_3_2() { | ||||||
|  |         yield this.Test1_3_3(); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_2.1"); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_2.2"); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_2.3"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     *Test1_3_3() { | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_3.1"); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_3.2"); | ||||||
|  |         yield CoroutineV2.WaitTime(1); | ||||||
|  |         cc.log("Test1_3_3.3"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test1_4() { | ||||||
|  |         this._num++; | ||||||
|  |         cc.log(`WaitTime2 ${this._num}`); | ||||||
|  |         yield CoroutineV2.WaitTime(2).Start(this._obj2); | ||||||
|  |         this._num++; | ||||||
|  |         cc.log(`WaitTime2 ${this._num}`); | ||||||
|  |         yield CoroutineV2.WaitTime(2).Start(this._obj2); | ||||||
|  |         this._num++; | ||||||
|  |         cc.log(`WaitTime2 ${this._num}`); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     *Test2_1() { | ||||||
|  |         cc.log("111"); | ||||||
|  |         CoroutineV2.Single(this.Test2_2()).Start(this); | ||||||
|  |         cc.log("333"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Test2_2() { | ||||||
|  |         cc.log("222"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     button2Clicked() { | ||||||
|  |         // this._routine && this._routine.Stop(); | ||||||
|  |         if (this._obj2) { | ||||||
|  |             CoroutineV2.StopCoroutinesBy(this._obj2); | ||||||
|  |             this._obj2 = null; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         if (this._obj) { | ||||||
|  |             CoroutineV2.StopCoroutinesBy(this._obj); | ||||||
|  |             this._obj = null; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         CoroutineV2.StopCoroutinesBy(this); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     button3Clicked() { | ||||||
|  |         // CoroutineV2.StopCoroutinesBy(this); | ||||||
|  |         this._routine && this._routine.Pause(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     button4Clicked() { | ||||||
|  |         // CoroutineV2.StopCoroutinesBy(this); | ||||||
|  |         this._routine && this._routine.Resume(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Coroutine1(start:number, end: number) | ||||||
|  |     { | ||||||
|  |         for (let i = start; i <= end; i++) { | ||||||
|  |             // yield CoroutineV2.WaitTime(1).Start(); // Start()可以省略, 會由外層啟動 | ||||||
|  |             // yield CoroutineV2.WaitTime(1).Start(this); // target也可以省略, 由外層的target控制 | ||||||
|  |              | ||||||
|  |             yield CoroutineV2.WaitTime(1).Start(); | ||||||
|  |             cc.log(`C1 => ${i}`); | ||||||
|  |  | ||||||
|  |             // 嵌套 | ||||||
|  |             yield CoroutineV2 | ||||||
|  |                         .WaitTime(1) | ||||||
|  |                         .ThenParallel( | ||||||
|  |                             // 再嵌套 | ||||||
|  |                             CoroutineV2.Action(() => cc.log("start parallel")), | ||||||
|  |                             this.Coroutine2(10, 2),  | ||||||
|  |                             this.Coroutine2(20, 2),  | ||||||
|  |                             new A()) | ||||||
|  |                         .ThenAction(() => cc.log("end parallel")) | ||||||
|  |                         .Start(); | ||||||
|  |  | ||||||
|  |             // Promise | ||||||
|  |             yield this.loadItemAsync("settings.json"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *Coroutine2(num: number, repeat: number) | ||||||
|  |     { | ||||||
|  |         for (let i = 0; i < repeat; i++) { | ||||||
|  |             //yield CoroutineV2.WaitTime(2); | ||||||
|  |             yield 0; | ||||||
|  |             cc.log(`C2: ${num}`); | ||||||
|  |             // yield CoroutineV2.WaitTime(1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     actionCallback() { | ||||||
|  |         cc.log("action callback 2"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     loadItemAsync(id: string): Promise<{id: string}> { | ||||||
|  |         return new Promise((resolve) => { | ||||||
|  |             cc.log('loading item start:', id); | ||||||
|  |             setTimeout(() => { | ||||||
|  |                 resolve({ id: id }); | ||||||
|  |                 cc.log('loading item done:', id); | ||||||
|  |             }, 3000); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "dfd32c11-76f6-4e38-9272-1d7966d1ef3c", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										75
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/CoroutineV2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								assets/Script/Engine/CatanEngine/CoroutineV2/CoroutineV2.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | import { IEnumeratorV2, IEnumeratorV2Started } from "./IEnumeratorV2"; | ||||||
|  | import { BaseEnumerator } from "./Core/BaseEnumerator"; | ||||||
|  | import { SingleEnumerator } from "./Core/SingleEnumerator"; | ||||||
|  | import { ParallelEnumerator } from "./Core/ParallelEnumerator"; | ||||||
|  | import { WaitTimeEnumerator } from "./Core/WaitTimeEnumerator"; | ||||||
|  | import { ActionEnumerator } from "./Core/ActionEnumerator"; | ||||||
|  | import { CoroutineExecutor } from "./Core/CoroutineExecutor"; | ||||||
|  |  | ||||||
|  | export module CoroutineV2 { | ||||||
|  |     /** | ||||||
|  |      * 啟動一般協程 | ||||||
|  |      */ | ||||||
|  |     export function StartCoroutine(iterator: Iterator<any>, target?: any): IEnumeratorV2Started { | ||||||
|  |         return Single(iterator).Start(target); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 依據IEnumeratorV2.Start(target)綁定的目標, 來停止協程 | ||||||
|  |      * @param target  | ||||||
|  |      */ | ||||||
|  |     export function StopCoroutinesBy(target: any) { | ||||||
|  |         CoroutineExecutor.instance.StopCoroutineBy(target); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 單一協程 | ||||||
|  |      */ | ||||||
|  |     export function Single(iterator: Iterator<any>): IEnumeratorV2 { | ||||||
|  |         if (iterator instanceof BaseEnumerator) { | ||||||
|  |             return iterator; | ||||||
|  |         } else { | ||||||
|  |             return new SingleEnumerator(iterator); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 平行協程 | ||||||
|  |      */ | ||||||
|  |     export function Parallel(...iterators: Iterator<any>[]): IEnumeratorV2 { | ||||||
|  |         return new ParallelEnumerator(iterators); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 序列協程 | ||||||
|  |      */ | ||||||
|  |     export function Serial(...iterators: Iterator<any>[]): IEnumeratorV2 { | ||||||
|  |         let [iterator, ...others] = iterators; | ||||||
|  |         if (iterator instanceof BaseEnumerator) { | ||||||
|  |             return iterator.ThenSerial(...others); | ||||||
|  |         } else { | ||||||
|  |             return new SingleEnumerator(iterator).ThenSerial(...others); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 執行方法協程 | ||||||
|  |      * @param action 方法 | ||||||
|  |      * @param delaySeconds 延遲秒數 | ||||||
|  |      */ | ||||||
|  |     export function Action(action: Function, delaySeconds?: number): IEnumeratorV2 { | ||||||
|  |         if (delaySeconds > 0) { | ||||||
|  |             return new WaitTimeEnumerator(delaySeconds).Then(new ActionEnumerator(action)); | ||||||
|  |         } else { | ||||||
|  |             return new ActionEnumerator(action); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 等待時間協程 | ||||||
|  |      * @param seconds 秒數 | ||||||
|  |      */ | ||||||
|  |     export function WaitTime(seconds: number): IEnumeratorV2 { | ||||||
|  |         return new WaitTimeEnumerator(seconds); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "fc38e505-bd37-44c3-9e0a-fd463bb88c51", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | export interface IEnumeratorV2 extends Iterator<any> { | ||||||
|  |     Start(target?: any): IEnumeratorV2Started; | ||||||
|  |     Then(iterator: Iterator<any>): IEnumeratorV2; | ||||||
|  |     ThenSerial(...iterators: Iterator<any>[]): IEnumeratorV2; | ||||||
|  |     ThenParallel(...iterators: Iterator<any>[]): IEnumeratorV2; | ||||||
|  |     ThenAction(action: Function, delaySeconds?: number): IEnumeratorV2; | ||||||
|  |     ThenWaitTime(seconds: number): IEnumeratorV2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface IEnumeratorV2Started { | ||||||
|  |     readonly Current: any; | ||||||
|  |  | ||||||
|  |     Pause(): void; | ||||||
|  |     Resume(): void; | ||||||
|  |     Stop(): void; | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "df3ab07d-3d2b-4552-b454-29b95223ea85", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "6f870efd-e869-4415-9cf2-138ab667cd5d", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/Core.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/Core.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "5e6c027f-ce4b-47fa-968c-f3bb6059ad81", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | import { Action } from "../../CSharp/System/Action"; | ||||||
|  | import { INetRequest } from "./INetRequest"; | ||||||
|  | import { INetResponse } from "./INetResponse"; | ||||||
|  |  | ||||||
|  | export interface INetConnector { | ||||||
|  |     readonly OnDataReceived: Action<INetResponse<any>>; | ||||||
|  |     readonly OnDisconnected: Action<void>; | ||||||
|  |     readonly IsConnected: boolean; | ||||||
|  |      | ||||||
|  |     SendAsync<TRequest, TResponse>(req: INetRequest<TRequest, TResponse>): Iterator<any>; | ||||||
|  |     Send<TRequest, TResponse>(req: INetRequest<TRequest, TResponse>); | ||||||
|  |     Logout(); | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "f97991b5-0da6-4220-ab29-13c8f8f7e405", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | import { INetResponse } from "./INetResponse"; | ||||||
|  |  | ||||||
|  | export interface INetRequest<TRequest, TResponse> { | ||||||
|  |     readonly Method: string; | ||||||
|  |     readonly MethodBack: string; | ||||||
|  |      | ||||||
|  |     Data: TRequest; | ||||||
|  |     Result: INetResponse<TResponse>; | ||||||
|  |      | ||||||
|  |     SendAsync(): Iterator<any>; | ||||||
|  |     Send(); | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "339fcf27-bdb9-4b8f-ae18-dd54c9500145", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | export interface INetResponse<TResponse> { | ||||||
|  |     readonly Method: string; | ||||||
|  |     readonly Status: number; | ||||||
|  |     readonly Data: TResponse; | ||||||
|  |     readonly IsValid: boolean; | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c4cb0cd4-b98c-4f8e-b1e6-ac3b51281b28", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/Examples.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/Examples.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "94e55972-723c-4dab-9ebc-870bd5043fca", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,69 @@ | |||||||
|  | import { CoroutineV2 } from "../../CoroutineV2/CoroutineV2"; | ||||||
|  | import { INetResponse } from "../Core/INetResponse"; | ||||||
|  | import { NetConnector } from "../NetConnector"; | ||||||
|  | import { NetManager } from "../NetManager"; | ||||||
|  | import { Slot1_SpinRequestExample } from "./Slot1_SpinRequestExample"; | ||||||
|  |  | ||||||
|  | const {ccclass, property} = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class NetTester extends cc.Component { | ||||||
|  |  | ||||||
|  |     onConnectClicked() { | ||||||
|  |         CoroutineV2.StartCoroutine(this.ConnectAsync()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *ConnectAsync() { | ||||||
|  |         if (!NetManager.HasInit) { | ||||||
|  |             let conn = new NetConnector("192.168.7.165", 9005); | ||||||
|  |             conn.OnDataReceived.AddCallback(this.OnNetDataReceived, this); | ||||||
|  |             conn.OnDisconnected.AddCallback(this.OnNetDisconnected, this); | ||||||
|  |             conn.OnLoadUIMask.AddCallback(this.OnLoadUIMask, this); | ||||||
|  |  | ||||||
|  |             NetManager.Initialize(conn); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         cc.log("連線中..."); | ||||||
|  |         yield NetManager.ConnectAsync(); // 同個connector要再次連線, 可以不用叫CasinoNetManager.Initialize(), 但要先叫CasinoNetManager.Disconnect() | ||||||
|  |         cc.log(`連線狀態: ${NetManager.IsConnected}`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onDisconnectClicked() { | ||||||
|  |         cc.log("中斷連線中..."); | ||||||
|  |         NetManager.Disconnect(); // 中斷連線 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onSendMessageClicked1() { | ||||||
|  |         cc.log("發送訊息(不使用協程)"); | ||||||
|  |         let req = new Slot1_SpinRequestExample(401); | ||||||
|  |         req.Send(); | ||||||
|  |         // CasinoNetManager.Send(req); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onSendMessageClicked2() { | ||||||
|  |         CoroutineV2.StartCoroutine(this.SendAsync()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *SendAsync() { | ||||||
|  |         cc.log("發送訊息中(使用協程)..."); | ||||||
|  |         let req = new Slot1_SpinRequestExample(399); | ||||||
|  |         yield req.SendAsync(); | ||||||
|  |         // yield CasinoNetManager.SendAsync(req); | ||||||
|  |  | ||||||
|  |         let resp = req.Result; | ||||||
|  |         cc.log(`發送協程完畢, Server回應: ${resp.Method}(${JSON.stringify(resp.Data)}), 狀態: ${resp.Status}`); | ||||||
|  |         // cc.log(`使用介面資料: ${resp.Data.slot}`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private OnNetDisconnected() { | ||||||
|  |         cc.log("[事件] 收到連線中斷事件"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private OnNetDataReceived(resp: INetResponse<any>) { | ||||||
|  |         cc.log(`[事件] 收到server呼叫: ${resp.Method}(${JSON.stringify(resp.Data)}), 狀態: ${resp.Status}`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private OnLoadUIMask(value: boolean) { | ||||||
|  |         cc.log(`[事件] LoadUIMask: ${value}`); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "0cb7df7a-d0e7-4ce1-832e-4583cf3385e5", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | import { NetRequest } from "../NetRequest"; | ||||||
|  |  | ||||||
|  | // 送給server的結構 | ||||||
|  | interface Request { | ||||||
|  |     pay: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // server回應的結構 | ||||||
|  | interface Response { | ||||||
|  |     pay: [[number, number]]; | ||||||
|  |     /**拉霸結果 */ | ||||||
|  |     slot: number[]; | ||||||
|  |     get: any[]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // class Account_CreateRequest extends CasinoRequest<number, any> { // 也可以是基本類或any, 但不建議用any, 使用介面ts才會有提示 | ||||||
|  | export class Slot1_SpinRequestExample extends NetRequest<Request, Response> { | ||||||
|  |     get Method(): string { | ||||||
|  |         return "slot1.spin"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // MethodBack預設回傳Method, 不一樣才需要覆寫 | ||||||
|  |     // get MethodBack(): string { | ||||||
|  |     //     return "slot1.freespin"; | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     constructor(totalBet: number) { | ||||||
|  |         super(); | ||||||
|  |  | ||||||
|  |         // 原本的SingleValue拿掉, 統一使用Data來存送出結構 | ||||||
|  |  | ||||||
|  |         // this.Data = 2; | ||||||
|  |         this.Data = { | ||||||
|  |             pay: totalBet, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "1af9e6af-3dc3-4d02-8b24-481adc07932a", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | export default class NetConfig { | ||||||
|  | 	/**是否顯示RPC接送JSON的LOG */ | ||||||
|  | 	public static ShowServerLog: boolean = true; | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c7f5f6a9-94fd-4f5f-9f0a-545cd14edca9", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										259
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetConnector.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetConnector.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | |||||||
|  | import { BaseEnumerator } from "../CoroutineV2/Core/BaseEnumerator"; | ||||||
|  | import { Action } from "../CSharp/System/Action"; | ||||||
|  | import { Encoding } from "../CSharp/System/Text/Encoding"; | ||||||
|  | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { INetResponse } from "./Core/INetResponse"; | ||||||
|  | import NetConfig from "./NetConfig"; | ||||||
|  |  | ||||||
|  | export class NetConnector { | ||||||
|  | 	readonly OnDataReceived: Action<INetResponse<any>> = new Action<INetResponse<any>>(); | ||||||
|  | 	readonly OnDisconnected: Action<void> = new Action<void>(); | ||||||
|  | 	readonly OnLoadUIMask: Action<boolean> = new Action<boolean>(); | ||||||
|  |  | ||||||
|  | 	get IsConnected() { | ||||||
|  | 		return this._ws && this._ws.readyState === WebSocket.OPEN; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private _host: string; | ||||||
|  | 	private _ws: WebSocket; | ||||||
|  | 	private _waitings: WsRequestEnumerator[] = []; | ||||||
|  |  | ||||||
|  | 	constructor(host: string, port: number/*, ip: string*/) { | ||||||
|  | 		let checkHttp: string = ""; | ||||||
|  | 		let index: number = host.indexOf("https://"); | ||||||
|  | 		if (index != -1) { | ||||||
|  | 			checkHttp = "https"; | ||||||
|  | 			host = host.replace("https://", ""); | ||||||
|  | 		} else { | ||||||
|  | 			checkHttp = window.location.href.substring(0, 5); | ||||||
|  | 			host = host.replace("http://", ""); | ||||||
|  | 		} | ||||||
|  | 		if (CC_DEBUG) { | ||||||
|  | 			cc.log("[事件]checkHttp=", checkHttp, host, port); | ||||||
|  | 		} | ||||||
|  | 		if (checkHttp != "https") { | ||||||
|  | 			//this._host = `ws://${host}:${port}/?ip=${ip}`; | ||||||
|  | 			this._host = `ws://${host}:${port}` | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			//this._host = `wss://${host}:${port}/?ip=${ip}`; | ||||||
|  | 			this._host = `wss://${host}:${port}`; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ConnectAsync() { | ||||||
|  | 		if (this._ws) { | ||||||
|  | 			throw new Error("請先執行CasinoNetManager.Disconnect()中斷連線"); | ||||||
|  | 		} | ||||||
|  | 		if (cc.sys.isNative && cc.sys.os == cc.sys.OS_ANDROID && this._host.indexOf("wss") !== -1) { | ||||||
|  | 			let cacert = cc.url.raw('resources/cacert.cer'); | ||||||
|  | 			if (cc.loader.md5Pipe) { | ||||||
|  | 				cacert = cc.loader.md5Pipe.transformURL(cacert) | ||||||
|  | 			} | ||||||
|  | 			//@ts-ignore | ||||||
|  | 			this._ws = new WebSocket(this._host, null, cacert) | ||||||
|  | 		} else { | ||||||
|  | 			//@ts-ignore | ||||||
|  | 			this._ws = new WebSocket(this._host); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		this._ws.binaryType = 'arraybuffer'; | ||||||
|  | 		this._ws.onopen = this.OnWebSocketOpen.bind(this); | ||||||
|  | 		this._ws.onmessage = this.OnWebSocketMessage.bind(this); | ||||||
|  | 		this._ws.onclose = this.OnWebSocketClose.bind(this); | ||||||
|  |  | ||||||
|  | 		return new WsConnectEnumerator(this._ws); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Send(req: INetRequest<any, any>) { | ||||||
|  | 		if (!this.IsConnected) return; | ||||||
|  |  | ||||||
|  | 		let json = [req.Method]; | ||||||
|  | 		if (req.Data != null && req.Data != undefined && req.Data != NaN) { | ||||||
|  | 			json[1] = req.Data; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||||
|  | 			if (req.Data != null && req.Data != undefined && req.Data != NaN) { | ||||||
|  | 				cc.log(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`); | ||||||
|  | 			} else { | ||||||
|  | 				cc.log(`[RPC] 傳送server資料: ${req.Method}()`); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		let str = JSON.stringify(json); | ||||||
|  | 		if (str.length > 65535) { | ||||||
|  | 			throw new Error('要傳的資料太大囉'); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		let strary = Encoding.UTF8.GetBytes(str); | ||||||
|  | 		let buffer = new Uint8Array(4 + strary.byteLength); | ||||||
|  | 		let u16ary = new Uint16Array(buffer.buffer, 0, 3); | ||||||
|  | 		u16ary[0] = strary.byteLength; | ||||||
|  | 		buffer[3] = 0x01; | ||||||
|  | 		buffer.set(strary, 4); | ||||||
|  |  | ||||||
|  | 		this._ws.send(buffer); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	SendAsync(req: INetRequest<any, any>, mask: boolean) { | ||||||
|  | 		let iterator = new WsRequestEnumerator(req); | ||||||
|  | 		if (!this.IsConnected) { | ||||||
|  | 			iterator.SetResponse(ErrorResponse); | ||||||
|  | 		} else { | ||||||
|  | 			this._waitings.push(iterator); | ||||||
|  | 			if (mask) { | ||||||
|  | 				this.OnLoadUIMask.DispatchCallback(true); | ||||||
|  | 			} | ||||||
|  | 			this.Send(req); | ||||||
|  | 		} | ||||||
|  | 		return iterator; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	Disconnect() { | ||||||
|  | 		this.WebSocketEnded(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private WebSocketEnded() { | ||||||
|  | 		if (!this._ws) return; | ||||||
|  |  | ||||||
|  | 		this._ws.close(); | ||||||
|  | 		this._ws.onopen = null; | ||||||
|  | 		this._ws.onmessage = null; | ||||||
|  | 		this._ws.onclose = () => { }; | ||||||
|  | 		this._ws = null; | ||||||
|  |  | ||||||
|  | 		this.CleanWaitings(); | ||||||
|  | 		this.OnDisconnected.DispatchCallback(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private CleanWaitings() { | ||||||
|  | 		for (let w of this._waitings) { | ||||||
|  | 			w.SetResponse(ErrorResponse); | ||||||
|  | 			this.OnLoadUIMask.DispatchCallback(false); | ||||||
|  | 		} | ||||||
|  | 		this._waitings.length = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private OnWebSocketOpen(e: Event) { | ||||||
|  | 		if (CC_DEBUG) { | ||||||
|  | 			cc.log(`[RPC] ${this._host} Connected.`); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private OnWebSocketMessage(e: MessageEvent) { | ||||||
|  | 		if (e.data instanceof ArrayBuffer) { | ||||||
|  | 			this.ParseRpcMessage(e.data); | ||||||
|  | 		} else if (e.data instanceof Blob) { | ||||||
|  | 			let reader = new FileReader(); | ||||||
|  | 			reader.onload = (e) => { this.ParseRpcMessage(<ArrayBuffer>reader.result); reader.onload = null; } | ||||||
|  | 			reader.readAsArrayBuffer(e.data); | ||||||
|  | 		} else { | ||||||
|  | 			throw new Error(`未知的OnWebSocketMessage(e.data)類型: ${e.data}`); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private ParseRpcMessage(buffer: ArrayBuffer) { | ||||||
|  | 		let startIndex = 0, byteLength = buffer.byteLength; | ||||||
|  | 		while (startIndex + 4 < byteLength) { | ||||||
|  | 			let strlen = new DataView(buffer, startIndex, 3).getUint16(0, true); | ||||||
|  | 			let str = Encoding.UTF8.GetString(new Uint8Array(buffer, startIndex + 4, strlen)); | ||||||
|  | 			startIndex += strlen + 4; | ||||||
|  |  | ||||||
|  | 			try { | ||||||
|  | 				let json = JSON.parse(str); | ||||||
|  | 				let method = <string>json[0]; | ||||||
|  | 				let status = <number>json[1][0]; | ||||||
|  | 				let data = json[1][1]; | ||||||
|  |  | ||||||
|  | 				let resp = <INetResponse<any>>{ | ||||||
|  | 					Method: method, | ||||||
|  | 					Status: status, | ||||||
|  | 					Data: data, | ||||||
|  | 					IsValid: method && status === 0 | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||||
|  | 					if (data) { | ||||||
|  | 						cc.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); | ||||||
|  | 					} else { | ||||||
|  | 						cc.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				let dispatch = true; | ||||||
|  | 				for (let i = 0, len = this._waitings.length; i < len; i++) { | ||||||
|  | 					let w = this._waitings[i]; | ||||||
|  | 					if (w.MethodBack === resp.Method) { | ||||||
|  | 						dispatch = false; | ||||||
|  | 						this._waitings.splice(i, 1); | ||||||
|  | 						w.SetResponse(resp); | ||||||
|  | 						this.OnLoadUIMask.DispatchCallback(false); | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (dispatch) { | ||||||
|  | 					this.OnDataReceived.DispatchCallback(resp); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			catch | ||||||
|  | 			{ | ||||||
|  | 				throw new Error(`[RPC] 無法解析Server回應: ${str}`); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private OnWebSocketClose(e: CloseEvent) { | ||||||
|  | 		this.WebSocketEnded(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ErrorResponse: INetResponse<any> = { | ||||||
|  | 	Status: -1, | ||||||
|  | 	Method: "", | ||||||
|  | 	Data: {}, | ||||||
|  | 	IsValid: false, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class WsConnectEnumerator extends BaseEnumerator { | ||||||
|  | 	private _ws: WebSocket; | ||||||
|  |  | ||||||
|  | 	constructor(ws: WebSocket) { | ||||||
|  | 		super(); | ||||||
|  | 		this._ws = ws; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	next(value?: any): IteratorResult<any> { | ||||||
|  | 		return { | ||||||
|  | 			done: this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CLOSED, | ||||||
|  | 			value: undefined | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class WsRequestEnumerator extends BaseEnumerator { | ||||||
|  | 	readonly MethodBack: string; | ||||||
|  |  | ||||||
|  | 	private _req: INetRequest<any, any>; | ||||||
|  | 	private _done: boolean = false; | ||||||
|  |  | ||||||
|  | 	constructor(req: INetRequest<any, any>) { | ||||||
|  | 		super(); | ||||||
|  |  | ||||||
|  | 		this._req = req; | ||||||
|  | 		this.MethodBack = req.MethodBack; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	SetResponse(resp: INetResponse<any>) { | ||||||
|  | 		this._req.Result = resp; | ||||||
|  | 		this._done = true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	next(value?: any): IteratorResult<any> { | ||||||
|  | 		return { | ||||||
|  | 			done: this._done, | ||||||
|  | 			value: undefined | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "221e1688-cc40-450d-9248-464978540a85", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										50
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetManager.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetManager.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { NetConnector } from "./NetConnector"; | ||||||
|  |  | ||||||
|  | export class NetManager { | ||||||
|  |     static get IsConnected() { return this._connector && this._connector.IsConnected; } | ||||||
|  |     static get HasInit() { return this._connector != null; } | ||||||
|  |  | ||||||
|  |     private static _connector: NetConnector; | ||||||
|  |  | ||||||
|  |     static Initialize(connector: NetConnector) { | ||||||
|  |         this._connector = connector; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static ConnectAsync() { | ||||||
|  |         this.CheckConnector(); | ||||||
|  |         return this._connector.ConnectAsync(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 斷線 | ||||||
|  |      */ | ||||||
|  |     static Disconnect() { | ||||||
|  |         this.CheckConnector(); | ||||||
|  |         this._connector.Disconnect(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 傳送資料給Server, 不等待回應 | ||||||
|  |      * @param req | ||||||
|  |      */ | ||||||
|  |     static Send(req: INetRequest<any, any>) { | ||||||
|  |         this.CheckConnector(); | ||||||
|  |         this._connector.Send(req); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 傳送資料給Server, 並等待回應 | ||||||
|  |      * @param req | ||||||
|  |      */ | ||||||
|  |     static SendAsync(req: INetRequest<any, any>,mask:boolean) { | ||||||
|  |         this.CheckConnector(); | ||||||
|  |         return this._connector.SendAsync(req,mask); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static CheckConnector() | ||||||
|  |     { | ||||||
|  |         if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "7c3e375d-3672-42e7-8a45-dd5ecf9d5fe8", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								assets/Script/Engine/CatanEngine/NetManagerV2/NetRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { NetManager } from "./NetManager"; | ||||||
|  |  | ||||||
|  | export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | ||||||
|  |     abstract get Method(): string; | ||||||
|  |  | ||||||
|  |     get MethodBack(): string { | ||||||
|  |         return this.Method; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Data: TResquest; | ||||||
|  |     Result: import("./Core/INetResponse").INetResponse<TResponse>; | ||||||
|  |  | ||||||
|  |     SendAsync(mask: boolean = false): Iterator<any> { | ||||||
|  |         return NetManager.SendAsync(this, mask); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Send() { | ||||||
|  |         NetManager.Send(this); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "36534597-4273-48e8-bbeb-8dde4857d26f", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								assets/Script/Engine/CatanEngine/NoSleep.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								assets/Script/Engine/CatanEngine/NoSleep.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										10
									
								
								assets/Script/Engine/CatanEngine/NoSleep.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/CatanEngine/NoSleep.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "90f2152c-2c37-4c7c-b3a3-04c8aee53c34", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "3d4ae989-9f9b-429a-a331-191a8cd8193d", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | export interface ITableJson { | ||||||
|  |     cols: string[], | ||||||
|  |     rows: any[], | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c5f8c44b-0b24-4f57-b229-4c3ad9301236", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core/ITableRow.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core/ITableRow.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | export interface ITableRow { | ||||||
|  |     Id: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 表沒有欄位 | ||||||
|  |  */ | ||||||
|  | export class WithoutRow implements ITableRow { | ||||||
|  |     Id: number; | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "104d86f0-0cb9-4cd1-a305-44ea90ee3d7f", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core/TableBase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								assets/Script/Engine/CatanEngine/TableV3/Core/TableBase.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | import { ITableRow } from "./ITableRow"; | ||||||
|  |  | ||||||
|  | export abstract class TableBase<TRow extends ITableRow> extends Array<TRow> { | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         Object.setPrototypeOf(this, new.target.prototype); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /**欄位數量 */ | ||||||
|  |     public get Count(): number { return this.length; } | ||||||
|  |     /**取得全部鍵值 */ | ||||||
|  |     public get Keys(): string[] { return Object.keys(this); } | ||||||
|  |     /**取得全部欄位值 */ | ||||||
|  |     public get Rows(): Array<TRow> { return Object["values"](this); } | ||||||
|  |     // public get Rows(): Array<TRow> { return this; } | ||||||
|  |      | ||||||
|  |     /**是否包含該Id值的欄位 */ | ||||||
|  |     public ContainsRow(id: number): boolean { | ||||||
|  |         return id in this; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "e4f18713-244f-4375-b77a-c26bf197cd3f", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/CatanEngine/TableV3/Examples.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/CatanEngine/TableV3/Examples.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "4a176b88-26e0-42ae-8acc-42ab2e942ace", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | import { TableManager } from "../TableManager"; | ||||||
|  | import { StringExampleTableRow, StringTableExample } from "./Tables/StringTableExample"; | ||||||
|  |  | ||||||
|  | const { ccclass } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class CSSettingsV3Example { | ||||||
|  |  | ||||||
|  | 	private static _stringExample: StringTableExample; | ||||||
|  | 	/** 共用_字串表#string.xlsx */ | ||||||
|  | 	public static get StringExample(): StringTableExample { return this._stringExample = this._stringExample || TableManager.InitTable("#string", StringTableExample, StringExampleTableRow); } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "04f57003-d6a1-4fee-adf8-69994db08f05", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,82 @@ | |||||||
|  | import CSSettingsV3Example from "./CSSettingsV3Example"; | ||||||
|  | import { StringExampleTable } from "./Tables/StringTableExample"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const { ccclass, property } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class TableUseExample extends cc.Component { | ||||||
|  |  | ||||||
|  |     start() { | ||||||
|  |  | ||||||
|  |         //#region StringExample表 | ||||||
|  |         cc.log("----------------#stringExample"); | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample instanceof StringExampleTable); // true | ||||||
|  |         cc.log(Array.isArray(CSSettingsV3Example.StringExample)); // true, 所以Array相關的方法都可以拿來操作 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.length); | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.Count); // 跟length一樣 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.ContainsRow(11)); // 是否包含id=11的Row | ||||||
|  |         cc.log(11 in CSSettingsV3Example.StringExample); // 同上 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample[1].MsgZnCh); | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample[1]["MsgZnCh"]); // 同上 | ||||||
|  |         cc.log(CSSettingsV3Example["StringExample"][1]["MsgZnCh"]); // 同上 | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let row of CSSettingsV3Example.StringExample) { | ||||||
|  |             if (row) { // 如果Row沒有連號, 那有可能取到undefined值, 要先判斷, 不想判斷就用 CSSettings.StringExample.Rows | ||||||
|  |                 cc.log(row.Id, row.MsgZnCh); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let id of CSSettingsV3Example.StringExample.Keys) { | ||||||
|  |             cc.log(id); // 只會列出有值的id, undefined會跳過 | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let row of CSSettingsV3Example.StringExample.Rows) { | ||||||
|  |             cc.log(row.Id, row.MsgZnCh); // 只會列出有值的Row, undefined會跳過 | ||||||
|  |         } | ||||||
|  |         //#endregion | ||||||
|  |  | ||||||
|  |         //#region StringExample表 #StringFilter表 | ||||||
|  |         cc.log("----------------#stringExample#string_filter"); | ||||||
|  |         //cc.log(CSSettings.StringExample.StringFilter instanceof StringFilterTable); // true | ||||||
|  |         cc.log(Array.isArray(CSSettingsV3Example.StringExample.StringFilter)); // true, 所以Array相關的方法都可以拿來操作 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.StringFilter.length); | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.StringFilter.Count); // 跟length一樣 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.StringFilter.ContainsRow(11)); // 是否包含id=11的Row | ||||||
|  |         cc.log(11 in CSSettingsV3Example.StringExample.StringFilter); // 同上 | ||||||
|  |  | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.StringFilter[1].FilterWord); | ||||||
|  |         cc.log(CSSettingsV3Example.StringExample.StringFilter[1]["FilterWord"]); // 同上 | ||||||
|  |         cc.log(CSSettingsV3Example["StringExample"]["StringFilter"][1]["FilterWord"]); // 同上 | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let row of CSSettingsV3Example.StringExample.StringFilter) { | ||||||
|  |             if (row) { // 如果Row沒有連號, 那有可能取到undefined值, 要先判斷, 不想判斷就用 CSSettings.StringExample.StringFilter.Rows | ||||||
|  |                 cc.log(row.Id, row.FilterWord); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let id of CSSettingsV3Example.StringExample.StringFilter.Keys) { | ||||||
|  |             cc.log(id); // 只會列出有值的id, undefined會跳過 | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         for (let row of CSSettingsV3Example.StringExample.StringFilter.Rows) { | ||||||
|  |             cc.log(row.Id, row.FilterWord); // 只會列出有值的Row, undefined會跳過 | ||||||
|  |         } | ||||||
|  |         //#endregion | ||||||
|  |  | ||||||
|  |         cc.log("----------------"); | ||||||
|  |         //CSSettingsV3.ResetTables(); // 重置表 | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "27d36ad6-da65-4673-abdb-4635a1a3d3a8", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "e65b6243-578c-4cea-ac46-1dfd4d455017", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | import { ITableRow } from "../../Core/ITableRow"; | ||||||
|  | import { TableBase } from "../../Core/TableBase"; | ||||||
|  | import { TableManager } from "../../TableManager"; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 共用_字串表#string.xlsx | ||||||
|  |  * ##程式碼由工具產生, 在此做的修改都將被覆蓋## | ||||||
|  |  */ | ||||||
|  | export class StringTableExample extends TableBase<StringExampleTableRow> { | ||||||
|  | 	private _stringFilter: StringFilterTable; | ||||||
|  | 	/**  共用_字串表#string.xlsx > #string_filter */ | ||||||
|  | 	public get StringFilter(): StringFilterTable { return this._stringFilter = this._stringFilter || TableManager.InitTable("#string#string_filter", StringFilterTable, StringFilterTableRow); } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * #string | ||||||
|  |  */ | ||||||
|  | export class StringExampleTable extends TableBase<StringExampleTableRow> {} | ||||||
|  |  | ||||||
|  | export class StringExampleTableRow implements ITableRow { | ||||||
|  | 	/** 編號 */ | ||||||
|  | 	Id: number; | ||||||
|  | 	/** 英文訊息 */ | ||||||
|  | 	MsgEn: string; | ||||||
|  | 	/** 繁體中文訊息 */ | ||||||
|  | 	MsgZnTw: string; | ||||||
|  | 	/** 簡體中文讯息 */ | ||||||
|  | 	MsgZnCh: string; | ||||||
|  | 	/** 越南文讯息 */ | ||||||
|  | 	MsgVi: string; | ||||||
|  | 	/** 泰文讯息 */ | ||||||
|  | 	MsgTh: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * #string_filter | ||||||
|  |  */ | ||||||
|  | export class StringFilterTable extends TableBase<StringFilterTableRow> {} | ||||||
|  |  | ||||||
|  | export class StringFilterTableRow implements ITableRow { | ||||||
|  | 	/** 編號 */ | ||||||
|  | 	Id: number; | ||||||
|  | 	/** 過濾字串 */ | ||||||
|  | 	FilterWord: string; | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c4bea919-96cd-40ee-a5f7-d9327414b1b2", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								assets/Script/Engine/CatanEngine/TableV3/TableManager.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								assets/Script/Engine/CatanEngine/TableV3/TableManager.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | import { ITableJson } from "./Core/ITableJson"; | ||||||
|  | import { ITableRow } from "./Core/ITableRow"; | ||||||
|  |  | ||||||
|  | export class TableManager { | ||||||
|  |     private static _tableJsons: { [key: string]: ITableJson } = {}; | ||||||
|  |  | ||||||
|  |     public static AddJsonAssets(jsonAssets: cc.JsonAsset[]) { | ||||||
|  |         if (!jsonAssets) return; | ||||||
|  |         let newAssets: cc.JsonAsset[] = jsonAssets.concat(); | ||||||
|  |         for (let jsonAsset of newAssets) { | ||||||
|  |             this.AddJsonAsset(jsonAsset); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static AddJsonAsset(jsonAsset: cc.JsonAsset) { | ||||||
|  |         if (!jsonAsset) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         for (let tableName in jsonAsset.json) { | ||||||
|  |             console.log(`TableV3 [${tableName}] json loaded`); | ||||||
|  |             this._tableJsons[tableName] = jsonAsset.json[tableName]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static GetTable(name: string): ITableJson { | ||||||
|  |         return this._tableJsons[name]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static InitTable<T extends Array<ITableRow>>(name: string, tableType: { new(): T }, rowType: { new(): ITableRow }): T { | ||||||
|  |         let json = this._tableJsons[name]; | ||||||
|  |         if (!json) { | ||||||
|  |             throw new Error(`TableV3 [${name}] 尚未載入json檔`); | ||||||
|  |         } | ||||||
|  |         let table = new tableType(); | ||||||
|  |         let cols = json.cols; | ||||||
|  |         let colLength = cols.length; | ||||||
|  |         let rows = json.rows; | ||||||
|  |         for (let r of rows) { | ||||||
|  |             let trow = new rowType(); | ||||||
|  |             for (let i = 0; i < colLength; i++) { | ||||||
|  |                 trow[cols[i]] = r[i]; | ||||||
|  |             } | ||||||
|  |             table[trow.Id] = trow; | ||||||
|  |         } | ||||||
|  |         //cc.log(`TableV3 [${name}] init done`); | ||||||
|  |         return table; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "f3bcfb76-6225-4757-a039-9018806ef54e", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/Component/Animation.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/Component/Animation.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "96902cc4-f71a-4909-b87d-f709fd0d5681", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  |  | ||||||
|  | const { ccclass, requireComponent, menu } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Animation/AnimationAutoPlay") | ||||||
|  | @requireComponent(cc.Animation) | ||||||
|  | export default class AnimationAutoPlay extends cc.Component { | ||||||
|  |  | ||||||
|  |     onEnable() { | ||||||
|  |         let anim = this.getComponent(cc.Animation); | ||||||
|  |         if (anim != null) { | ||||||
|  |             let animationState = anim.play(); | ||||||
|  |             anim.sample(animationState.name); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c51bb156-b283-4e24-a738-317650150b9d", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										153
									
								
								assets/Script/Engine/Component/Animation/AnimationRandomPlay.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								assets/Script/Engine/Component/Animation/AnimationRandomPlay.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  | const { ccclass, property, requireComponent, menu } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass("State_AnimationRandomPlay") | ||||||
|  | export class State_AnimationRandomPlay { | ||||||
|  |     @property({ displayName: "最少時間", type: cc.Float }) | ||||||
|  |     public mintime: number = 0; | ||||||
|  |     @property({ displayName: "最多時間", type: cc.Float }) | ||||||
|  |     public maxtime: number = 0; | ||||||
|  |     @property({ displayName: "權重", type: cc.Integer }) | ||||||
|  |     public weight: number = 0; | ||||||
|  |     @property({ displayName: "動畫", type: cc.AnimationClip }) | ||||||
|  |     public clip: cc.AnimationClip = null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Animation/AnimationRandomPlay") | ||||||
|  | @requireComponent(cc.Animation) | ||||||
|  | /** 可以根據權重決定多久後隨機播放甚麼動畫 */ | ||||||
|  | export class AnimationRandomPlay extends cc.Component { | ||||||
|  |     //#region public 外調參數 | ||||||
|  |  | ||||||
|  |     @property({ type: State_AnimationRandomPlay }) | ||||||
|  |     public states: State_AnimationRandomPlay[] = []; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region public 屬性 | ||||||
|  |  | ||||||
|  |     public nowPlayName: string = ""; | ||||||
|  |     public nextPlayName: string = ""; | ||||||
|  |     public nextPlayTime: number = null; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region private 屬性 | ||||||
|  |  | ||||||
|  |     private _animation: cc.Animation = null; | ||||||
|  |     private _weightAll: number[] = []; | ||||||
|  |     private _weightAllNum: number = 0; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region get set | ||||||
|  |  | ||||||
|  |     get animation(): cc.Animation { | ||||||
|  |         if (this._animation == null) { | ||||||
|  |             this._animation = this.node.getComponent(cc.Animation); | ||||||
|  |         } | ||||||
|  |         return this._animation; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Lifecycle | ||||||
|  |  | ||||||
|  |     onLoad(): void { | ||||||
|  |         let self: this = this; | ||||||
|  |         let weight: number = 0; | ||||||
|  |         for (let i: number = 0; i < this.states.length; i++) { | ||||||
|  |             weight += this.states[i].weight; | ||||||
|  |             this._weightAll.push(weight); | ||||||
|  |             this._weightAllNum += this.states[i].weight; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 一般動畫 | ||||||
|  |         this.animation.on("finished", () => { | ||||||
|  |             self.GetNextAnim(); | ||||||
|  |         }, this); | ||||||
|  |  | ||||||
|  |         // 不一般動畫 (X | ||||||
|  |         // Loop動畫 | ||||||
|  |         this.animation.on("lastframe", () => { | ||||||
|  |             self.animation.setCurrentTime(0); | ||||||
|  |             self.animation.stop(); | ||||||
|  |             self.GetNextAnim(); | ||||||
|  |         }, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onEnable(): void { | ||||||
|  |         this.GetNextAnim(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onDisable(): void { | ||||||
|  |         this.nextPlayName = ""; | ||||||
|  |         this.nextPlayTime = null; | ||||||
|  |         this.animation.setCurrentTime(0); | ||||||
|  |         this.animation.stop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onDestroy(): void { | ||||||
|  |         this.animation.targetOff(this); | ||||||
|  |         // let self: this = this; | ||||||
|  |         // this.animation.off("finished", () => { | ||||||
|  |         //     self.GetNextAnim(); | ||||||
|  |         // }, this); | ||||||
|  |         // this.animation.off("lastframe", () => { | ||||||
|  |         //     self.animation.setCurrentTime(0); | ||||||
|  |         //     self.animation.stop(); | ||||||
|  |         //     self.GetNextAnim(); | ||||||
|  |         // }, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update(dt: number): void { | ||||||
|  |         let time: number = Date.now(); | ||||||
|  |         if (this.nextPlayTime && time >= this.nextPlayTime) { | ||||||
|  |             this.nowPlayName = this.nextPlayName; | ||||||
|  |             if (this.animation.getAnimationState(this.nextPlayName)) { | ||||||
|  |                 this.animation.play(this.nextPlayName); | ||||||
|  |             } else { | ||||||
|  |                 console.error(`this node(${this.node.name}) not has animation(${this.nextPlayName})`); | ||||||
|  |                 this.animation.addClip(this.GetClip_From_states(this.nextPlayName)); | ||||||
|  |                 if (this.animation.getAnimationState(this.nextPlayName)) { | ||||||
|  |                     console.warn(`this node(${this.node.name}) add animation(${this.nextPlayName})`); | ||||||
|  |                     this.animation.play(this.nextPlayName); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             this.nextPlayName = ""; | ||||||
|  |             this.nextPlayTime = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Custom Function | ||||||
|  |  | ||||||
|  |     /** 取得下一隻動畫的時間&名稱 */ | ||||||
|  |     GetNextAnim(): void { | ||||||
|  |         let random: number = Math.floor(Math.random() * this._weightAllNum) + 1; | ||||||
|  |         for (let i: number = 0; i < this._weightAll.length; i++) { | ||||||
|  |             if (random <= this._weightAll[i]) { | ||||||
|  |                 let time: number = Math.floor(Math.random() * (this.states[i].maxtime - this.states[i].mintime + 1)) + this.states[i].mintime; | ||||||
|  |                 this.nextPlayTime = Date.now() + (time * 1000); | ||||||
|  |                 this.nextPlayName = this.states[i].clip.name; | ||||||
|  |                 // if (CC_DEBUG) { | ||||||
|  |                 //     let date: Date = new Date(this.nextPlayTime); | ||||||
|  |                 //     console.log(`nextWaitTime: ${time}, nextPlayTime: ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}, nextPlayName: ${this.nextPlayName}`); | ||||||
|  |                 // } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** 取得下一隻動畫的時間&名稱 */ | ||||||
|  |     GetClip_From_states(name: string): cc.AnimationClip { | ||||||
|  |         for (let i: number = 0; i < this.states.length; i++) { | ||||||
|  |             if (this.states[i].clip.name === name) { | ||||||
|  |                 return this.states[i].clip; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "66e6675c-c922-4952-9eb1-dc55aece8dc3", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										163
									
								
								assets/Script/Engine/Component/Animation/Animator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								assets/Script/Engine/Component/Animation/Animator.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | |||||||
|  | import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
|  | import { RandomEx } from "../../Utils/Number/RandomEx"; | ||||||
|  |  | ||||||
|  | const { ccclass, property, requireComponent, menu } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass("State") | ||||||
|  | export class State { | ||||||
|  |     @property() | ||||||
|  |     public name: string = ""; | ||||||
|  |     @property({ type: cc.AnimationClip }) | ||||||
|  |     public clip: cc.AnimationClip = null; | ||||||
|  |     @property() | ||||||
|  |     public transitionTo: string = ""; | ||||||
|  | } | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Animation/Animator") | ||||||
|  | @requireComponent(cc.Animation) | ||||||
|  | export class Animator extends cc.Component { | ||||||
|  |  | ||||||
|  |     @property({ displayName: "Default State" }) | ||||||
|  |     public defaultState: string = ""; | ||||||
|  |  | ||||||
|  |     @property({ type: State }) | ||||||
|  |     public states: State[] = []; | ||||||
|  |     public nowPlayName: string = ""; | ||||||
|  |     _animation: cc.Animation = null; | ||||||
|  |  | ||||||
|  |     /** 動畫速度 */ | ||||||
|  |     private _speed: number = 1; | ||||||
|  |     get animation(): cc.Animation { | ||||||
|  |         if (this._animation == null) { | ||||||
|  |             this._animation = this.node.getComponent(cc.Animation); | ||||||
|  |         } | ||||||
|  |         return this._animation; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onLoad(): void { | ||||||
|  |         if (CC_DEV) { | ||||||
|  |             let animationClip: cc.AnimationClip[] = this.animation.getClips(); | ||||||
|  |             for (let s of this.states) { | ||||||
|  |                 let state: State = null; | ||||||
|  |                 for (let i: number = 0; i < animationClip.length; i++) { | ||||||
|  |                     const clip: cc.AnimationClip = animationClip[i]; | ||||||
|  |                     if (s.clip != null && s.clip.name === clip.name) { | ||||||
|  |                         state = s; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (state === null) { | ||||||
|  |                     console.error(`node: ${this.node.name}, anim: ${s.clip?.name}, 動畫沒有掛在Animation上面`); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onEnable(): void { | ||||||
|  |         this.stopState(); | ||||||
|  |         if (this.defaultState !== "") { | ||||||
|  |             this.playState(this.defaultState); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     onDisable(): void { | ||||||
|  |         this.stopState(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * runStateAndWait(動作機只會接一次動畫) | ||||||
|  |      * @param name 動畫State的名稱 | ||||||
|  |      * @param callback callback 沒有transitionTo才會觸發 | ||||||
|  |      */ | ||||||
|  |     public *runStateAndWait(name: string, callback: Function = null): any { | ||||||
|  |         if (name === "") { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this.animation.stop(); | ||||||
|  |         this.nowPlayName = name; | ||||||
|  |         let state: State = null; | ||||||
|  |         for (let s of this.states) { | ||||||
|  |             if (s.name === name && s.clip != null && s.clip.isValid) { | ||||||
|  |                 state = s; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (state == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         let animationState: cc.AnimationState = this.animation.play(state.clip.name); | ||||||
|  |         animationState.speed = this.animation.currentClip.speed * this._speed; | ||||||
|  |         this.animation.sample(animationState.name); | ||||||
|  |         if (animationState.duration) { | ||||||
|  |             yield CoroutineV2.WaitTime(animationState.duration); | ||||||
|  |         } | ||||||
|  |         if (callback && !state.transitionTo) { | ||||||
|  |             callback(); | ||||||
|  |         } | ||||||
|  |         yield* this.runStateAndWait(state.transitionTo, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** playState(動作機只會接一次動畫) */ | ||||||
|  |     public playState(name: string, callback: Function = null): void { | ||||||
|  |         if (!this.node?.activeInHierarchy) { | ||||||
|  |             cc.warn(`Animator error name: ${this.node.name}, activeInHierarchy: ${this.node.activeInHierarchy}`); | ||||||
|  |         } | ||||||
|  |         CoroutineV2.Single(this.runStateAndWait(name, callback)).Start(this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** playState(隨機) */ | ||||||
|  |     public playRandomState(callback: Function = null): void { | ||||||
|  |         let random: number = RandomEx.GetInt(0, this.states.length); | ||||||
|  |         let state: State = this.states[random]; | ||||||
|  |         this.playState(state.name, callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public stopState(): void { | ||||||
|  |         CoroutineV2.StopCoroutinesBy(this); | ||||||
|  |         this.nowPlayName = ""; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 設定動畫速率(原有動畫的Speed在乘上倍率) | ||||||
|  |      * @param speed 速率 | ||||||
|  |      */ | ||||||
|  |     public SetSpeed(speed: number): void { | ||||||
|  |         this._speed = speed; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public getAnimTime(name: string, isGetNext: boolean = false): number { | ||||||
|  |         for (let s of this.states) { | ||||||
|  |             if (s.name === name && s.clip != null) { | ||||||
|  |                 let time: number = s.clip.duration / this._speed; | ||||||
|  |                 if (isGetNext && s.transitionTo !== "") { | ||||||
|  |                     time += this.getAnimTime(s.transitionTo, true); | ||||||
|  |                 } | ||||||
|  |                 return time; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 暫停在某時間 | ||||||
|  |      * @param name Animator設定的動畫名稱 | ||||||
|  |      * @param time 要停的時間點 | ||||||
|  |      * @example | ||||||
|  |      * this._anim.GotoTimeAndPause(name, 0); | ||||||
|  |      */ | ||||||
|  |     public GotoTimeAndPause(name: string, time: number = 0): void { | ||||||
|  |         let clipName: string = null; | ||||||
|  |         for (let s of this.states) { | ||||||
|  |             if (s.name === name && s.clip != null) { | ||||||
|  |                 clipName = s.clip.name; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (!clipName) { | ||||||
|  |             cc.error(`GotoFrameAndPause get clip error: ${name}`); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this.animation.play(clipName); | ||||||
|  |         this.animation.stop(clipName); | ||||||
|  |         this.animation.setCurrentTime(time); | ||||||
|  |         this.animation.sample(clipName); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/Component/Animation/Animator.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/Component/Animation/Animator.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "e0690d25-55e6-4fb2-9932-2231d0125e60", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										184
									
								
								assets/Script/Engine/Component/Animation/SPAnimator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								assets/Script/Engine/Component/Animation/SPAnimator.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | |||||||
|  | import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
|  |  | ||||||
|  | const { ccclass, property, requireComponent, menu, executeInEditMode } = cc._decorator; | ||||||
|  |  | ||||||
|  | // /** Clipname */ | ||||||
|  | // export enum Clipname { | ||||||
|  | //     None, | ||||||
|  | // } | ||||||
|  |  | ||||||
|  | @ccclass("SPState") | ||||||
|  | export class SPState { | ||||||
|  | 	@property() | ||||||
|  | 	public name: string = ""; | ||||||
|  | 	public clip: cc.AnimationClip = null; | ||||||
|  | 	@property({ displayName: "Spine動畫名稱", tooltip: "Spine動畫名稱" }) | ||||||
|  | 	public clipname: string = ""; | ||||||
|  | 	// @property({ displayName: "clipname1", type: cc.Enum(Clipname) }) | ||||||
|  | 	// public clipname1: Clipname = Clipname.None; | ||||||
|  | 	@property() | ||||||
|  | 	public isloop: boolean = false; | ||||||
|  | 	@property() | ||||||
|  | 	public transitionTo: string = ""; | ||||||
|  | } | ||||||
|  | @ccclass | ||||||
|  | // @executeInEditMode | ||||||
|  | @menu("Plug-in/Animation/SPAnimator") | ||||||
|  | @requireComponent(sp.Skeleton) | ||||||
|  | export class SPAnimator extends cc.Component { | ||||||
|  |  | ||||||
|  | 	@property({ displayName: "Default State" }) | ||||||
|  | 	public defaultState: string = ""; | ||||||
|  |  | ||||||
|  | 	@property({ type: SPState }) | ||||||
|  | 	public states: SPState[] = []; | ||||||
|  | 	public nowPlayName: string = ""; | ||||||
|  | 	private _isInit: boolean = false; | ||||||
|  | 	_animation: sp.Skeleton = null; | ||||||
|  |  | ||||||
|  | 	/** 動畫速度 */ | ||||||
|  | 	private _speed: number = 1; | ||||||
|  | 	get animation(): sp.Skeleton { | ||||||
|  | 		if (this._animation == null) { | ||||||
|  | 			this._animation = this.node.getComponent(sp.Skeleton); | ||||||
|  | 		} | ||||||
|  | 		return this._animation; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	protected onLoad(): void { | ||||||
|  | 		if (this._isInit) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		if (!this.node.activeInHierarchy) { | ||||||
|  | 			cc.error(`node: ${this.node.name}, activeInHierarchy: ${this.node.activeInHierarchy}, 動畫沒有打開無法初始化`); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		let animationClip: cc.AnimationClip[] = this.animation["skeletonData"]["_skeletonCache"].animations; | ||||||
|  | 		// if (CC_EDITOR) { | ||||||
|  | 		//     for (let i: number = 0; i < animationClip.length; i++) { | ||||||
|  | 		//         const clip: cc.AnimationClip = animationClip[i]; | ||||||
|  | 		//         Clipname[clip.name] = i; | ||||||
|  | 		//         Clipname[i.toString()] = clip.name; | ||||||
|  | 		//         cc.log(`[${i}] ${clip.name}`); | ||||||
|  | 		//     } | ||||||
|  | 		//     return; | ||||||
|  | 		// } | ||||||
|  | 		for (let s of this.states) { | ||||||
|  | 			let state: SPState = null; | ||||||
|  | 			for (let i: number = 0; i < animationClip.length; i++) { | ||||||
|  | 				const clip: cc.AnimationClip = animationClip[i]; | ||||||
|  | 				if (s.clipname === clip.name && s.clipname != null) { | ||||||
|  | 					s.clip = clip; | ||||||
|  | 					state = s; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (CC_DEV) { | ||||||
|  | 				if (state === null) { | ||||||
|  | 					console.error(`node: ${this.node.name}, anim: ${s.clipname}, 動畫沒有掛在Animation上面`); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		this._isInit = true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	protected onEnable(): void { | ||||||
|  | 		this.stopState(); | ||||||
|  | 		if (this.defaultState !== "") { | ||||||
|  | 			this.playState(this.defaultState); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	protected onDisable(): void { | ||||||
|  | 		this.stopState(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * runStateAndWait(動作機只會接一次動畫) | ||||||
|  | 	 * @param name 動畫State的名稱 | ||||||
|  | 	 * @param callback callback 沒有transitionTo才會觸發 | ||||||
|  | 	 */ | ||||||
|  | 	public *runStateAndWait(name: string, callback: Function = null): any { | ||||||
|  | 		if (!this._isInit) { | ||||||
|  | 			this.onLoad(); | ||||||
|  | 		} | ||||||
|  | 		if (name === "") { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		this.animation.setToSetupPose(); | ||||||
|  | 		let lastPlayName: string = ""; | ||||||
|  | 		for (let s of this.states) { | ||||||
|  | 			if (s.name === this.nowPlayName && s.clipname != null) { | ||||||
|  | 				lastPlayName = s.clipname; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		this.nowPlayName = name; | ||||||
|  | 		let state: SPState = null; | ||||||
|  | 		for (let s of this.states) { | ||||||
|  | 			if (s.name === name && s.clipname != null) { | ||||||
|  | 				state = s; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (state == null) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		// let animationState: cc.AnimationState = this.animation.play(state.clipname); | ||||||
|  | 		if (lastPlayName) { | ||||||
|  | 			this.animation.setMix(lastPlayName, state.clipname, 0.5); | ||||||
|  | 		} | ||||||
|  | 		this.animation.setAnimation(0, state.clipname, state.isloop); | ||||||
|  | 		// let animationState: sp.spine.TrackEntry = this.animation.setAnimation(0, state.clipname, state.isloop); | ||||||
|  | 		// animationState.speed = this.animation.currentClip.speed * this._speed; | ||||||
|  | 		// this.animation.sample(animationState.name); | ||||||
|  | 		if (state.clip.duration) { | ||||||
|  | 			yield CoroutineV2.WaitTime(state.clip.duration); | ||||||
|  | 		} | ||||||
|  | 		if (callback && !state.transitionTo) { | ||||||
|  | 			callback(); | ||||||
|  | 		} | ||||||
|  | 		yield* this.runStateAndWait(state.transitionTo, callback); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** playState(動作機只會接一次動畫) */ | ||||||
|  | 	public playState(name: string, callback: Function = null): void { | ||||||
|  | 		if (!this.node.activeInHierarchy) { | ||||||
|  | 			cc.warn(`SPAnimator error name: ${this.node.name}, activeInHierarchy: ${this.node.activeInHierarchy}`); | ||||||
|  | 		} | ||||||
|  | 		CoroutineV2.Single(this.runStateAndWait(name, callback)).Start(this); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// /** playState(隨機) */ | ||||||
|  | 	// public playRandomState(callback: Function = null): void { | ||||||
|  | 	//     let random: number = RandomEx.GetInt(0, this.states.length); | ||||||
|  | 	//     let state: SPState = this.states[random]; | ||||||
|  | 	//     this.playState(state.name, callback); | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	public stopState(): void { | ||||||
|  | 		CoroutineV2.StopCoroutinesBy(this); | ||||||
|  | 		this.nowPlayName = ""; | ||||||
|  | 		this.animation.clearTracks(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// /** | ||||||
|  | 	//  * 設定動畫速率(原有動畫的Speed在乘上倍率) | ||||||
|  | 	//  * @param speed 速率 | ||||||
|  | 	//  */ | ||||||
|  | 	// public SetSpeed(speed: number): void { | ||||||
|  | 	//     this._speed = speed; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	public getAnimTime(name: string, isGetNext: boolean = false): number { | ||||||
|  | 		for (let s of this.states) { | ||||||
|  | 			if (s.name === name && s.clipname != null) { | ||||||
|  | 				let time: number = s.clip.duration / this._speed; | ||||||
|  | 				if (isGetNext && s.transitionTo !== "") { | ||||||
|  | 					time += this.getAnimTime(s.transitionTo, true); | ||||||
|  | 				} | ||||||
|  | 				return time; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return null; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/Component/Animation/SPAnimator.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/Component/Animation/SPAnimator.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "636825f6-4e9a-4b5b-991d-8bc1afd3a1ca", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								assets/Script/Engine/Component/Animation/SkeletonExt.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								assets/Script/Engine/Component/Animation/SkeletonExt.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  |  | ||||||
|  | cc.game.once(cc.game.EVENT_ENGINE_INITED, function () { | ||||||
|  |  | ||||||
|  | 	cc.js.mixin(sp.Skeleton.prototype, { | ||||||
|  | 		update(dt) { | ||||||
|  | 			// if (CC_EDITOR) return; | ||||||
|  |  | ||||||
|  | 			if (CC_EDITOR) { | ||||||
|  | 				cc.engine._animatingInEditMode = 1; | ||||||
|  | 				cc.engine.animatingInEditMode = 1; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (this.paused) return; | ||||||
|  |  | ||||||
|  | 			dt *= this.timeScale * sp.timeScale; | ||||||
|  |  | ||||||
|  | 			if (this.isAnimationCached()) { | ||||||
|  |  | ||||||
|  | 				// Cache mode and has animation queue. | ||||||
|  | 				if (this._isAniComplete) { | ||||||
|  | 					if (this._animationQueue.length === 0 && !this._headAniInfo) { | ||||||
|  | 						let frameCache = this._frameCache; | ||||||
|  | 						if (frameCache && frameCache.isInvalid()) { | ||||||
|  | 							frameCache.updateToFrame(); | ||||||
|  | 							let frames = frameCache.frames; | ||||||
|  | 							this._curFrame = frames[frames.length - 1]; | ||||||
|  | 						} | ||||||
|  | 						return; | ||||||
|  | 					} | ||||||
|  | 					if (!this._headAniInfo) { | ||||||
|  | 						this._headAniInfo = this._animationQueue.shift(); | ||||||
|  | 					} | ||||||
|  | 					this._accTime += dt; | ||||||
|  | 					if (this._accTime > this._headAniInfo.delay) { | ||||||
|  | 						let aniInfo = this._headAniInfo; | ||||||
|  | 						this._headAniInfo = null; | ||||||
|  | 						this.setAnimation(0, aniInfo.animationName, aniInfo.loop); | ||||||
|  | 					} | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				this._updateCache(dt); | ||||||
|  | 			} else { | ||||||
|  | 				this._updateRealtime(dt); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/Component/Animation/SkeletonExt.js.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/Component/Animation/SkeletonExt.js.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "9d832050-308c-4cd9-87c6-d8542ea9c3f3", | ||||||
|  |   "importer": "javascript", | ||||||
|  |   "isPlugin": true, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": true, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								assets/Script/Engine/Component/Button.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								assets/Script/Engine/Component/Button.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.3", | ||||||
|  |   "uuid": "f5250e44-01c0-4660-8c8c-ca3e9d5c9def", | ||||||
|  |   "importer": "folder", | ||||||
|  |   "isBundle": false, | ||||||
|  |   "bundleName": "", | ||||||
|  |   "priority": 1, | ||||||
|  |   "compressionType": {}, | ||||||
|  |   "optimizeHotUpdate": {}, | ||||||
|  |   "inlineSpriteFrames": {}, | ||||||
|  |   "isRemoteBundle": {}, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
| @@ -0,0 +1,27 @@ | |||||||
|  |  | ||||||
|  | const { ccclass, requireComponent, menu, property } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Button/BlockDoubleClickButton") | ||||||
|  | @requireComponent(cc.Button) | ||||||
|  | export default class BlockDoubleClickButton extends cc.Component { | ||||||
|  |     //#region Lifecycle | ||||||
|  |  | ||||||
|  |     protected onEnable(): void { | ||||||
|  |         this.node.on("click", this.OnClickNode, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected onDisable(): void { | ||||||
|  |         this.node.off("click", this.OnClickNode, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Event | ||||||
|  |  | ||||||
|  |     public OnClickNode(event: cc.Button, customEventData: any): void { | ||||||
|  |         this.getComponent(cc.Button).interactable = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "b9536e4d-70cc-4d90-ac7d-4af5134f9cc7", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								assets/Script/Engine/Component/Button/ButtonClickCD.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								assets/Script/Engine/Component/Button/ButtonClickCD.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | // import CSSettingsV3 from "../../../FormTable/CSSettingsV3"; | ||||||
|  |  | ||||||
|  | const { ccclass, requireComponent, menu, property } = cc._decorator; | ||||||
|  |  | ||||||
|  | /** 有冷卻功能的按鈕 */ | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Button/ButtonClickCD") | ||||||
|  | @requireComponent(cc.Button) | ||||||
|  | export default class ButtonClickCD extends cc.Component { | ||||||
|  |     //#region property | ||||||
|  |  | ||||||
|  |     @property() | ||||||
|  |     public CDTime: number = 3; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public Msg: string; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region private | ||||||
|  |  | ||||||
|  |     private _nowCDTime: number = 0; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Lifecycle | ||||||
|  |  | ||||||
|  |     protected onLoad(): void { | ||||||
|  |         this.loadMsg(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async loadMsg(): Promise<void> { | ||||||
|  |         let CSSettingsV3: any = (await (import("../../../FormTable/CSSettingsV3"))).default; | ||||||
|  |         this.Msg = CSSettingsV3.prototype.CommonString(1514); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected update(dt: number): void { | ||||||
|  |         if (this._nowCDTime > 0) { | ||||||
|  |             this._nowCDTime -= dt; | ||||||
|  |             if (this._nowCDTime <= 0) { | ||||||
|  |                 this._nowCDTime = 0; | ||||||
|  |                 this.getComponent(cc.Button).interactable = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected onEnable(): void { | ||||||
|  |         this.node.on("click", this._onClick, this); | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected onDisable(): void { | ||||||
|  |         this.node.off("click", this._onClick, this); | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Custom | ||||||
|  |  | ||||||
|  |     private _onClick(event: cc.Button, customEventData: any): void { | ||||||
|  |         // if (this._nowCDTime > 0) { | ||||||
|  |         //     CSMessage.CreateYesMsg(String.Format(this.Msg, this._nowCDTime.toFixed(0))); | ||||||
|  |         //     return; | ||||||
|  |         // } | ||||||
|  |         this.getComponent(cc.Button).interactable = false; | ||||||
|  |         this._nowCDTime = this.CDTime; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async _onTouchStart(event: cc.Event.EventTouch): Promise<void> { | ||||||
|  |         if (this._nowCDTime > 0) { | ||||||
|  |             let CSMessage: any = (await (import("../../../Common/Message/CSMessage"))).default; | ||||||
|  |             CSMessage.CreateYesMsg(String.Format(this.Msg, this._nowCDTime.toFixed(0))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/Component/Button/ButtonClickCD.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/Component/Button/ButtonClickCD.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "c9dc0a70-6d91-4d02-8ceb-8be96cc33225", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								assets/Script/Engine/Component/Button/HoldButton.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								assets/Script/Engine/Component/Button/HoldButton.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  |  | ||||||
|  | const { ccclass, requireComponent, menu, property } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | @menu("Plug-in/Button/HoldButton") | ||||||
|  | @requireComponent(cc.Button) | ||||||
|  | export default class HoldButton extends cc.Component { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     @property() | ||||||
|  |     public MaxTime: number = 2; | ||||||
|  |  | ||||||
|  |     /** 是否HoldLine */ | ||||||
|  |     @property({ displayName: "是否有HoldLine", tooltip: "是否HoldLine" }) | ||||||
|  |     public IsHaveHoldLine: boolean = false; | ||||||
|  |  | ||||||
|  |     @property({ type: cc.Node, visible(): boolean { return this.IsHaveHoldLine; } }) | ||||||
|  |     public HoldLine: cc.Node = null; | ||||||
|  |  | ||||||
|  |     @property({ type: cc.Sprite, visible(): boolean { return this.IsHaveHoldLine; } }) | ||||||
|  |     public ProgressBG: cc.Sprite = null; | ||||||
|  |  | ||||||
|  |     @property({ type: cc.Sprite, visible(): boolean { return this.IsHaveHoldLine; } }) | ||||||
|  |     public ProgressLine: cc.Sprite = null; | ||||||
|  |  | ||||||
|  |     @property({ type: [cc.Component.EventHandler] }) | ||||||
|  |     public OnInvoke: cc.Component.EventHandler[] = []; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region private | ||||||
|  |  | ||||||
|  |     private _isOnInvoke: boolean = false; | ||||||
|  |  | ||||||
|  |     private _m_isMouseDown: boolean = false; | ||||||
|  |  | ||||||
|  |     private _m_pressDeltaTime: number = 0; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Lifecycle | ||||||
|  |  | ||||||
|  |     protected start(): void { | ||||||
|  |         if (this.HoldLine != null) { | ||||||
|  |             this.HoldLine.active = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected update(dt: number): void { | ||||||
|  |         if (this._m_isMouseDown) { | ||||||
|  |             this._checkHoldAutoStart(dt); | ||||||
|  |         } else { | ||||||
|  |             if (this.IsHaveHoldLine) { | ||||||
|  |                 this.HoldLine.active = false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected onEnable(): void { | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this); | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected onDisable(): void { | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this); | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Custom | ||||||
|  |  | ||||||
|  |     private _checkHoldAutoStart(deltaTime: number): void { | ||||||
|  |         this._m_pressDeltaTime += deltaTime; | ||||||
|  |  | ||||||
|  |         if (this.IsHaveHoldLine) { | ||||||
|  |             // 蓄能條顯示特效 | ||||||
|  |             this.ProgressLine.fillRange = this._m_pressDeltaTime; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._m_pressDeltaTime > this.MaxTime) { | ||||||
|  |             this.node.pauseSystemEvents(true); | ||||||
|  |  | ||||||
|  |             this._isOnInvoke = true; | ||||||
|  |             this._m_isMouseDown = false; | ||||||
|  |             if (this.IsHaveHoldLine) { | ||||||
|  |                 this.HoldLine.active = false; | ||||||
|  |             } | ||||||
|  |             this._m_pressDeltaTime = 0; | ||||||
|  |             if (this.OnInvoke != null) { | ||||||
|  |                 this.OnInvoke.forEach((eventHandler: cc.Component.EventHandler) => { | ||||||
|  |                     if (eventHandler) { | ||||||
|  |                         if (eventHandler.target === <any>"Callback" && eventHandler.component === "Callback" && eventHandler.handler) { | ||||||
|  |                             (<Function><unknown>eventHandler.handler)(); | ||||||
|  |                         } else { | ||||||
|  |                             eventHandler.emit([this.node.getComponent(cc.Button)]); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region EventT | ||||||
|  |  | ||||||
|  |     private _onTouchStart(event: cc.Event.EventTouch): void { | ||||||
|  |         if (this._m_isMouseDown) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this._m_isMouseDown = true; | ||||||
|  |         if (this.IsHaveHoldLine) { | ||||||
|  |             this.HoldLine.active = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _onTouchEnd(event: cc.Event.EventTouch): void { | ||||||
|  |         this.node.resumeSystemEvents(true); | ||||||
|  |         this._m_isMouseDown = false; | ||||||
|  |         this._m_pressDeltaTime = 0; | ||||||
|  |         if (this.IsHaveHoldLine) { | ||||||
|  |             this.HoldLine.active = false; | ||||||
|  |         } | ||||||
|  |         this._isOnInvoke = false; | ||||||
|  |         this._checkHoldAutoStart(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _onTouchCancel(event: cc.Event.EventTouch): void { | ||||||
|  |         this.node.resumeSystemEvents(true); | ||||||
|  |         this._m_isMouseDown = false; | ||||||
|  |         this._m_pressDeltaTime = 0; | ||||||
|  |         if (this.IsHaveHoldLine) { | ||||||
|  |             this.HoldLine.active = false; | ||||||
|  |         } | ||||||
|  |         this._isOnInvoke = false; | ||||||
|  |         this._checkHoldAutoStart(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								assets/Script/Engine/Component/Button/HoldButton.ts.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								assets/Script/Engine/Component/Button/HoldButton.ts.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  |   "ver": "1.1.0", | ||||||
|  |   "uuid": "1472bab3-e5de-4d9a-a761-ccf2787ad36f", | ||||||
|  |   "importer": "typescript", | ||||||
|  |   "isPlugin": false, | ||||||
|  |   "loadPluginInWeb": true, | ||||||
|  |   "loadPluginInNative": true, | ||||||
|  |   "loadPluginInEditor": false, | ||||||
|  |   "subMetas": {} | ||||||
|  | } | ||||||
							
								
								
									
										90
									
								
								assets/Script/Engine/Component/Button/LongTouchComponent.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								assets/Script/Engine/Component/Button/LongTouchComponent.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | |||||||
|  | const { ccclass, property } = cc._decorator; | ||||||
|  |  | ||||||
|  | @ccclass | ||||||
|  | export default class LongTouchComponent extends cc.Component { | ||||||
|  |     @property({ | ||||||
|  |         tooltip: "触摸回调间隔(秒)。假如为0.1,那么1秒内会回调10次 ${longTouchEvents} 事件数组" | ||||||
|  |     }) | ||||||
|  |     touchInterval: number = 0.1; | ||||||
|  |  | ||||||
|  |     @property({ | ||||||
|  |         type: [cc.Component.EventHandler], | ||||||
|  |         tooltip: "回调事件数组,每间隔 ${toucheInterval}s 回调一次" | ||||||
|  |     }) | ||||||
|  |     longTouchEvents: cc.Component.EventHandler[] = []; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 触摸计数器,用于统计本次长按的回调次数 | ||||||
|  |      */ | ||||||
|  |     private _touchCounter: number = 0; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 标记当前是否在触摸这个节点 | ||||||
|  |      */ | ||||||
|  |     private _isTouching: boolean = false; | ||||||
|  |  | ||||||
|  |     onEnable() { | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this); | ||||||
|  |         this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onDisable() { | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_START, this._onTouchStart, this); | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this); | ||||||
|  |         this.node.off(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _onTouchStart(event: cc.Event.EventTouch) { | ||||||
|  |             if (this._isTouching) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (this.node.getBoundingBoxToWorld().contains(event.getLocation())) { | ||||||
|  |                 this._isTouching = true; | ||||||
|  |             } else { | ||||||
|  |                 this._isTouching = false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (this._isTouching) { | ||||||
|  |                 // 第一次触摸立即回调一次 | ||||||
|  |                 this.publishOneTouch(); | ||||||
|  |  | ||||||
|  |                 // 然后开启计时器,计算后续的长按相当于触摸了多少次 | ||||||
|  |                 this.schedule(this._touchCounterCallback, this.touchInterval); | ||||||
|  |             } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _onTouchEnd(event: cc.Event.EventTouch) { | ||||||
|  |         this._isTouching = false; | ||||||
|  |         this._touchCounter = 0; | ||||||
|  |         this.unschedule(this._touchCounterCallback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _onTouchCancel(event: cc.Event.EventTouch) { | ||||||
|  |         this._isTouching = false; | ||||||
|  |         this._touchCounter = 0; | ||||||
|  |         this.unschedule(this._touchCounterCallback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private _touchCounterCallback() { | ||||||
|  |         if (this._isTouching) { | ||||||
|  |             this.publishOneTouch(); | ||||||
|  |         } else { | ||||||
|  |             this.unschedule(this._touchCounterCallback); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 通知出去:被点击/触摸了一次,长按时,会连续多次回调这个方法 | ||||||
|  |      */ | ||||||
|  |     private publishOneTouch() { | ||||||
|  |         if (!this._isTouching) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this._touchCounter++; | ||||||
|  |         this.longTouchEvents.forEach((eventHandler: cc.Component.EventHandler) => { | ||||||
|  |             eventHandler.emit([this._touchCounter]); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user