[add] Engine
This commit is contained in:
parent
f67e566f2a
commit
d9c19f096c
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
Loading…
Reference in New Issue
Block a user