mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-07 01:01:09 +08:00
@@ -4,7 +4,7 @@
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2023-08-28 10:02:57
|
||||
*/
|
||||
import { _decorator, Component, director, Game, game, JsonAsset, Node, resources, screen, sys } from "cc";
|
||||
import { _decorator, Component, director, Game, game, JsonAsset, Node, profiler, resources, screen, sys } from "cc";
|
||||
import { GameConfig } from "../module/config/GameConfig";
|
||||
import { GameQueryConfig } from "../module/config/GameQueryConfig";
|
||||
import { oops, version } from "./Oops";
|
||||
@@ -94,6 +94,8 @@ export class Root extends Component {
|
||||
//@ts-ignore
|
||||
oops.gui.initLayer(this.gui, config.json.gui);
|
||||
|
||||
// 初始化统计信息
|
||||
oops.config.game.stats ? profiler.showStats() : profiler.hideStats();
|
||||
// 初始化每秒传输帧数
|
||||
game.frameRate = oops.config.game.frameRate;
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ export type ListenerFunc = (event: string, ...args: any) => void
|
||||
/** 框架内部全局事件 */
|
||||
export enum EventMessage {
|
||||
/** 游戏从后台进入事件 */
|
||||
GAME_SHOW = "GAME_ENTER",
|
||||
GAME_SHOW = "onGameShow",
|
||||
/** 游戏切到后台事件 */
|
||||
GAME_HIDE = "GAME_EXIT",
|
||||
GAME_HIDE = "onGameHide",
|
||||
/** 游戏画笔尺寸变化事件 */
|
||||
GAME_RESIZE = "GAME_RESIZE",
|
||||
GAME_RESIZE = "onGameResize",
|
||||
/** 游戏全屏事件 */
|
||||
GAME_FULL_SCREEN = "GAME_FULL_SCREEN",
|
||||
GAME_FULL_SCREEN = "onGameFullScreen",
|
||||
/** 游戏旋转屏幕事件 */
|
||||
GAME_ORIENTATION = "GAME_ORIENTATION"
|
||||
GAME_ORIENTATION = "onGameOrientation"
|
||||
}
|
||||
|
||||
87
assets/core/common/loader/ZipLoader.ts
Normal file
87
assets/core/common/loader/ZipLoader.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { BufferAsset, SpriteFrame, Texture2D } from "cc";
|
||||
import { resLoader } from "./ResLoader";
|
||||
|
||||
/**
|
||||
* 加载Zip资源
|
||||
* 注:
|
||||
* 1. 使用此功能需要教程项目中项目资源目录libs/jszip目录拷贝到自己的项目中
|
||||
* 2. 选中libs/jszip/jszip文件,属性检查器中勾选导入为插件、允许指点平台加载此库
|
||||
* 3. 压缩软件打包的 game.zip 修改为 game.bin 则可在游戏中加载
|
||||
*/
|
||||
export class ZipLoader {
|
||||
private static zips: Map<string, JSZip> = new Map();
|
||||
|
||||
/**
|
||||
* 加载ZIP资源包
|
||||
* @param url
|
||||
* @returns
|
||||
*/
|
||||
static load(url: string): Promise<JSZip> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resLoader.load(url, BufferAsset, async (error: Error | null, asset: BufferAsset) => {
|
||||
if (error) return reject(error);
|
||||
|
||||
var zip = await JSZip.loadAsync(asset.buffer());
|
||||
this.zips.set(url, zip);
|
||||
resolve(zip);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
static getJson(zipName: string, path: string): Promise<any> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var zip = this.zips.get(zipName);
|
||||
if (zip == null) {
|
||||
console.error(`名为【${zipName}】的资源包不存在`);
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var file = zip.file(path);
|
||||
var json = JSON.parse(await file.async("text"));
|
||||
resolve(json);
|
||||
});
|
||||
}
|
||||
|
||||
static getSpriteFrame(zipName: string, path: string): Promise<SpriteFrame> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var zip = this.zips.get(zipName);
|
||||
if (zip == null) {
|
||||
console.error(`名为【${zipName}】的资源包不存在`);
|
||||
resolve(null!);
|
||||
return;
|
||||
}
|
||||
|
||||
var file = zip.file(path);
|
||||
var buf = await file.async("base64");
|
||||
var img = new Image();
|
||||
img.src = 'data:image/png;base64,' + buf;
|
||||
img.onload = () => {
|
||||
var texture = new Texture2D();
|
||||
texture.reset({
|
||||
width: img.width,
|
||||
height: img.height
|
||||
});
|
||||
texture.uploadData(img, 0, 0);
|
||||
texture.loaded = true;
|
||||
|
||||
var sf = new SpriteFrame();
|
||||
sf.texture = texture;
|
||||
|
||||
resolve(sf);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 释放Zip资源 */
|
||||
static release(url?: string) {
|
||||
if (url) {
|
||||
resLoader.release(url);
|
||||
}
|
||||
else {
|
||||
this.zips.forEach((value: JSZip, key: string) => {
|
||||
resLoader.release(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "52a6c740-3b9b-46c5-a784-d53a6b67954a",
|
||||
"uuid": "2c6ce5e4-08fd-4ff1-b0b6-8c07d7192263",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
@@ -126,7 +126,7 @@ oops.log.table(object);
|
||||
* 打印标准日志
|
||||
* @param msg 日志消息
|
||||
*/
|
||||
trace(msg: any, color: string = "#000000") {
|
||||
trace(msg: any, color: string = "#000000ff") {
|
||||
this.print(LogType.Trace, msg, color);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,29 @@ import { Component, game } from "cc";
|
||||
import { StringUtil } from "../../utils/StringUtil";
|
||||
import { Timer } from "./Timer";
|
||||
|
||||
interface ITimer {
|
||||
/** 倒计时编号 */
|
||||
id: string;
|
||||
/** 定时器 */
|
||||
timer: Timer;
|
||||
/** 数据对象 */
|
||||
object: any;
|
||||
/** 修改数据对象的字段 */
|
||||
field: string;
|
||||
/** 事件侦听器的目标和被叫方 */
|
||||
target: any;
|
||||
/** 开始时间 */
|
||||
startTime: number;
|
||||
/** 每秒触发事件 */
|
||||
onSeconds: Function[];
|
||||
/** 时间完成事件 */
|
||||
onCompletes: Function[];
|
||||
}
|
||||
|
||||
/** 时间管理 */
|
||||
export class TimerManager extends Component {
|
||||
/** 倒计时数据 */
|
||||
private times: any = {};
|
||||
private times: { [key: string]: ITimer } = {};
|
||||
/** 服务器时间 */
|
||||
private date_s: Date = new Date();
|
||||
/** 服务器初始时间 */
|
||||
@@ -25,7 +44,7 @@ export class TimerManager extends Component {
|
||||
protected update(dt: number) {
|
||||
for (let key in this.times) {
|
||||
let data = this.times[key];
|
||||
let timer = data.timer as Timer;
|
||||
let timer = data.timer;
|
||||
if (timer.update(dt)) {
|
||||
if (data.object[data.field] > 0) {
|
||||
data.object[data.field]--;
|
||||
@@ -35,8 +54,8 @@ export class TimerManager extends Component {
|
||||
this.onTimerComplete(data);
|
||||
}
|
||||
// 触发每秒回调事件
|
||||
else if (data.onSecond) {
|
||||
data.onSecond.call(data.object);
|
||||
else if (data.onSeconds) {
|
||||
data.onSeconds.forEach(fn => fn.call(data.object));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,10 +63,8 @@ export class TimerManager extends Component {
|
||||
}
|
||||
|
||||
/** 触发倒计时完成事件 */
|
||||
private onTimerComplete(data: any) {
|
||||
if (data.onComplete) data.onComplete.call(data.target, data.object);
|
||||
if (data.event) this.node.dispatchEvent(data.event);
|
||||
|
||||
private onTimerComplete(data: ITimer) {
|
||||
if (data.onCompletes) data.onCompletes.forEach(fn => fn.call(data.target, data.object));
|
||||
delete this.times[data.id];
|
||||
}
|
||||
|
||||
@@ -58,14 +75,14 @@ export class TimerManager extends Component {
|
||||
* @param target 触发事件的对象
|
||||
* @param onSecond 每秒事件
|
||||
* @param onComplete 倒计时完成事件
|
||||
* @returns
|
||||
* @returns 倒计时编号
|
||||
* @example
|
||||
export class Test extends Component {
|
||||
private timeId!: string;
|
||||
|
||||
start() {
|
||||
// 在指定对象上注册一个倒计时的回调管理器
|
||||
this.timeId = oops.timer.register(this, "countDown", this.onSecond, this.onComplete);
|
||||
this.timeId = oops.timer.register(this, "countDown", this, this.onSecond, this.onComplete);
|
||||
}
|
||||
|
||||
private onSecond() {
|
||||
@@ -77,22 +94,41 @@ export class TimerManager extends Component {
|
||||
}
|
||||
}
|
||||
*/
|
||||
register(object: any, field: string, target: object, onSecond: Function, onComplete: Function): string {
|
||||
register(object: any, field: string, target: object, onSecond?: Function, onComplete?: Function): string {
|
||||
const timer = new Timer();
|
||||
timer.step = 1;
|
||||
|
||||
let data: any = {};
|
||||
data.id = StringUtil.guid();
|
||||
data.timer = timer;
|
||||
data.object = object; // 管理对象
|
||||
data.field = field; // 时间字段
|
||||
data.onSecond = onSecond; // 每秒事件
|
||||
data.onComplete = onComplete; // 倒计时完成事件
|
||||
data.target = target
|
||||
let data: ITimer = {
|
||||
id: StringUtil.guid(),
|
||||
timer: timer,
|
||||
object: object,
|
||||
field: field,
|
||||
onSeconds: [],
|
||||
onCompletes: [],
|
||||
target: target,
|
||||
startTime: this.getTime()
|
||||
};
|
||||
if (onSecond) data.onSeconds.push(onSecond);
|
||||
if (onComplete) data.onCompletes.push(onComplete);
|
||||
|
||||
this.times[data.id] = data;
|
||||
return data.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定倒计时添加回调事件
|
||||
* @param id 倒计时编号
|
||||
* @param onSecond 每秒事件
|
||||
* @param onComplete 倒计时完成事件
|
||||
*/
|
||||
addCallback(id: string, onSecond?: Function, onComplete?: Function) {
|
||||
let data = this.times[id];
|
||||
if (data) {
|
||||
if (onSecond) data.onSeconds.push(onSecond);
|
||||
if (onComplete) data.onCompletes.push(onComplete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定对象上注销一个倒计时的回调管理器
|
||||
* @param id 时间对象唯一表示
|
||||
@@ -153,23 +189,24 @@ export class TimerManager extends Component {
|
||||
/** 游戏最小化时记录时间数据 */
|
||||
save(): void {
|
||||
for (let key in this.times) {
|
||||
this.times[key].startTime = this.getTime();
|
||||
let data: ITimer = this.times[key];
|
||||
data.startTime = this.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
/** 游戏最大化时回复时间数据 */
|
||||
load(): void {
|
||||
for (let key in this.times) {
|
||||
let interval = Math.floor((this.getTime() - (this.times[key].startTime || this.getTime())) / 1000);
|
||||
let data = this.times[key];
|
||||
let interval = Math.floor((this.getTime() - (data.startTime || this.getTime())) / 1000);
|
||||
data.object[data.field] = data.object[data.field] - interval;
|
||||
if (data.object[data.field] <= 0) {
|
||||
data.object[data.field] = 0;
|
||||
this.onTimerComplete(data);
|
||||
}
|
||||
else {
|
||||
this.times[key].startTime = null;
|
||||
data.object[data.field] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,9 @@ export class GameManager {
|
||||
}
|
||||
|
||||
// 自定义节点排序索引
|
||||
if (params && params.siblingIndex) node.setSiblingIndex(params.siblingIndex);
|
||||
if (params) {
|
||||
if (params.siblingIndex) node.setSiblingIndex(params.siblingIndex);
|
||||
}
|
||||
|
||||
resolve(node);
|
||||
});
|
||||
@@ -70,4 +72,4 @@ export class GameManager {
|
||||
//@ts-ignore
|
||||
return director.globalGameTimeScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
assets/core/gui/Gui.ts
Normal file
49
assets/core/gui/Gui.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { UIConfigMap } from "./layer/LayerEnum";
|
||||
import { UIConfig } from "./layer/UIConfig";
|
||||
|
||||
var configs: UIConfigMap = {};
|
||||
|
||||
export namespace gui {
|
||||
/** 注册界面组件 */
|
||||
export function register(key: string, config: UIConfig) {
|
||||
return function (ctor: any) {
|
||||
//@ts-ignore
|
||||
ctor[gui.internal.GUI_KEY] = key;
|
||||
internal.setConfig(key, config);
|
||||
};
|
||||
}
|
||||
|
||||
/** 框架内部使用方法 */
|
||||
export namespace internal {
|
||||
/** 界面唯一标记变量名 */
|
||||
export const GUI_KEY = "OOPS_GUI_KEY";
|
||||
|
||||
/** 获取界面唯一关键字 */
|
||||
export function getKey(ctor: any) {
|
||||
return ctor[GUI_KEY];
|
||||
}
|
||||
|
||||
/** 获取界面组件配置 */
|
||||
export function getConfig(key: string) {
|
||||
return configs[key];
|
||||
}
|
||||
|
||||
/** 获取界面组件配置 */
|
||||
export function setConfig(key: string, config: UIConfig) {
|
||||
let c = getConfig(key);
|
||||
if (c == null) {
|
||||
configs[key] = config;
|
||||
}
|
||||
else {
|
||||
console.error(`界面${key}重复注册`);
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化界面组件配置 */
|
||||
export function initConfigs(uicm: UIConfigMap) {
|
||||
for (const key in uicm) {
|
||||
configs[key] = uicm[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "dd2077e2-c862-4b7f-9afe-6e488c83076d",
|
||||
"uuid": "51e09b11-d9ab-453b-b637-74d6aa615806",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
@@ -4,9 +4,9 @@
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2023-07-24 17:14:57
|
||||
*/
|
||||
|
||||
import { Node } from "cc";
|
||||
import { LayerPopUp } from "./LayerPopup";
|
||||
import { UICallbacks, UIParams } from "./LayerUIElement";
|
||||
import { UIParam, UIState } from "./LayerUIElement";
|
||||
import { UIConfig } from "./UIConfig";
|
||||
|
||||
/** 模式弹窗数据 */
|
||||
@@ -16,9 +16,7 @@ type DialogParam = {
|
||||
/** 窗口配置 */
|
||||
config: UIConfig;
|
||||
/** 窗口附加参数 */
|
||||
params?: any;
|
||||
/** 窗口回调 */
|
||||
callbacks?: UICallbacks;
|
||||
params?: UIParam;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -27,56 +25,51 @@ type DialogParam = {
|
||||
export class LayerDialog extends LayerPopUp {
|
||||
/** 窗口调用参数队列 */
|
||||
private params: Array<DialogParam> = [];
|
||||
/** 当前打开的界面 */
|
||||
private current: Node = null!;
|
||||
|
||||
add(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) {
|
||||
// 控制同一时间只能显示一个模式窗口
|
||||
if (this.ui_nodes.size > 0) {
|
||||
this.params.push({
|
||||
uiid: uiid,
|
||||
config: config,
|
||||
params: params,
|
||||
callbacks: callbacks,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.show(uiid, config, params, callbacks);
|
||||
/**
|
||||
* 添加模式窗口
|
||||
* 1. 同时添加多个模式窗口时,第一个之后的窗口会先队列起来,在第一个关闭后在加载与显示第二个;同时方法返回节点保持只返回当前显示的界面节点
|
||||
*/
|
||||
add(uiid: string, config: UIConfig, params?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
// 控制同一时间只能显示一个模式窗口
|
||||
if (this.ui_nodes.size > 0) {
|
||||
this.params.push({ uiid: uiid, config: config, params: params });
|
||||
resolve(this.current);
|
||||
}
|
||||
else {
|
||||
this.current = await this.showDialog(uiid, config, params);
|
||||
resolve(this.current);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 显示模式弹窗 */
|
||||
private show(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) {
|
||||
let uip = this.ui_cache.get(config.prefab);
|
||||
if (uip == null) {
|
||||
uip = new UIParams();
|
||||
uip.uiid = uiid;
|
||||
uip.valid = true;
|
||||
uip.config = config;
|
||||
}
|
||||
|
||||
uip.params = params || {};
|
||||
uip.callbacks = callbacks ?? {};
|
||||
this.ui_nodes.set(uip.config.prefab, uip);
|
||||
|
||||
this.load(uip, config.bundle);
|
||||
private showDialog(uiid: string, config: UIConfig, param?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
let state = this.initUIConfig(uiid, config, param);
|
||||
let node = await this.load(state);
|
||||
resolve(node);
|
||||
});
|
||||
}
|
||||
|
||||
protected onCloseWindow(uip: UIParams) {
|
||||
super.onCloseWindow(uip);
|
||||
protected closeUi(state: UIState) {
|
||||
super.closeUi(state);
|
||||
setTimeout(this.next.bind(this), 0);
|
||||
}
|
||||
|
||||
protected closeUI() {
|
||||
protected closeBlack() {
|
||||
if (this.params.length == 0) {
|
||||
this.black.enabled = false;
|
||||
this.closeVacancyRemove();
|
||||
this.closeMask()
|
||||
super.closeBlack();
|
||||
}
|
||||
}
|
||||
|
||||
private next() {
|
||||
if (this.params.length > 0) {
|
||||
let param = this.params.shift()!;
|
||||
this.show(param.uiid, param.config, param.params, param.callbacks);
|
||||
this.showDialog(param.uiid, param.config, param.params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UIConfig } from "./UIConfig";
|
||||
|
||||
/** 界面编号 */
|
||||
export type Uiid = number | string | UIConfig;
|
||||
export type Uiid = number | string | UIConfig | Function;
|
||||
/** 界面配置集合 */
|
||||
export type UIConfigMap = { [key: string]: UIConfig }
|
||||
|
||||
@@ -51,4 +51,4 @@ export enum LayerTypeCls {
|
||||
Game = "Game",
|
||||
/** 自定义节点层 */
|
||||
Node = "Node"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Camera, Layers, Node, ResolutionPolicy, SafeArea, Widget, screen, view, warn } from "cc";
|
||||
import { resLoader } from "../../common/loader/ResLoader";
|
||||
import { Camera, Node, ResolutionPolicy, SafeArea, screen, view, warn } from "cc";
|
||||
import { oops } from "../../Oops";
|
||||
import { gui } from "../Gui";
|
||||
import { LayerDialog } from "./LayerDialog";
|
||||
import { LayerCustomType, LayerTypeCls, UIConfigMap, Uiid } from "./LayerEnum";
|
||||
import { LayerGame } from "./LayerGame";
|
||||
import { LayerHelper } from "./LayerHelper";
|
||||
import { LayerNotify } from "./LayerNotify";
|
||||
import { LayerPopUp } from "./LayerPopup";
|
||||
import { LayerUI } from "./LayerUI";
|
||||
import { LayerUIElement, UICallbacks } from "./LayerUIElement";
|
||||
import { LayerUIElement, UIParam } from "./LayerUIElement";
|
||||
import { UIConfig } from "./UIConfig";
|
||||
import { LayerGame } from "./LayerGame";
|
||||
|
||||
/** 界面层级管理器 */
|
||||
export class LayerManager {
|
||||
@@ -30,8 +31,6 @@ export class LayerManager {
|
||||
|
||||
/** 消息提示控制器,请使用show方法来显示 */
|
||||
private notify!: LayerNotify;
|
||||
/** UI配置 */
|
||||
private configs: UIConfigMap = {};
|
||||
/** 界面层集合 - 无自定义类型 */
|
||||
private uiLayers: Map<string, LayerUI> = new Map();
|
||||
/** 界面层组件集合 */
|
||||
@@ -137,7 +136,7 @@ export class LayerManager {
|
||||
* @param configs 配置对象
|
||||
*/
|
||||
init(configs: UIConfigMap): void {
|
||||
this.configs = configs;
|
||||
gui.internal.initConfigs(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,23 +170,30 @@ export class LayerManager {
|
||||
this.notify.waitClose();
|
||||
}
|
||||
|
||||
/** 获取界面信息 */
|
||||
private getInfo(uiid: Uiid): { key: string; config: UIConfig } {
|
||||
let key = "";
|
||||
let config: UIConfig = null!;
|
||||
|
||||
// 确定 key 和 config
|
||||
// 界面配置
|
||||
if (typeof uiid === 'object') {
|
||||
if (uiid.bundle == null) uiid.bundle = resLoader.defaultBundleName;
|
||||
key = uiid.bundle + "_" + uiid.prefab;
|
||||
config = this.configs[key];
|
||||
config = gui.internal.getConfig(key);
|
||||
if (config == null) {
|
||||
config = uiid;
|
||||
this.configs[key] = uiid;
|
||||
gui.internal.setConfig(key, uiid);
|
||||
}
|
||||
}
|
||||
// 界面对象 - 配合gui.register使用
|
||||
else if (uiid instanceof Function) {
|
||||
//@ts-ignore
|
||||
key = uiid[gui.internal.GUI_KEY];
|
||||
config = gui.internal.getConfig(key);
|
||||
}
|
||||
// 界面唯一标记
|
||||
else {
|
||||
key = uiid.toString();
|
||||
config = this.configs[uiid];
|
||||
config = gui.internal.getConfig(key);
|
||||
if (config == null) {
|
||||
console.error(`打开编号为【${uiid}】的界面失败,配置信息不存在`);
|
||||
}
|
||||
@@ -198,8 +204,7 @@ export class LayerManager {
|
||||
/**
|
||||
* 同步打开一个窗口
|
||||
* @param uiid 窗口唯一编号
|
||||
* @param uiArgs 窗口参数
|
||||
* @param callbacks 回调对象
|
||||
* @param param 窗口参数
|
||||
* @example
|
||||
var uic: UICallbacks = {
|
||||
onAdded: (node: Node, params: any) => {
|
||||
@@ -209,52 +214,62 @@ export class LayerManager {
|
||||
|
||||
}
|
||||
};
|
||||
oops.gui.open(UIID.Loading, null, uic);
|
||||
oops.gui.open(UIID.Loading);
|
||||
*/
|
||||
open(uiid: Uiid, uiArgs: any = null, callbacks?: UICallbacks): void {
|
||||
open(uiid: Uiid, param?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
let info = this.getInfo(uiid);
|
||||
let layer = this.uiLayers.get(info.config.layer);
|
||||
if (layer) {
|
||||
let node = await layer.add(info.key, info.config, param);
|
||||
resolve(node);
|
||||
}
|
||||
else {
|
||||
console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 显示指定界面 */
|
||||
show(uiid: Uiid) {
|
||||
let info = this.getInfo(uiid);
|
||||
let layer = this.uiLayers.get(info.config.layer);
|
||||
if (layer) {
|
||||
layer.add(info.key, info.config, uiArgs, callbacks);
|
||||
layer.show(info.config.prefab);
|
||||
}
|
||||
else {
|
||||
console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步打开一个窗口
|
||||
* @param uiid 窗口唯一编号
|
||||
* @param uiArgs 窗口参数
|
||||
* @example
|
||||
* var node = await oops.gui.openAsync(UIID.Loading);
|
||||
*/
|
||||
async openAsync(uiid: Uiid, uiArgs: any = null): Promise<Node | null> {
|
||||
return new Promise<Node | null>((resolve, reject) => {
|
||||
const callbacks: UICallbacks = {
|
||||
onAdded: (node: Node, params: any) => {
|
||||
resolve(node);
|
||||
},
|
||||
onLoadFailure: () => {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
this.open(uiid, uiArgs, callbacks);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定标识的窗口
|
||||
* @param uiid 窗口唯一标识
|
||||
* @param isDestroy 移除后是否释放(默认释放内存)
|
||||
* @example
|
||||
* oops.gui.remove(UIID.Loading);
|
||||
*/
|
||||
remove(uiid: Uiid, isDestroy: boolean = true) {
|
||||
remove(uiid: Uiid) {
|
||||
let info = this.getInfo(uiid);
|
||||
let layer = this.uiLayers.get(info.config.layer);
|
||||
if (layer) {
|
||||
layer.remove(info.config.prefab, isDestroy);
|
||||
layer.remove(info.config.prefab);
|
||||
}
|
||||
else {
|
||||
console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理指定界面的缓存
|
||||
* @param uiid 窗口唯一标识
|
||||
* @example
|
||||
* oops.gui.removeCache(UIID.Loading);
|
||||
*/
|
||||
removeCache(uiid: Uiid) {
|
||||
let info = this.getInfo(uiid);
|
||||
let layer = this.uiLayers.get(info.config.layer);
|
||||
if (layer) {
|
||||
layer.removeCache(info.config.prefab);
|
||||
}
|
||||
else {
|
||||
console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`);
|
||||
@@ -264,25 +279,24 @@ export class LayerManager {
|
||||
/**
|
||||
* 通过界面节点移除
|
||||
* @param node 窗口节点
|
||||
* @param isDestroy 移除后是否释放资源(默认释放内存)
|
||||
* @example
|
||||
* oops.gui.removeByNode(cc.Node);
|
||||
*/
|
||||
removeByNode(node: Node, isDestroy: boolean = true) {
|
||||
removeByNode(node: Node) {
|
||||
if (node instanceof Node) {
|
||||
let comp = node.getComponent(LayerUIElement);
|
||||
if (comp && comp.params) {
|
||||
if (comp && comp.state) {
|
||||
// 释放显示的界面
|
||||
if (node.parent) {
|
||||
let uiid = this.configs[comp.params.uiid];
|
||||
this.remove(uiid, isDestroy);
|
||||
let uiid = gui.internal.getConfig(comp.state.uiid);
|
||||
this.remove(uiid);
|
||||
}
|
||||
// 释放缓存中的界面
|
||||
else if (isDestroy) {
|
||||
let layer = this.uiLayers.get(comp.params.config.layer);
|
||||
else {
|
||||
let layer = this.uiLayers.get(comp.state.config.layer);
|
||||
if (layer) {
|
||||
// @ts-ignore 注:不对外使用
|
||||
layer.removeCache(comp.params.config.prefab);
|
||||
layer.removeCache(comp.state.config.prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,34 +310,14 @@ export class LayerManager {
|
||||
/**
|
||||
* 场景替换
|
||||
* @param removeUiId 移除场景编号
|
||||
* @param openUiId 新打开场景编号
|
||||
* @param uiArgs 新打开场景参数
|
||||
* @param openUiid 新打开场景编号
|
||||
* @param param 新打开场景参数
|
||||
*/
|
||||
replace(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null) {
|
||||
const callbacks: UICallbacks = {
|
||||
onAdded: (node: Node, params: any) => {
|
||||
this.remove(removeUiId);
|
||||
}
|
||||
};
|
||||
this.open(openUiId, uiArgs, callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步场景替换
|
||||
* @param removeUiId 移除场景编号
|
||||
* @param openUiId 新打开场景编号
|
||||
* @param uiArgs 新打开场景参数
|
||||
*/
|
||||
replaceAsync(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null): Promise<Node | null> {
|
||||
return new Promise<Node | null>(async (resolve, reject) => {
|
||||
const node = await this.openAsync(openUiId, uiArgs);
|
||||
if (node) {
|
||||
this.remove(removeUiId);
|
||||
resolve(node);
|
||||
}
|
||||
else {
|
||||
resolve(null);
|
||||
}
|
||||
replace(removeUiId: Uiid, openUiid: Uiid, param?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
let node = await this.open(openUiid, param);
|
||||
this.remove(removeUiId);
|
||||
resolve(node);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -380,12 +374,7 @@ export class LayerManager {
|
||||
|
||||
private create_node(name: string) {
|
||||
const node = new Node(name);
|
||||
node.layer = Layers.Enum.UI_2D;
|
||||
const w: Widget = node.addComponent(Widget);
|
||||
w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true;
|
||||
w.left = w.right = w.top = w.bottom = 0;
|
||||
w.alignMode = 2;
|
||||
w.enabled = true;
|
||||
LayerHelper.setFullScreen(node);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { BlockInputEvents, EventTouch, Node } from "cc";
|
||||
import { ViewUtil } from "../../utils/ViewUtil";
|
||||
import { PromptResType } from "../GuiEnum";
|
||||
import { LayerUI } from "./LayerUI";
|
||||
import { UIParams } from "./LayerUIElement";
|
||||
import { UIState } from "./LayerUIElement";
|
||||
import { UIConfig } from "./UIConfig";
|
||||
|
||||
/* 弹窗层,允许同时弹出多个窗口 */
|
||||
@@ -17,27 +17,21 @@ export class LayerPopUp extends LayerUI {
|
||||
/** 半透明遮罩资源 */
|
||||
protected mask!: Node;
|
||||
|
||||
constructor(name: string) {
|
||||
super(name);
|
||||
|
||||
this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
|
||||
this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this);
|
||||
protected onChildAdded(child: Node) {
|
||||
this.mask && this.mask.setSiblingIndex(this.children.length - 2);
|
||||
}
|
||||
|
||||
private onChildAdded(child: Node) {
|
||||
if (this.mask) this.mask.setSiblingIndex(this.children.length - 2);
|
||||
protected onChildRemoved(child: Node) {
|
||||
this.mask && this.mask.setSiblingIndex(this.children.length - 2);
|
||||
super.onChildRemoved(child);
|
||||
}
|
||||
|
||||
private onChildRemoved(child: Node) {
|
||||
if (this.mask) this.mask.setSiblingIndex(this.children.length - 2);
|
||||
}
|
||||
|
||||
protected showUi(uip: UIParams): Promise<boolean> {
|
||||
protected uiInit(state: UIState): Promise<boolean> {
|
||||
return new Promise(async (resolve) => {
|
||||
const r = await super.showUi(uip);
|
||||
const r = await super.uiInit(state);
|
||||
if (r) {
|
||||
// 界面加载完成显示时,启动触摸非窗口区域关闭
|
||||
this.openVacancyRemove(uip.config);
|
||||
this.openVacancyRemove(state.config);
|
||||
|
||||
// 界面加载完成显示时,层级事件阻挡
|
||||
this.black.enabled = true;
|
||||
@@ -46,15 +40,15 @@ export class LayerPopUp extends LayerUI {
|
||||
});
|
||||
}
|
||||
|
||||
protected onCloseWindow(uip: UIParams) {
|
||||
super.onCloseWindow(uip);
|
||||
protected closeUi(state: UIState) {
|
||||
super.closeUi(state);
|
||||
|
||||
// 界面关闭后,关闭触摸事件阻挡、关闭触摸非窗口区域关闭、关闭遮罩
|
||||
this.closeUI();
|
||||
this.closeBlack();
|
||||
}
|
||||
|
||||
/** 设置触摸事件阻挡 */
|
||||
protected closeUI() {
|
||||
protected closeBlack() {
|
||||
// 所有弹窗关闭后,关闭事件阻挡功能
|
||||
if (this.ui_nodes.size == 0) {
|
||||
if (this.black) this.black.enabled = false;
|
||||
@@ -120,13 +114,13 @@ export class LayerPopUp extends LayerUI {
|
||||
if (this.ui_nodes.size > 0) {
|
||||
let vp = this.ui_nodes.array[this.ui_nodes.size - 1];
|
||||
if (vp.valid && vp.config.vacancy) {
|
||||
this.remove(vp.config.prefab, vp.config.destroy);
|
||||
this.remove(vp.config.prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear(isDestroy: boolean) {
|
||||
super.clear(isDestroy)
|
||||
this.closeUI();
|
||||
this.closeBlack();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
import { instantiate, Node, Prefab, SafeArea } from "cc";
|
||||
import { Collection } from "db://oops-framework/libs/collection/Collection";
|
||||
import { resLoader } from "../../common/loader/ResLoader";
|
||||
import { oops } from "../../Oops";
|
||||
import { Uiid } from "./LayerEnum";
|
||||
import { LayerHelper } from "./LayerHelper";
|
||||
import { LayerUIElement, UICallbacks, UIParams } from "./LayerUIElement";
|
||||
import { LayerUIElement, UIParam, UIState } from "./LayerUIElement";
|
||||
import { UIConfig } from "./UIConfig";
|
||||
|
||||
/** 界面层对象 */
|
||||
export class LayerUI extends Node {
|
||||
/** 全局窗口打开失败 */
|
||||
/** 全局窗口打开失败事件 */
|
||||
onOpenFailure: Function = null!;
|
||||
/** 显示界面节点集合 */
|
||||
protected ui_nodes = new Collection<string, UIParams>();
|
||||
protected ui_nodes = new Collection<string, UIState>();
|
||||
/** 被移除的界面缓存数据 */
|
||||
protected ui_cache = new Map<string, UIParams>();
|
||||
protected ui_cache = new Map<string, UIState>();
|
||||
|
||||
/**
|
||||
* UI基础层,允许添加多个预制件节点
|
||||
@@ -22,77 +23,122 @@ export class LayerUI extends Node {
|
||||
constructor(name: string) {
|
||||
super(name);
|
||||
LayerHelper.setFullScreen(this);
|
||||
|
||||
this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
|
||||
this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this);
|
||||
}
|
||||
|
||||
protected onChildAdded(child: Node) {
|
||||
|
||||
}
|
||||
|
||||
protected onChildRemoved(child: Node) {
|
||||
const comp = child.getComponent(LayerUIElement);
|
||||
if (comp) {
|
||||
this.closeUi(comp.state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点
|
||||
* @param uiid 窗口唯一标识
|
||||
* @param config 界面配置数据
|
||||
* @param params 自定义参数
|
||||
* @param callbacks 回调函数对象,可选
|
||||
* @returns ture为成功,false为失败
|
||||
*/
|
||||
add(uiid: Uiid, config: UIConfig, params?: any, callbacks?: UICallbacks) {
|
||||
if (this.ui_nodes.has(config.prefab)) {
|
||||
console.warn(`路径为【${config.prefab}】的预制重复加载`);
|
||||
return;
|
||||
add(uiid: Uiid, config: UIConfig, params?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
if (this.ui_nodes.has(config.prefab)) {
|
||||
console.warn(`路径为【${config.prefab}】的预制重复加载`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查缓存中是否存界面
|
||||
let state = this.initUIConfig(uiid, config, params);
|
||||
await this.load(state);
|
||||
resolve(state.node);
|
||||
});
|
||||
}
|
||||
|
||||
/** 初始化界面配置初始值 */
|
||||
protected initUIConfig(uiid: Uiid, config: UIConfig, params?: UIParam) {
|
||||
let state = this.ui_cache.get(config.prefab);
|
||||
if (state == null) {
|
||||
if (config.bundle == null) config.bundle = resLoader.defaultBundleName;
|
||||
if (config.destroy == null) config.destroy = true;
|
||||
if (config.vacancy == null) config.vacancy = false;
|
||||
if (config.mask == null) config.mask = false;
|
||||
if (config.safeArea == null) config.safeArea = false;
|
||||
|
||||
state = new UIState();
|
||||
state.uiid = uiid.toString();
|
||||
state.config = config;
|
||||
}
|
||||
|
||||
// 检查缓存中是否存界面
|
||||
let uip = this.ui_cache.get(config.prefab);
|
||||
if (uip == null) {
|
||||
uip = new UIParams();
|
||||
uip.uiid = uiid.toString();
|
||||
uip.config = config;
|
||||
}
|
||||
this.ui_nodes.set(config.prefab, uip);
|
||||
|
||||
uip.params = params ?? {};
|
||||
uip.callbacks = callbacks ?? {};
|
||||
uip.valid = true;
|
||||
|
||||
this.load(uip, config.bundle)
|
||||
state.params = params ?? {};
|
||||
state.valid = true;
|
||||
this.ui_nodes.set(config.prefab, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载界面资源
|
||||
* @param uip 显示参数
|
||||
* @param state 显示参数
|
||||
* @param bundle 远程资源包名,如果为空就是默认本地资源包
|
||||
*/
|
||||
protected async load(uip: UIParams, bundle?: string) {
|
||||
// 加载界面资源超时提示
|
||||
const timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
|
||||
protected async load(state: UIState): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
// 加载界面资源超时提示
|
||||
if (state.node == null) {
|
||||
let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
|
||||
|
||||
if (uip && uip.node) {
|
||||
await this.showUi(uip);
|
||||
}
|
||||
else {
|
||||
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
|
||||
bundle = bundle || oops.res.defaultBundleName;
|
||||
const res = await oops.res.loadAsync(bundle, uip.config.prefab, Prefab);
|
||||
if (res) {
|
||||
uip.node = instantiate(res);
|
||||
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
|
||||
const res = await resLoader.loadAsync(state.config.bundle!, state.config.prefab, Prefab);
|
||||
if (res) {
|
||||
state.node = instantiate(res);
|
||||
|
||||
// 是否启动真机安全区域显示
|
||||
if (uip.config.safeArea) uip.node.addComponent(SafeArea);
|
||||
// 是否启动真机安全区域显示
|
||||
if (state.config.safeArea) state.node.addComponent(SafeArea);
|
||||
|
||||
// 窗口事件委托
|
||||
const dc = uip.node.addComponent(LayerUIElement);
|
||||
dc.params = uip;
|
||||
//@ts-ignore
|
||||
dc.onCloseWindow = this.onCloseWindow.bind(this);
|
||||
// 窗口事件委托
|
||||
const comp = state.node.addComponent(LayerUIElement);
|
||||
comp.state = state;
|
||||
}
|
||||
else {
|
||||
console.warn(`路径为【${state.config.prefab}】的预制加载失败`);
|
||||
this.failure(state);
|
||||
}
|
||||
|
||||
// 显示界面
|
||||
await this.showUi(uip);
|
||||
// 关闭界面资源超时提示
|
||||
oops.gui.waitClose();
|
||||
clearTimeout(timerId);
|
||||
}
|
||||
|
||||
await this.uiInit(state);
|
||||
resolve(state.node);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建界面节点
|
||||
* @param state 视图参数
|
||||
*/
|
||||
protected uiInit(state: UIState): Promise<boolean> {
|
||||
return new Promise<boolean>(async (resolve, reject) => {
|
||||
const comp = state.node.getComponent(LayerUIElement)!;
|
||||
const r: boolean = await comp.add();
|
||||
if (r) {
|
||||
state.valid = true; // 标记界面为使用状态
|
||||
if (!state.params.preload) {
|
||||
state.params.preload = false;
|
||||
state.node.parent = this;
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn(`路径为【${uip.config.prefab}】的预制加载失败`);
|
||||
this.failure(uip);
|
||||
console.warn(`路径为【${state.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`);
|
||||
this.failure(state);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭界面资源超时提示
|
||||
oops.gui.waitClose();
|
||||
clearTimeout(timerId);
|
||||
resolve(r);
|
||||
});
|
||||
}
|
||||
|
||||
/** 加载超时事件*/
|
||||
@@ -101,89 +147,57 @@ export class LayerUI extends Node {
|
||||
}
|
||||
|
||||
/** 窗口关闭事件 */
|
||||
protected onCloseWindow(vp: UIParams) {
|
||||
this.ui_nodes.delete(vp.config.prefab);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建界面节点
|
||||
* @param uip 视图参数
|
||||
*/
|
||||
protected async showUi(uip: UIParams): Promise<boolean> {
|
||||
// 触发窗口添加事件
|
||||
const comp = uip.node.getComponent(LayerUIElement)!;
|
||||
const r: boolean = await comp.add();
|
||||
if (r) {
|
||||
uip.node.parent = this;
|
||||
|
||||
// 标记界面为使用状态
|
||||
uip.valid = true;
|
||||
}
|
||||
else {
|
||||
console.warn(`路径为【${uip.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`);
|
||||
this.failure(uip);
|
||||
}
|
||||
return r;
|
||||
protected closeUi(state: UIState) {
|
||||
this.ui_nodes.delete(state.config.prefab);
|
||||
}
|
||||
|
||||
/** 打开窗口失败逻辑 */
|
||||
protected failure(uip: UIParams) {
|
||||
this.onCloseWindow(uip);
|
||||
uip.callbacks && uip.callbacks.onLoadFailure && uip.callbacks.onLoadFailure();
|
||||
protected failure(state: UIState) {
|
||||
this.closeUi(state);
|
||||
this.onOpenFailure && this.onOpenFailure();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据预制件路径删除,预制件如在队列中也会被删除,如果该预制件存在多个也会一起删除
|
||||
* @param prefabPath 预制路径
|
||||
* @param isDestroy 移除后是否释放
|
||||
*/
|
||||
remove(prefabPath: string, isDestroy?: boolean): void {
|
||||
let release: any = undefined;
|
||||
if (isDestroy !== undefined) release = isDestroy;
|
||||
|
||||
// 界面移出舞台
|
||||
const uip = this.ui_nodes.get(prefabPath);
|
||||
if (uip) {
|
||||
// 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面
|
||||
if (release === undefined) {
|
||||
release = uip.config.destroy !== undefined ? uip.config.destroy : true;
|
||||
}
|
||||
remove(prefabPath: string): void {
|
||||
const state = this.ui_nodes.get(prefabPath);
|
||||
if (state) {
|
||||
let release: boolean = state.config.destroy!;
|
||||
|
||||
// 不释放界面,缓存起来待下次使用
|
||||
if (release === false) {
|
||||
this.ui_cache.set(uip.config.prefab, uip);
|
||||
}
|
||||
if (release === false) this.ui_cache.set(state.config.prefab, state);
|
||||
|
||||
const node = uip.node;
|
||||
const comp = node.getComponent(LayerUIElement)!;
|
||||
// 界面移出舞台
|
||||
const comp = state.node.getComponent(LayerUIElement)!;
|
||||
comp.remove(release);
|
||||
}
|
||||
|
||||
// 验证是否删除后台缓存界面
|
||||
if (release === true) this.removeCache(prefabPath);
|
||||
}
|
||||
|
||||
/** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */
|
||||
private removeCache(prefabPath: string) {
|
||||
let vp = this.ui_cache.get(prefabPath);
|
||||
if (vp) {
|
||||
this.onCloseWindow(vp);
|
||||
/** 删除缓存的界面,当调用 remove 移除舞台时,可通过此方法删除缓存界面 */
|
||||
removeCache(prefabPath: string) {
|
||||
const state = this.ui_cache.get(prefabPath);
|
||||
if (state) {
|
||||
this.ui_cache.delete(prefabPath);
|
||||
const node = vp.node;
|
||||
const comp = node.getComponent(LayerUIElement)!;
|
||||
const comp = state.node.getComponent(LayerUIElement)!;
|
||||
comp.remove(true);
|
||||
node.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/** 显示界面 */
|
||||
show(prefabPath: string) {
|
||||
const state = this.ui_nodes.get(prefabPath);
|
||||
if (state) state.node.parent = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据预制路径获取已打开界面的节点对象
|
||||
* @param prefabPath 预制路径
|
||||
*/
|
||||
get(prefabPath: string): Node {
|
||||
const vp = this.ui_nodes.get(prefabPath);
|
||||
if (vp) return vp.node;
|
||||
const state = this.ui_nodes.get(prefabPath);
|
||||
if (state) return state.node;
|
||||
return null!;
|
||||
}
|
||||
|
||||
@@ -204,13 +218,13 @@ export class LayerUI extends Node {
|
||||
const length = this.ui_nodes.array.length - 1;
|
||||
for (let i = length; i >= 0; i--) {
|
||||
const uip = this.ui_nodes.array[i];
|
||||
this.remove(uip.config.prefab, isDestroy);
|
||||
this.remove(uip.config.prefab);
|
||||
}
|
||||
this.ui_nodes.clear();
|
||||
|
||||
// 清除缓存中的界面
|
||||
if (isDestroy) {
|
||||
this.ui_cache.forEach((value: UIParams, prefabPath: string) => {
|
||||
this.ui_cache.forEach((value: UIState, prefabPath: string) => {
|
||||
this.removeCache(prefabPath);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@ const { ccclass } = _decorator;
|
||||
@ccclass('LayerUIElement')
|
||||
export class LayerUIElement extends Component {
|
||||
/** 视图参数 */
|
||||
params: UIParams = null!;
|
||||
state: UIState = null!;
|
||||
/** 关闭窗口之前 */
|
||||
onCloseWindowBefore: Function = null!;
|
||||
/** 界面关闭回调 - 包括关闭动画播放完(辅助框架内存业务流程使用) */
|
||||
private onCloseWindow: Function = null!;
|
||||
onClose: Function = null!;
|
||||
|
||||
/** 窗口添加 */
|
||||
/** 添加界面且界面设置到父节点之前 */
|
||||
add(): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// 触发窗口组件上添加到父节点后的事件
|
||||
@@ -32,7 +30,7 @@ export class LayerUIElement extends Component {
|
||||
const component: any = this.node.components[i];
|
||||
const func = component[EventOnAdded];
|
||||
if (func) {
|
||||
if (await func.call(component, this.params.params) == false) {
|
||||
if (await func.call(component, this.state.params.data) == false) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
@@ -40,8 +38,8 @@ export class LayerUIElement extends Component {
|
||||
}
|
||||
|
||||
// 触发外部窗口显示前的事件(辅助实现自定义动画逻辑)
|
||||
if (typeof this.params.callbacks.onAdded === "function") {
|
||||
this.params.callbacks.onAdded(this.node, this.params.params);
|
||||
if (typeof this.state.params.onAdded === "function") {
|
||||
this.state.params.onAdded(this.node, this.state.params.data);
|
||||
}
|
||||
|
||||
resolve(true);
|
||||
@@ -49,14 +47,14 @@ export class LayerUIElement extends Component {
|
||||
}
|
||||
|
||||
/** 删除节点,该方法只能调用一次,将会触发onBeforeRemoved回调 */
|
||||
remove(isDestroy?: boolean) {
|
||||
if (this.params.valid) {
|
||||
remove(isDestroy: boolean) {
|
||||
if (this.state.valid) {
|
||||
// 触发窗口移除舞台之前事件
|
||||
this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.params.params);
|
||||
this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.state.params.data);
|
||||
|
||||
// 通知外部对象窗口组件上移除之前的事件(关闭窗口前的关闭动画处理)
|
||||
if (typeof this.params.callbacks.onBeforeRemove === "function") {
|
||||
this.params.callbacks.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy));
|
||||
if (typeof this.state.params.onBeforeRemove === "function") {
|
||||
this.state.params.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy));
|
||||
}
|
||||
else {
|
||||
this.onBeforeRemoveNext(isDestroy);
|
||||
@@ -68,37 +66,31 @@ export class LayerUIElement extends Component {
|
||||
}
|
||||
|
||||
/** 窗口关闭前动画处理完后的回调方法,主要用于释放资源 */
|
||||
private onBeforeRemoveNext(isDestroy?: boolean) {
|
||||
this.onCloseWindowBefore && this.onCloseWindowBefore();
|
||||
this.removed(this.params, isDestroy);
|
||||
}
|
||||
private onBeforeRemoveNext(isDestroy: boolean) {
|
||||
this.state.valid = false;
|
||||
|
||||
/** 窗口组件中触发移除事件与释放窗口对象 */
|
||||
private removed(uip: UIParams, isDestroy?: boolean) {
|
||||
uip.valid = false;
|
||||
|
||||
if (uip.callbacks && typeof uip.callbacks.onRemoved === "function") {
|
||||
uip.callbacks.onRemoved(this.node, uip.params);
|
||||
if (this.state.params && typeof this.state.params.onRemoved === "function") {
|
||||
this.state.params.onRemoved(this.node, this.state.params.data);
|
||||
}
|
||||
|
||||
// 界面移除舞台事件
|
||||
this.onCloseWindow && this.onCloseWindow(uip);
|
||||
// 关闭动画播放完后,界面移除舞台事件
|
||||
this.onClose && this.onClose();
|
||||
|
||||
if (isDestroy) {
|
||||
// 释放界面显示对象
|
||||
this.node.destroy();
|
||||
|
||||
// 释放界面相关资源
|
||||
oops.res.release(uip.config.prefab, uip.config.bundle);
|
||||
oops.res.release(this.state.config.prefab, this.state.config.bundle);
|
||||
|
||||
oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`);
|
||||
// oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`);
|
||||
}
|
||||
else {
|
||||
this.node.removeFromParent();
|
||||
}
|
||||
|
||||
// 触发窗口组件上窗口移除之后的事件
|
||||
this.applyComponentsFunction(this.node, EventOnRemoved, this.params.params);
|
||||
this.applyComponentsFunction(this.node, EventOnRemoved, this.state.params.data);
|
||||
}
|
||||
|
||||
private applyComponentsFunction(node: Node, funName: string, params: any) {
|
||||
@@ -112,30 +104,33 @@ export class LayerUIElement extends Component {
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.params = null!;
|
||||
this.onCloseWindowBefore = null!;
|
||||
this.onCloseWindow = null!;
|
||||
this.state = null!;
|
||||
this.onClose = null!;
|
||||
}
|
||||
}
|
||||
|
||||
/** 本类型仅供gui模块内部使用,请勿在功能逻辑中使用 */
|
||||
export class UIParams {
|
||||
export class UIState {
|
||||
/** 界面唯一编号 */
|
||||
uiid: string = null!;
|
||||
/** 界面配置 */
|
||||
config: UIConfig = null!;
|
||||
/** 传递给打开界面的参数 */
|
||||
params: any = null!;
|
||||
/** 窗口事件 */
|
||||
callbacks: UICallbacks = null!;
|
||||
params: UIParam = null!;
|
||||
/** 是否在使用状态 */
|
||||
valid: boolean = true;
|
||||
/** 界面根节点 */
|
||||
node: Node = null!;
|
||||
}
|
||||
|
||||
/*** 界面回调参数对象定义 */
|
||||
export interface UICallbacks {
|
||||
/*** 界面打开参数 */
|
||||
export interface UIParam {
|
||||
/** 自定义传递参数 */
|
||||
data?: any;
|
||||
|
||||
/** 是否开启预加载(默认不开启 - 开启后加载完不显示界面) */
|
||||
preload?: boolean;
|
||||
|
||||
/**
|
||||
* 节点添加到层级以后的回调
|
||||
* @param node 当前界面节点
|
||||
@@ -143,13 +138,6 @@ export interface UICallbacks {
|
||||
*/
|
||||
onAdded?: (node: Node, params: any) => void,
|
||||
|
||||
/**
|
||||
* 窗口节点 destroy 之后回调
|
||||
* @param node 当前界面节点
|
||||
* @param params 外部传递参数
|
||||
*/
|
||||
onRemoved?: (node: Node | null, params: any) => void,
|
||||
|
||||
/**
|
||||
* 如果指定onBeforeRemoved,则next必须调用,否则节点不会被正常删除。
|
||||
*
|
||||
@@ -159,6 +147,10 @@ export interface UICallbacks {
|
||||
*/
|
||||
onBeforeRemove?: (node: Node, next: Function) => void,
|
||||
|
||||
/** 网络异常时,窗口加载失败回调 */
|
||||
onLoadFailure?: () => void;
|
||||
/**
|
||||
* 窗口节点 destroy 之后回调
|
||||
* @param node 当前界面节点
|
||||
* @param params 外部传递参数
|
||||
*/
|
||||
onRemoved?: (node: Node, params: any) => void
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export interface UIConfig {
|
||||
layer: string;
|
||||
/** 预制资源相对路径 */
|
||||
prefab: string;
|
||||
/** 是否自动施放(默认不自动释放) */
|
||||
/** 是否自动施放(默认自动释放) */
|
||||
destroy?: boolean;
|
||||
|
||||
/** -----弹窗属性----- */
|
||||
@@ -39,7 +39,7 @@ export interface UIConfig {
|
||||
vacancy?: boolean,
|
||||
/** 是否打开窗口后显示背景遮罩(默认关闭) */
|
||||
mask?: boolean;
|
||||
/** 是否启动真机安全区域显示 */
|
||||
/** 是否启动真机安全区域显示(默认关闭) */
|
||||
safeArea?: boolean;
|
||||
/** 界面弹出时的节点排序索引 */
|
||||
siblingIndex?: number;
|
||||
|
||||
@@ -40,9 +40,6 @@ export class DeviceUtil {
|
||||
/** 是否为字节小游戏 */
|
||||
static get isByteDance() { return sys.platform === sys.Platform.BYTEDANCE_MINI_GAME; }
|
||||
|
||||
/** 是否为百度小游戏 */
|
||||
static get isBaidu() { return sys.platform === sys.Platform.BAIDU_MINI_GAME; }
|
||||
|
||||
/** 是否为 vivo 小游戏 */
|
||||
static get isVivo() { return sys.platform === sys.Platform.VIVO_MINI_GAME; }
|
||||
|
||||
|
||||
@@ -6,91 +6,91 @@
|
||||
*/
|
||||
|
||||
import { JsonAsset } from "cc";
|
||||
import { ZipLoader } from "db://oops-framework/core/common/loader/ZipLoader";
|
||||
import { resLoader } from "../common/loader/ResLoader";
|
||||
|
||||
/** 资源路径 */
|
||||
const path: string = "config/game/";
|
||||
const pathJson: string = "config/game/";
|
||||
/** 压缩包资源路径 */
|
||||
const pathZip: string = "config/game/game";
|
||||
|
||||
/** 数据缓存 */
|
||||
const data: Map<string, any> = new Map();
|
||||
|
||||
/** JSON数据表工具 */
|
||||
export class JsonUtil {
|
||||
/** 是否使用压缩包加载配置表 */
|
||||
static zip: boolean = false;
|
||||
|
||||
/**
|
||||
* 通知资源名从缓存中获取一个Json数据表
|
||||
* @param name 资源名
|
||||
*/
|
||||
static get(name: string): any {
|
||||
if (data.has(name))
|
||||
return data.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知资源名加载Json数据表
|
||||
* @param name 资源名
|
||||
* @param callback 资源加载完成回调
|
||||
*/
|
||||
static load(name: string, callback: Function): void {
|
||||
if (data.has(name))
|
||||
callback(data.get(name));
|
||||
else {
|
||||
const url = path + name;
|
||||
resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => {
|
||||
if (err) {
|
||||
console.warn(err.message);
|
||||
callback(null);
|
||||
}
|
||||
else {
|
||||
data.set(name, content.json);
|
||||
resLoader.release(url);
|
||||
callback(content.json);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (data.has(name)) return data.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步加载Json数据表
|
||||
* @param name 资源名
|
||||
*/
|
||||
static loadAsync(name: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
static load(name: string): Promise<any> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let content: any = null;
|
||||
if (data.has(name)) {
|
||||
resolve(data.get(name))
|
||||
resolve(data.get(name));
|
||||
}
|
||||
else {
|
||||
const url = path + name;
|
||||
resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => {
|
||||
if (err) {
|
||||
console.warn(err.message);
|
||||
resolve(null);
|
||||
}
|
||||
else {
|
||||
data.set(name, content.json);
|
||||
resLoader.release(url);
|
||||
resolve(content.json);
|
||||
}
|
||||
});
|
||||
const url = pathJson + name;
|
||||
if (this.zip) {
|
||||
content = await ZipLoader.getJson(pathZip, `${name}.json`);
|
||||
}
|
||||
else {
|
||||
content = await resLoader.loadAsync(url, JsonAsset);
|
||||
}
|
||||
|
||||
if (content) {
|
||||
data.set(name, content.json);
|
||||
resLoader.release(url);
|
||||
resolve(content.json);
|
||||
}
|
||||
else {
|
||||
resolve(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 加载所有配置表数据到缓存中 */
|
||||
static loadDirAsync(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resLoader.loadDir(path, (err: Error | null, assets: JsonAsset[]) => {
|
||||
if (err) {
|
||||
console.warn(err.message);
|
||||
resolve(false);
|
||||
}
|
||||
else {
|
||||
assets.forEach(asset => {
|
||||
data.set(asset.name, asset.json);
|
||||
});
|
||||
resLoader.releaseDir(path);
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 加载所有配置表数据到缓存中
|
||||
* @param isZip 是否为压缩包
|
||||
* @param zipNames 压缩包内的资源名列表
|
||||
*/
|
||||
static loadDir(zipNames?: string[]): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (this.zip && zipNames) {
|
||||
await ZipLoader.load(pathZip);
|
||||
zipNames.forEach(name => {
|
||||
data.set(name, ZipLoader.getJson(pathZip, `${name}.json`));
|
||||
});
|
||||
ZipLoader.release(pathZip);
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
resLoader.loadDir(pathJson, (err: Error | null, assets: JsonAsset[]) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
assets.forEach(asset => {
|
||||
data.set(asset.name, asset.json);
|
||||
});
|
||||
resLoader.releaseDir(pathJson);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ export class TimeUtil {
|
||||
* @param time2 结束时间
|
||||
* @returns
|
||||
*/
|
||||
public static daysBetween(time1: number | string | Date, time2: number | string | Date): number {
|
||||
static daysBetween(time1: number | string | Date, time2: number | string | Date): number {
|
||||
if (time2 == undefined) {
|
||||
time2 = +new Date();
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export class TimeUtil {
|
||||
}
|
||||
|
||||
/** 间隔秒数,时间顺序无要求,最后会获取绝对值 */
|
||||
public static secsBetween(time1: number, time2: number) {
|
||||
static secsBetween(time1: number, time2: number) {
|
||||
let dates = Math.abs((time2 - time1)) / (1000);
|
||||
dates = Math.floor(dates) + 1;
|
||||
return dates;
|
||||
@@ -28,7 +28,7 @@ export class TimeUtil {
|
||||
* 代码休眠时间
|
||||
* @param ms 毫秒
|
||||
*/
|
||||
public static async sleep(ms: number) {
|
||||
static async sleep(ms: number) {
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
|
||||
@@ -10,35 +10,35 @@ import { IControl } from './IControl';
|
||||
export abstract class BTreeNode implements IControl {
|
||||
protected _control!: IControl;
|
||||
|
||||
public title: string;
|
||||
title: string;
|
||||
|
||||
public constructor() {
|
||||
constructor() {
|
||||
this.title = this.constructor.name;
|
||||
}
|
||||
|
||||
public start(blackboard?: any) {
|
||||
start(blackboard?: any) {
|
||||
|
||||
}
|
||||
|
||||
public end(blackboard?: any) {
|
||||
end(blackboard?: any) {
|
||||
|
||||
}
|
||||
|
||||
public abstract run(blackboard?: any): void;
|
||||
abstract run(blackboard?: any): void;
|
||||
|
||||
public setControl(control: IControl) {
|
||||
setControl(control: IControl) {
|
||||
this._control = control;
|
||||
}
|
||||
|
||||
public running(blackboard?: any) {
|
||||
running(blackboard?: any) {
|
||||
this._control.running(this);
|
||||
}
|
||||
|
||||
public success() {
|
||||
success() {
|
||||
this._control.success();
|
||||
}
|
||||
|
||||
public fail() {
|
||||
fail() {
|
||||
this._control.fail();
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export class BehaviorTree implements IControl {
|
||||
private _blackboard: any;
|
||||
|
||||
/** 是否已开始执行 */
|
||||
public get started(): boolean {
|
||||
get started(): boolean {
|
||||
return this._started;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export class BehaviorTree implements IControl {
|
||||
* @param node 根节点
|
||||
* @param blackboard 外部参数对象
|
||||
*/
|
||||
public constructor(node: BTreeNode, blackboard?: any) {
|
||||
constructor(node: BTreeNode, blackboard?: any) {
|
||||
countUnnamed += 1;
|
||||
this.title = node.constructor.name + '(btree_' + (countUnnamed) + ')';
|
||||
this._root = node;
|
||||
@@ -34,12 +34,12 @@ export class BehaviorTree implements IControl {
|
||||
}
|
||||
|
||||
/** 设置行为逻辑中的共享数据 */
|
||||
public setObject(blackboard: any) {
|
||||
setObject(blackboard: any) {
|
||||
this._blackboard = blackboard;
|
||||
}
|
||||
|
||||
/** 执行行为树逻辑 */
|
||||
public run() {
|
||||
run() {
|
||||
if (this._started) {
|
||||
console.error(`行为树【${this.title}】未调用步骤,在最后一次调用步骤时有一个任务未完成`);
|
||||
}
|
||||
@@ -52,16 +52,16 @@ export class BehaviorTree implements IControl {
|
||||
node.run(this._blackboard);
|
||||
}
|
||||
|
||||
public running(node: BTreeNode) {
|
||||
running(node: BTreeNode) {
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
public success() {
|
||||
success() {
|
||||
this._current.end(this._blackboard);
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
public fail() {
|
||||
fail() {
|
||||
this._current.end(this._blackboard);
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { BTreeNode } from './BTreeNode';
|
||||
/** 复合节点 */
|
||||
export abstract class BranchNode extends BTreeNode {
|
||||
/** 子节点数组 */
|
||||
public children: Array<BTreeNode>;
|
||||
children: Array<BTreeNode>;
|
||||
/** 当前任务索引 */
|
||||
protected _actualTask!: number;
|
||||
/** 正在运行的节点 */
|
||||
@@ -19,17 +19,17 @@ export abstract class BranchNode extends BTreeNode {
|
||||
/** 外部参数对象 */
|
||||
protected _blackboard: any;
|
||||
|
||||
public constructor(nodes: Array<BTreeNode>) {
|
||||
constructor(nodes: Array<BTreeNode>) {
|
||||
super();
|
||||
this.children = nodes || [];
|
||||
}
|
||||
|
||||
public start() {
|
||||
start() {
|
||||
this._actualTask = 0;
|
||||
super.start();
|
||||
}
|
||||
|
||||
public run(blackboard?: any) {
|
||||
run(blackboard?: any) {
|
||||
if (this.children.length == 0) { // 没有子任务直接视为执行失败
|
||||
this._control.fail();
|
||||
}
|
||||
@@ -53,17 +53,17 @@ export abstract class BranchNode extends BTreeNode {
|
||||
node.run(this._blackboard);
|
||||
}
|
||||
|
||||
public running(node: BTreeNode) {
|
||||
running(node: BTreeNode) {
|
||||
this._nodeRunning = node;
|
||||
this._control.running(node);
|
||||
}
|
||||
|
||||
public success() {
|
||||
success() {
|
||||
this._nodeRunning = null;
|
||||
this._runningNode.end(this._blackboard);
|
||||
}
|
||||
|
||||
public fail() {
|
||||
fail() {
|
||||
this._nodeRunning = null;
|
||||
this._runningNode.end(this._blackboard);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { BTreeNode } from './BTreeNode';
|
||||
* 如果装饰器是true 它所在的子树会被执行,如果是false 所在的子树不会被执行
|
||||
*/
|
||||
export class Decorator extends BTreeNode {
|
||||
public node!: BTreeNode;
|
||||
node!: BTreeNode;
|
||||
|
||||
constructor(node?: string | BTreeNode) {
|
||||
super()
|
||||
@@ -25,17 +25,17 @@ export class Decorator extends BTreeNode {
|
||||
this.node = BehaviorTree.getNode(node);
|
||||
}
|
||||
|
||||
public start() {
|
||||
start() {
|
||||
this.node.setControl(this);
|
||||
this.node.start();
|
||||
super.start();
|
||||
}
|
||||
|
||||
public end() {
|
||||
end() {
|
||||
this.node.end();
|
||||
}
|
||||
|
||||
public run(blackboard: any) {
|
||||
run(blackboard: any) {
|
||||
this.node.run(blackboard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ import { BranchNode } from './BranchNode';
|
||||
* 只要子节点有一个返回true,则停止执行其它子节点,并且Selector返回true。如果所有子节点都返回false,则Selector返回false。
|
||||
*/
|
||||
export class Selector extends BranchNode {
|
||||
public success() {
|
||||
success() {
|
||||
super.success()
|
||||
this._control.success();
|
||||
}
|
||||
|
||||
public fail() {
|
||||
fail() {
|
||||
super.fail()
|
||||
|
||||
this._actualTask += 1;
|
||||
|
||||
@@ -16,7 +16,7 @@ export class Sequence extends BranchNode {
|
||||
super(nodes);
|
||||
}
|
||||
|
||||
public success() {
|
||||
success() {
|
||||
super.success();
|
||||
|
||||
this._actualTask += 1;
|
||||
@@ -28,7 +28,7 @@ export class Sequence extends BranchNode {
|
||||
}
|
||||
}
|
||||
|
||||
public fail() {
|
||||
fail() {
|
||||
super.fail();
|
||||
this._control.fail();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export namespace ecs {
|
||||
export interface IComp {
|
||||
canRecycle: boolean;
|
||||
ent: Entity;
|
||||
tid: number;
|
||||
|
||||
reset(): void;
|
||||
}
|
||||
@@ -145,17 +146,14 @@ export namespace ecs {
|
||||
if (ctor.tid === -1) {
|
||||
ctor.tid = ECSModel.compTid++;
|
||||
ctor.compName = name;
|
||||
ECSModel.compCtors.push(ctor); // 注册不同类型的组件
|
||||
if (canNew) {
|
||||
ECSModel.compCtors.push(ctor); // 注册不同类型的组件
|
||||
ECSModel.compPools.set(ctor.tid, []);
|
||||
}
|
||||
else {
|
||||
ECSModel.compCtors.push(null!);
|
||||
}
|
||||
ECSModel.compAddOrRemove.set(ctor.tid, []);
|
||||
}
|
||||
else {
|
||||
throw new Error(`重复注册组件: ${name}.`);
|
||||
throw new Error(`ECS 组件重复注册: ${name}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,18 +14,18 @@ import { ECSEntity } from "./ECSEntity";
|
||||
export abstract class ECSComp implements ecs.IComp {
|
||||
/** 组件的类型编号,-1表示未给该组件分配编号 */
|
||||
static tid: number = -1;
|
||||
|
||||
/** 组件名 */
|
||||
static compName: string;
|
||||
|
||||
/** 拥有该组件的实体 */
|
||||
ent!: ECSEntity;
|
||||
|
||||
/**
|
||||
* 是否可回收组件对象,默认情况下都是可回收的
|
||||
* 注:如果该组件对象是由ecs系统外部创建的,则不可回收,需要用户自己手动进行回收
|
||||
*/
|
||||
canRecycle: boolean = true;
|
||||
/** 拥有该组件的实体 */
|
||||
ent!: ECSEntity;
|
||||
/** 组件的类型编号 */
|
||||
tid: number = -1;
|
||||
|
||||
/**
|
||||
* 组件被回收时会调用这个接口。可以在这里重置数据,或者解除引用
|
||||
|
||||
@@ -81,22 +81,30 @@ export class ECSEntity {
|
||||
this._parent = value;
|
||||
}
|
||||
|
||||
private _children: Map<number, ECSEntity> | null = null;
|
||||
/** 子实体集合 */
|
||||
get children(): Map<number, ECSEntity> {
|
||||
if (this._children == null) {
|
||||
this._children = new Map<number, ECSEntity>();
|
||||
}
|
||||
return this._children;
|
||||
/** 子实体 */
|
||||
private childs: Map<number, ECSEntity> = null!;
|
||||
|
||||
/** 获取子实体 */
|
||||
getChild<T>(eid: number) {
|
||||
return this.childs.get(eid) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加子实体
|
||||
* @param entity 被添加的实体对象
|
||||
* @returns 子实体的唯一编号, -1表示添加失败
|
||||
*/
|
||||
addChild(entity: ECSEntity) {
|
||||
addChild(entity: ECSEntity): number {
|
||||
if (this.childs == null) this.childs = new Map<number, ECSEntity>();
|
||||
|
||||
if (this.childs.has(entity.eid)) {
|
||||
console.warn(`子实体${entity.name}已存在`);
|
||||
return -1;
|
||||
}
|
||||
|
||||
entity._parent = this;
|
||||
this.children.set(entity.eid, entity);
|
||||
this.childs.set(entity.eid, entity);
|
||||
return entity.eid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,10 +114,10 @@ export class ECSEntity {
|
||||
* @returns
|
||||
*/
|
||||
removeChild(entity: ECSEntity, isDestroy = true) {
|
||||
if (this.children == null) return;
|
||||
if (this.childs == null) return;
|
||||
|
||||
entity.parent = null;
|
||||
this.children.delete(entity.eid);
|
||||
this.childs.delete(entity.eid);
|
||||
if (isDestroy) entity.destroy();
|
||||
}
|
||||
|
||||
@@ -154,6 +162,7 @@ export class ECSEntity {
|
||||
// @ts-ignore
|
||||
this[ctor.compName] = comp;
|
||||
this.compTid2Ctor.set(compTid, ctor);
|
||||
comp.tid = compTid;
|
||||
comp.ent = this;
|
||||
// 广播实体添加组件的消息
|
||||
broadcastCompAddOrRemove(this, compTid);
|
||||
@@ -173,9 +182,11 @@ export class ECSEntity {
|
||||
this[tmpCtor.compName] = ctor;
|
||||
this.compTid2Ctor.set(compTid, tmpCtor);
|
||||
//@ts-ignore
|
||||
ctor.ent = this;
|
||||
ctor.tid = compTid;
|
||||
//@ts-ignore
|
||||
ctor.canRecycle = false;
|
||||
//@ts-ignore
|
||||
ctor.ent = this;
|
||||
broadcastCompAddOrRemove(this, compTid);
|
||||
|
||||
return this;
|
||||
@@ -272,11 +283,11 @@ export class ECSEntity {
|
||||
}
|
||||
|
||||
// 移除模块上所有子模块
|
||||
if (this._children) {
|
||||
this._children.forEach(e => {
|
||||
if (this.childs) {
|
||||
this.childs.forEach(e => {
|
||||
this.removeChild(e);
|
||||
});
|
||||
this._children = null;
|
||||
this.childs = null!;
|
||||
}
|
||||
|
||||
// 移除实体上所有组件
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
declare global {
|
||||
interface Date {
|
||||
/**
|
||||
* 时间格式化
|
||||
* @param format 时间格式,例如:yy-mm-dd hh:mm:ss
|
||||
*/
|
||||
format(format: string): string;
|
||||
|
||||
/**
|
||||
* 时间加法
|
||||
* @param addMillis 时间加法,单位毫秒
|
||||
*/
|
||||
addTime(addMillis: number): Date;
|
||||
|
||||
/**
|
||||
* 验证时间是否在指定范围
|
||||
* @param t1 范围开始时间
|
||||
* @param t2 范围结束时间
|
||||
*/
|
||||
range(t1: number | Date, t2: number | Date): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
/** 格式化时间字符串 */
|
||||
Date.prototype.format = function (format: string): string {
|
||||
const year: number = this.getFullYear();
|
||||
const month: number = this.getMonth() + 1;
|
||||
@@ -35,4 +51,27 @@ Date.prototype.format = function (format: string): string {
|
||||
return r;
|
||||
};
|
||||
|
||||
export { };
|
||||
Date.prototype.addTime = function (addMillis: number): Date {
|
||||
return new Date(this.getTime() + addMillis);
|
||||
}
|
||||
|
||||
Date.prototype.range = function (d1: number | Date, d2: number | Date): boolean {
|
||||
let t1: number = -1;
|
||||
let t2: number = -1;
|
||||
if (d1 instanceof Date)
|
||||
t1 = d1.getTime();
|
||||
else
|
||||
t1 = d1;
|
||||
if (d2 instanceof Date)
|
||||
t2 = d2.getTime();
|
||||
else
|
||||
t2 = d2;
|
||||
|
||||
let now = this.getTime();
|
||||
if (now >= t1 && now < t2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export { };
|
||||
@@ -59,7 +59,7 @@ export default class ButtonSimple extends Component {
|
||||
}
|
||||
|
||||
/** 短按触摸音效 */
|
||||
protected async playEffect() {
|
||||
protected playEffect() {
|
||||
if (ButtonSimple.effectPath) {
|
||||
oops.audio.playEffect(ButtonSimple.effectPath);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import { Label, _decorator } from "cc";
|
||||
import { EDITOR } from "cc/env";
|
||||
import { oops } from "../../../core/Oops";
|
||||
import { EventMessage } from "../../../core/common/event/EventMessage";
|
||||
import { TimeUtil } from "../../../core/utils/TimeUtils";
|
||||
import { EDITOR } from "cc/env";
|
||||
|
||||
const { ccclass, property, menu } = _decorator;
|
||||
|
||||
/** 倒计时标签 */
|
||||
@ccclass("LabelTime")
|
||||
@menu('OopsFramework/Label/LabelTime (倒计时标签)')
|
||||
@menu("OopsFramework/Label/LabelTime (倒计时标签)")
|
||||
export default class LabelTime extends Label {
|
||||
@property({
|
||||
tooltip: "到计时间总时间(单位秒)"
|
||||
tooltip: "到计时间总时间(单位秒)",
|
||||
})
|
||||
countDown: number = 1000;
|
||||
|
||||
@property({
|
||||
tooltip: "天数数据格式化"
|
||||
tooltip: "天数数据格式化",
|
||||
})
|
||||
dayFormat: string = "{0} day";
|
||||
dayFormat: string = "{0}天{1}小时";
|
||||
|
||||
@property({
|
||||
tooltip: "时间格式化"
|
||||
tooltip: "时间格式化",
|
||||
})
|
||||
timeFormat: string = "{0}:{1}:{2}";
|
||||
|
||||
@property({
|
||||
tooltip: "是否有00"
|
||||
tooltip: "时间是否有固定二位数据",
|
||||
})
|
||||
zeroize: boolean = true;
|
||||
|
||||
@@ -35,9 +35,9 @@ export default class LabelTime extends Label {
|
||||
})
|
||||
paused: boolean = false;
|
||||
|
||||
private backStartTime: number = 0; // 进入后台开始时间
|
||||
private dateDisable!: boolean; // 时间能否由天数显示
|
||||
private result!: string; // 时间结果字符串
|
||||
private backStartTime: number = 0; // 进入后台开始时间
|
||||
private dateDisable!: boolean; // 时间能否由天数显示
|
||||
private result!: string; // 时间结果字符串
|
||||
|
||||
/** 每秒触发事件 */
|
||||
onSecond: Function = null!;
|
||||
@@ -45,10 +45,9 @@ export default class LabelTime extends Label {
|
||||
onComplete: Function = null!;
|
||||
|
||||
private replace(value: string, ...args: any): string {
|
||||
return value.replace(/\{(\d+)\}/g,
|
||||
function (m, i) {
|
||||
return args[i];
|
||||
});
|
||||
return value.replace(/\{(\d+)\}/g, function (m, i) {
|
||||
return args[i];
|
||||
});
|
||||
}
|
||||
|
||||
/** 格式化字符串 */
|
||||
@@ -75,7 +74,7 @@ export default class LabelTime extends Label {
|
||||
let dataFormat = this.dayFormat;
|
||||
let index = dataFormat.indexOf("{1}");
|
||||
if (hours == 0 && index > -1) {
|
||||
dataFormat = dataFormat.substring(0, index - 1);
|
||||
dataFormat = dataFormat.substring(0, index);
|
||||
}
|
||||
let df = dataFormat;
|
||||
if (date > 1 && dataFormat.indexOf("days") < 0) {
|
||||
@@ -84,23 +83,21 @@ export default class LabelTime extends Label {
|
||||
if (date < 2) {
|
||||
df = df.replace("days", "day");
|
||||
}
|
||||
this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..."
|
||||
|
||||
if (this.zeroize) {
|
||||
this.result = this.replace(df, date, this.coverString(hours));
|
||||
}
|
||||
else {
|
||||
this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..."
|
||||
}
|
||||
}
|
||||
else {
|
||||
hours += date * 24;
|
||||
if (this.zeroize) {
|
||||
this.result = this.replace(
|
||||
this.timeFormat,
|
||||
this.coverString(hours),
|
||||
this.coverString(minutes),
|
||||
this.coverString(seconds)); // 否则显示 "01:12:24"
|
||||
this.result = this.replace(this.timeFormat, this.coverString(hours), this.coverString(minutes), this.coverString(seconds)); // 否则显示 "01:12:24"
|
||||
}
|
||||
else {
|
||||
this.result = this.replace(
|
||||
this.timeFormat,
|
||||
hours,
|
||||
minutes,
|
||||
seconds);
|
||||
this.result = this.replace(this.timeFormat, hours, minutes, seconds);
|
||||
}
|
||||
}
|
||||
this.string = this.result;
|
||||
@@ -108,8 +105,7 @@ export default class LabelTime extends Label {
|
||||
|
||||
/** 个位数的时间数据将字符串补位 */
|
||||
private coverString(value: number) {
|
||||
if (value < 10)
|
||||
return "0" + value;
|
||||
if (value < 10) return "0" + value;
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@@ -123,7 +119,7 @@ export default class LabelTime extends Label {
|
||||
* @param second 倒计时时间(单位秒)
|
||||
*/
|
||||
setTime(second: number) {
|
||||
this.countDown = second; // 倒计时,初始化显示字符串
|
||||
this.countDown = second; // 倒计时,初始化显示字符串
|
||||
this.timing_end();
|
||||
this.timing_start();
|
||||
this.format();
|
||||
@@ -140,15 +136,33 @@ export default class LabelTime extends Label {
|
||||
this.format();
|
||||
}
|
||||
|
||||
start() {
|
||||
onLoad() {
|
||||
if (!EDITOR) {
|
||||
oops.message.on(EventMessage.GAME_SHOW, this.onGameShow, this);
|
||||
oops.message.on(EventMessage.GAME_HIDE, this.onGameHide, this);
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.countDown <= 0) return;
|
||||
this.timing_start();
|
||||
this.format();
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
super.onEnable();
|
||||
if (!EDITOR) {
|
||||
this.onGameShow();
|
||||
}
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
super.onDisable();
|
||||
if (!EDITOR) {
|
||||
this.onGameHide();
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (!EDITOR) {
|
||||
oops.message.off(EventMessage.GAME_SHOW, this.onGameShow, this);
|
||||
@@ -175,6 +189,12 @@ export default class LabelTime extends Label {
|
||||
}
|
||||
|
||||
private onScheduleSecond() {
|
||||
if (this.countDown == 0) {
|
||||
this.format();
|
||||
this.onScheduleComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
this.countDown--;
|
||||
this.format();
|
||||
if (this.onSecond) this.onSecond(this.node);
|
||||
@@ -187,15 +207,17 @@ export default class LabelTime extends Label {
|
||||
private onScheduleComplete() {
|
||||
this.timing_end();
|
||||
this.format();
|
||||
this.unschedule(this.onScheduleSecond);
|
||||
if (this.onComplete) this.onComplete(this.node);
|
||||
}
|
||||
|
||||
/** 开始计时 */
|
||||
private timing_start() {
|
||||
timing_start() {
|
||||
this.schedule(this.onScheduleSecond, 1);
|
||||
}
|
||||
|
||||
private timing_end() {
|
||||
/** 关闭计时 */
|
||||
timing_end() {
|
||||
this.unscheduleAllCallbacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export class LanguageManager {
|
||||
* @param language 语言名
|
||||
* @param callback 多语言资源数据加载完成回调
|
||||
*/
|
||||
setLanguage(language: string, callback?: (success: boolean) => void) {
|
||||
setLanguage(language: string, callback?: Function) {
|
||||
if (language == null || language == "") {
|
||||
language = this._defaultLanguage;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export class LanguageManager {
|
||||
}
|
||||
|
||||
if (language === LanguageData.current) {
|
||||
callback && callback(false);
|
||||
callback && callback();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ export class LanguageManager {
|
||||
LanguageData.current = language;
|
||||
this._languagePack.updateLanguage(language);
|
||||
this._languagePack.releaseLanguageAssets(oldLanguage);
|
||||
callback && callback(true);
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ export class LanguagePack {
|
||||
/** 多语言Excel配置表数据 */
|
||||
private loadTable(lang: string): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let json = await JsonUtil.loadAsync("Language");
|
||||
let json = await JsonUtil.load("Language");
|
||||
if (json) {
|
||||
LanguageData.language.set(LanguageDataType.Excel, json);
|
||||
Logger.instance.logConfig("config/game/Language", "下载语言包 table 资源");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { LanguageData } from "../gui/language/LanguageData";
|
||||
|
||||
/**
|
||||
* 数值格式化函数, 通过语义解析自动设置值的范围
|
||||
* //整数
|
||||
@@ -93,19 +95,20 @@ class StringFormat {
|
||||
}
|
||||
|
||||
/** 将数字缩短显示为KMBT单位 大写,目前只支持英文 */
|
||||
private kmbt(value: number, lang: string = 'en') {
|
||||
private kmbt(value: number) {
|
||||
//10^4=万, 10^8=亿,10^12=兆,10^16=京,
|
||||
let counts = [1000, 1000000, 1000000000, 1000000000000];
|
||||
let units = ['', 'K', 'M', 'B', 'T'];
|
||||
let counts: number[] = null!;
|
||||
let units: string[] = null!;
|
||||
|
||||
switch (lang) {
|
||||
switch (LanguageData.current) {
|
||||
case 'zh':
|
||||
//10^4=万, 10^8=亿,10^12=兆,10^16=京,
|
||||
counts = [10000, 100000000, 1000000000000, 10000000000000000];
|
||||
units = ['', '万', '亿', '兆', '京'];
|
||||
break;
|
||||
|
||||
default:
|
||||
counts = [1000, 1000000, 1000000000, 1000000000000];
|
||||
units = ['', 'K', 'M', 'B', 'T'];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
85
assets/module/common/CCBusiness.ts
Normal file
85
assets/module/common/CCBusiness.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2025-09-18 10:20:51
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2025-09-18 17:20:51
|
||||
*/
|
||||
|
||||
import { EventDispatcher } from "../../core/common/event/EventDispatcher";
|
||||
import { ListenerFunc } from "../../core/common/event/EventMessage";
|
||||
import { CCEntity } from "./CCEntity";
|
||||
|
||||
/** 业务逻辑 */
|
||||
export class CCBusiness<T extends CCEntity> {
|
||||
ent!: T;
|
||||
|
||||
/** 业务逻辑初始化 */
|
||||
protected init() {
|
||||
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// 释放消息对象
|
||||
if (this._event) {
|
||||
this._event.destroy();
|
||||
this._event = null;
|
||||
}
|
||||
}
|
||||
|
||||
//#region 全局事件管理
|
||||
|
||||
private _event: EventDispatcher | null = null;
|
||||
/** 全局事件管理器 */
|
||||
private get event(): EventDispatcher {
|
||||
if (this._event == null) this._event = new EventDispatcher();
|
||||
return this._event;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册全局事件
|
||||
* @param event 事件名
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的this对象
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: any) {
|
||||
this.event.on(event, listener, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除全局事件
|
||||
* @param event 事件名
|
||||
*/
|
||||
off(event: string) {
|
||||
this.event.off(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
dispatchEvent(event: string, ...args: any) {
|
||||
this.event.dispatchEvent(event, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置全局事件
|
||||
* @example
|
||||
* this.setEvent("onGlobal");
|
||||
* this.dispatchEvent("onGlobal", "全局事件");
|
||||
*
|
||||
* onGlobal(event: string, args: any) { console.log(args) };
|
||||
*/
|
||||
protected setEvent(...args: string[]) {
|
||||
const self: any = this;
|
||||
for (const name of args) {
|
||||
const func = self[name];
|
||||
if (func)
|
||||
this.on(name, func, this);
|
||||
else
|
||||
console.error(`名为【${name}】的全局事方法不存在`);
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "5908a4e6-3359-48b6-95e0-a3b44ea50790",
|
||||
"uuid": "4a753a57-2867-478e-b770-c05d96535c4e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
186
assets/module/common/CCEntity.ts
Normal file
186
assets/module/common/CCEntity.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { __private, Node } from "cc";
|
||||
import { resLoader } from "../../core/common/loader/ResLoader";
|
||||
import { gui } from "../../core/gui/Gui";
|
||||
import { LayerUIElement, UIParam } from "../../core/gui/layer/LayerUIElement";
|
||||
import { oops } from "../../core/Oops";
|
||||
import { ViewUtil } from "../../core/utils/ViewUtil";
|
||||
import { ecs } from "../../libs/ecs/ECS";
|
||||
import { ECSEntity } from "../../libs/ecs/ECSEntity";
|
||||
import { CompType } from "../../libs/ecs/ECSModel";
|
||||
import { CCBusiness } from "./CCBusiness";
|
||||
import { CCView } from "./CCView";
|
||||
import { CCViewVM } from "./CCViewVM";
|
||||
|
||||
export type ECSCtor<T extends ecs.Comp> = __private.__types_globals__Constructor<T> | __private.__types_globals__AbstractedConstructor<T>;
|
||||
export type ECSView = CCViewVM<CCEntity> | CCView<CCEntity>;
|
||||
|
||||
/** ECS 游戏模块实体 */
|
||||
export abstract class CCEntity extends ecs.Entity {
|
||||
//#region 子模块管理
|
||||
/** 单例子实体 */
|
||||
private singletons: Map<any, ECSEntity> = null!;
|
||||
|
||||
/** 添加单例子实体 */
|
||||
addChildSingleton<T>(cls: any): T {
|
||||
if (this.singletons == null) this.singletons = new Map();
|
||||
if (this.singletons.has(cls)) {
|
||||
console.error(`${cls.name} 单例子实体已存在`);
|
||||
return null!;
|
||||
}
|
||||
let entity = cls.create();
|
||||
this.singletons.set(cls, entity);
|
||||
this.addChild(entity);
|
||||
return entity as T;
|
||||
}
|
||||
|
||||
/** 获取单例子实体 */
|
||||
getChildSingleton<T>(cls: any): T {
|
||||
return this.singletons.get(cls) as T;
|
||||
}
|
||||
|
||||
/** 移除单例子实体 */
|
||||
removeChildSingleton(cls: any) {
|
||||
let entity = this.singletons.get(cls);
|
||||
if (entity) {
|
||||
this.singletons.delete(cls);
|
||||
this.removeChild(entity);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region 游戏视图层管理
|
||||
/**
|
||||
* 通过资源内存中获取预制上的组件添加到ECS实体中
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param parent 显示对象父级
|
||||
* @param path 显示资源地址
|
||||
* @param bundleName 资源包名称
|
||||
*/
|
||||
addPrefab<T extends ECSView>(ctor: ECSCtor<T>, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) {
|
||||
const node = ViewUtil.createPrefabNode(path, bundleName);
|
||||
const comp = node.getComponent(ctor)!;
|
||||
this.add(comp);
|
||||
node.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加视图层组件
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param params 界面参数
|
||||
* @returns 界面节点
|
||||
*/
|
||||
addUi<T extends ECSView>(ctor: ECSCtor<T>, params?: UIParam): Promise<Node> {
|
||||
return new Promise<Node>(async (resolve, reject) => {
|
||||
const key = gui.internal.getKey(ctor);
|
||||
if (key) {
|
||||
if (params == null) {
|
||||
params = { preload: true };
|
||||
}
|
||||
else {
|
||||
params.preload = true;
|
||||
}
|
||||
|
||||
const node = await oops.gui.open(key, params);
|
||||
const comp = node.getComponent(ctor) as ecs.Comp;
|
||||
this.add(comp);
|
||||
oops.gui.show(key);
|
||||
resolve(node);
|
||||
}
|
||||
else {
|
||||
console.error(`${key} 界面组件未使用 gui.register 注册`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除视图层组件
|
||||
* @param ctor 界面逻辑组件
|
||||
*/
|
||||
removeUi(ctor: CompType<ecs.IComp>) {
|
||||
const key = gui.internal.getKey(ctor);
|
||||
if (key) {
|
||||
const node = oops.gui.get(key);
|
||||
if (node == null) {
|
||||
console.error(`${key} 界面重复关闭`);
|
||||
return;
|
||||
}
|
||||
|
||||
const comp = node.getComponent(LayerUIElement);
|
||||
if (comp) {
|
||||
// 处理界面关闭动画播放完成后,移除ECS组件,避免使用到组件实体数据还在动画播放时在使用导致的空对象问题
|
||||
comp.onClose = this.remove.bind(this, ctor);
|
||||
oops.gui.remove(key);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.remove(ctor);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region 游戏业务层管理
|
||||
/** 模块业务逻辑组件 */
|
||||
private businesss: Map<any, CCBusiness<CCEntity>> = null!;
|
||||
|
||||
/**
|
||||
* 批量添加组件
|
||||
* @param ctors 组件类
|
||||
* @returns
|
||||
*/
|
||||
addBusinesss<T extends CCBusiness<CCEntity>>(...clss: any[]) {
|
||||
for (let ctor of clss) {
|
||||
this.addBusiness<T>(ctor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加业务逻辑组件
|
||||
* @param cls 业务逻辑组件类
|
||||
* @returns 业务逻辑组件实例
|
||||
*/
|
||||
addBusiness<T extends CCBusiness<CCEntity>>(cls: any): T {
|
||||
if (this.businesss == null) this.businesss = new Map();
|
||||
if (this.businesss.has(cls)) {
|
||||
console.error(`${cls.name} 业务逻辑组件已存在`);
|
||||
return null!;
|
||||
}
|
||||
let business = new cls();
|
||||
business.ent = this;
|
||||
business.init();
|
||||
this.businesss.set(cls, business);
|
||||
return business as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取业务逻辑组件
|
||||
* @param cls 业务逻辑组件类
|
||||
* @returns 业务逻辑组件实例
|
||||
*/
|
||||
getBusiness<T extends CCBusiness<CCEntity>>(cls: any): T {
|
||||
return this.businesss.get(cls) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除业务逻辑组件
|
||||
* @param cls 业务逻辑组件类
|
||||
*/
|
||||
removeBusiness(cls: any) {
|
||||
let business = this.businesss.get(cls);
|
||||
if (business) this.businesss.delete(cls);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
destroy(): void {
|
||||
if (this.singletons) {
|
||||
this.singletons.clear();
|
||||
this.singletons = null!;
|
||||
}
|
||||
|
||||
if (this.businesss) {
|
||||
this.businesss.forEach(business => business.destroy());
|
||||
this.businesss.clear();
|
||||
this.businesss = null!;
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
9
assets/module/common/CCEntity.ts.meta
Normal file
9
assets/module/common/CCEntity.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "59805570-9a5d-4894-aac0-14a60c895c74",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,46 +1,56 @@
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2021-11-11 19:05:32
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-06 17:20:51
|
||||
*/
|
||||
|
||||
import { _decorator } from 'cc';
|
||||
import { GameComponent } from './GameComponent';
|
||||
import { ecs } from '../../libs/ecs/ECS';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 游戏显示对象组件
|
||||
*
|
||||
* 功能介绍:
|
||||
* 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能
|
||||
* 2. 对象自带全局事件监听、释放、发送全局消息功能
|
||||
* 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象
|
||||
*
|
||||
* 应用场景
|
||||
* 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象
|
||||
*
|
||||
* @example
|
||||
@ccclass('RoleViewComp')
|
||||
@ecs.register('RoleView', false)
|
||||
export class RoleViewComp extends CCComp {
|
||||
@property({ type: sp.Skeleton, tooltip: '角色动画' })
|
||||
spine: sp.Skeleton = null!;
|
||||
|
||||
onLoad(){
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ccclass('CCComp')
|
||||
export abstract class CCComp extends GameComponent implements ecs.IComp {
|
||||
static tid: number = -1;
|
||||
static compName: string;
|
||||
|
||||
canRecycle!: boolean;
|
||||
ent!: ecs.Entity;
|
||||
|
||||
abstract reset(): void;
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2021-11-11 19:05:32
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-06 17:20:51
|
||||
*/
|
||||
|
||||
import { ecs } from '../../libs/ecs/ECS';
|
||||
import { ECSModel } from '../../libs/ecs/ECSModel';
|
||||
import { CCEntity } from './CCEntity';
|
||||
import { GameComponent } from './GameComponent';
|
||||
|
||||
/**
|
||||
* ECS 游戏显示对象组件
|
||||
*
|
||||
* 功能介绍:
|
||||
* 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能
|
||||
* 2. 对象自带全局事件监听、释放、发送全局消息功能
|
||||
* 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象
|
||||
*
|
||||
* 应用场景
|
||||
* 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象
|
||||
*
|
||||
* @example
|
||||
@ccclass('RoleViewComp')
|
||||
@ecs.register('RoleView', false)
|
||||
export class RoleViewComp extends CCView<Role> {
|
||||
@property({ type: sp.Skeleton, tooltip: '角色动画' })
|
||||
spine: sp.Skeleton = null!;
|
||||
|
||||
onLoad(){
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
export abstract class CCView<T extends CCEntity> extends GameComponent implements ecs.IComp {
|
||||
static tid: number = -1;
|
||||
static compName: string;
|
||||
|
||||
canRecycle!: boolean;
|
||||
ent!: T;
|
||||
tid: number = -1;
|
||||
|
||||
/** 从父节点移除自己 */
|
||||
remove() {
|
||||
const cct = ECSModel.compCtors[this.tid];
|
||||
if (this.ent) {
|
||||
this.ent.removeUi(cct);
|
||||
}
|
||||
else {
|
||||
console.error(`组件 ${this.name} 移除失败,组件未注册`);
|
||||
}
|
||||
}
|
||||
|
||||
abstract reset(): void;
|
||||
}
|
||||
9
assets/module/common/CCView.ts.meta
Normal file
9
assets/module/common/CCView.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7f4397f9-04cd-42e3-a323-d468c93b19c0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,58 +1,68 @@
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2021-11-11 19:05:32
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-06 17:22:05
|
||||
*/
|
||||
|
||||
import { _decorator } from 'cc';
|
||||
import { ecs } from '../../libs/ecs/ECS';
|
||||
import VMParent from '../../libs/model-view/VMParent';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 支持 MVVM 功能的游戏显示对象组件
|
||||
*
|
||||
* 使用方法:
|
||||
* 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能
|
||||
* 2. 对象自带全局事件监听、释放、发送全局消息功能
|
||||
* 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象(节点名不能有重名)
|
||||
* 4. 对象支持 VMParent 所有功能
|
||||
*
|
||||
* 应用场景
|
||||
* 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象
|
||||
*
|
||||
* @example
|
||||
@ccclass('LoadingViewComp')
|
||||
@ecs.register('LoadingView', false)
|
||||
export class LoadingViewComp extends CCVMParentComp {
|
||||
// VM 组件绑定数据
|
||||
data: any = {
|
||||
// 加载资源当前进度
|
||||
finished: 0,
|
||||
// 加载资源最大进度
|
||||
total: 0,
|
||||
// 加载资源进度比例值
|
||||
progress: "0",
|
||||
// 加载流程中提示文本
|
||||
prompt: ""
|
||||
};
|
||||
|
||||
private progress: number = 0;
|
||||
|
||||
reset(): void {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ccclass('CCVMParentComp')
|
||||
export abstract class CCVMParentComp extends VMParent implements ecs.IComp {
|
||||
static tid: number = -1;
|
||||
static compName: string;
|
||||
|
||||
canRecycle!: boolean;
|
||||
ent!: ecs.Entity;
|
||||
|
||||
abstract reset(): void;
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2021-11-11 19:05:32
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-06 17:22:05
|
||||
*/
|
||||
|
||||
import { ecs } from '../../libs/ecs/ECS';
|
||||
import { ECSModel } from '../../libs/ecs/ECSModel';
|
||||
import VMParent from '../../libs/model-view/VMParent';
|
||||
import { CCEntity } from './CCEntity';
|
||||
|
||||
/**
|
||||
* 支持 MVVM 功能的 ECS 游戏显示对象组件
|
||||
*
|
||||
* 使用方法:
|
||||
* 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能
|
||||
* 2. 对象自带全局事件监听、释放、发送全局消息功能
|
||||
* 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象(节点名不能有重名)
|
||||
* 4. 对象支持 VMParent 所有功能
|
||||
*
|
||||
* 应用场景
|
||||
* 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象
|
||||
*
|
||||
* @example
|
||||
@ccclass('LoadingViewComp')
|
||||
@ecs.register('LoadingView', false)
|
||||
export class LoadingViewComp extends CCViewVM<Initialize> {
|
||||
// VM 组件绑定数据
|
||||
data: any = {
|
||||
// 加载资源当前进度
|
||||
finished: 0,
|
||||
// 加载资源最大进度
|
||||
total: 0,
|
||||
// 加载资源进度比例值
|
||||
progress: "0",
|
||||
// 加载流程中提示文本
|
||||
prompt: ""
|
||||
};
|
||||
|
||||
private progress: number = 0;
|
||||
|
||||
reset(): void {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
export abstract class CCViewVM<T extends CCEntity> extends VMParent implements ecs.IComp {
|
||||
static tid: number = -1;
|
||||
static compName: string;
|
||||
|
||||
canRecycle!: boolean;
|
||||
ent!: T;
|
||||
tid: number = -1;
|
||||
|
||||
/** 从父节点移除自己 */
|
||||
remove() {
|
||||
const cct = ECSModel.compCtors[this.tid];
|
||||
if (this.ent) {
|
||||
this.ent.removeUi(cct);
|
||||
}
|
||||
else {
|
||||
console.error(`组件 ${this.name} 移除失败,组件未注册`);
|
||||
}
|
||||
}
|
||||
|
||||
abstract reset(): void;
|
||||
}
|
||||
9
assets/module/common/CCViewVM.ts.meta
Normal file
9
assets/module/common/CCViewVM.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "33d31b2d-c771-4759-9fc6-96bbd5bcfa15",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -480,6 +480,12 @@ export class GameComponent extends Component {
|
||||
/** 游戏旋转屏幕事件回调 */
|
||||
protected onGameOrientation(): void { }
|
||||
//#endregion
|
||||
|
||||
/** 移除自己 */
|
||||
remove() {
|
||||
oops.gui.removeByNode(this.node);
|
||||
}
|
||||
|
||||
protected onDestroy() {
|
||||
// 释放消息对象
|
||||
if (this._event) {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import { Node, __private } from "cc";
|
||||
import { oops } from "../../core/Oops";
|
||||
import { resLoader } from "../../core/common/loader/ResLoader";
|
||||
import { Uiid } from "../../core/gui/layer/LayerEnum";
|
||||
import { LayerUIElement, UICallbacks } from "../../core/gui/layer/LayerUIElement";
|
||||
import { ViewUtil } from "../../core/utils/ViewUtil";
|
||||
import { ecs } from "../../libs/ecs/ECS";
|
||||
import { CompType } from "../../libs/ecs/ECSModel";
|
||||
import { CCComp } from "./CCComp";
|
||||
import { CCVMParentComp } from "./CCVMParentComp";
|
||||
|
||||
export type ECSCtor<T extends ecs.Comp> = __private.__types_globals__Constructor<T> | __private.__types_globals__AbstractedConstructor<T>;
|
||||
|
||||
export class ModuleUtil {
|
||||
/**
|
||||
* 添加界面组件
|
||||
* @param ent 模块实体
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param uiId 界面资源编号
|
||||
* @param uiArgs 界面参数
|
||||
*/
|
||||
static addViewUi<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiId: Uiid, uiArgs: any = null) {
|
||||
const uic: UICallbacks = {
|
||||
onAdded: (node: Node, params: any) => {
|
||||
const comp = node.getComponent(ctor) as ecs.Comp;
|
||||
//@ts-ignore
|
||||
if (!ent.has(ctor)) ent.add(comp);
|
||||
}
|
||||
};
|
||||
oops.gui.open(uiId, uiArgs, uic);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步添加视图层组件
|
||||
* @param ent 模块实体
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param uiId 界面资源编号
|
||||
* @param uiArgs 界面参数
|
||||
* @returns 界面节点
|
||||
*/
|
||||
static addViewUiAsync<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiId: Uiid, uiArgs: any = null): Promise<Node | null> {
|
||||
return new Promise<Node | null>((resolve, reject) => {
|
||||
const uic: UICallbacks = {
|
||||
onAdded: (node: Node, params: any) => {
|
||||
const comp = node.getComponent(ctor) as ecs.Comp;
|
||||
ent.add(comp);
|
||||
resolve(node);
|
||||
},
|
||||
onLoadFailure: () => {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
oops.gui.open(uiId, uiArgs, uic);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过资源内存中获取预制上的组件添加到ECS实体中
|
||||
* @param ent 模块实体
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param parent 显示对象父级
|
||||
* @param url 显示资源地址
|
||||
* @param bundleName 资源包名称
|
||||
*/
|
||||
static addView<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, parent: Node, url: string, bundleName: string = resLoader.defaultBundleName) {
|
||||
const node = ViewUtil.createPrefabNode(url, bundleName);
|
||||
const comp = node.getComponent(ctor)!;
|
||||
ent.add(comp);
|
||||
node.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务实体上移除界面组件
|
||||
* @param ent 模块实体
|
||||
* @param ctor 界面逻辑组件
|
||||
* @param uiId 界面资源编号
|
||||
* @param isDestroy 是否释放界面缓存(默认为释放界面缓存)
|
||||
* @param onRemoved 窗口关闭完成事件
|
||||
*/
|
||||
static removeViewUi(ent: ecs.Entity, ctor: CompType<ecs.IComp>, uiId: Uiid, isDestroy: boolean = true, onRemoved?: Function) {
|
||||
const node = oops.gui.get(uiId);
|
||||
if (!node) {
|
||||
if (onRemoved) onRemoved();
|
||||
return;
|
||||
}
|
||||
|
||||
const comp = node.getComponent(LayerUIElement);
|
||||
if (comp) {
|
||||
comp.onCloseWindowBefore = () => {
|
||||
// 移除ECS显示组件
|
||||
if (isDestroy) ent.remove(ctor, isDestroy);
|
||||
if (onRemoved) onRemoved();
|
||||
};
|
||||
oops.gui.remove(uiId, isDestroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ const keys = (Object.keys(buildTimeConstants) as (keyof typeof buildTimeConstant
|
||||
|
||||
/* 游戏运行环境 */
|
||||
export class BuildTimeConstants {
|
||||
constructor() {
|
||||
toString() {
|
||||
const keyNameMaxLen = keys.reduce((len, key) => Math.max(len, key.length), 0);
|
||||
const enviroment = `${keys.map((key) => {
|
||||
const value = buildTimeConstants[key];
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
* @LastEditTime: 2022-11-01 15:47:16
|
||||
*/
|
||||
|
||||
import { BuildTimeConstants } from "./BuildTimeConstants";
|
||||
import { GameConfig } from "./GameConfig";
|
||||
import { GameQueryConfig } from "./GameQueryConfig";
|
||||
|
||||
/** 游戏配置静态访问类 */
|
||||
export class Config {
|
||||
/** 环境常量 */
|
||||
// btc!: BuildTimeConstants;
|
||||
btc: BuildTimeConstants = new BuildTimeConstants();
|
||||
|
||||
/** 游戏配置数据,版本号、支持语种等数据 */
|
||||
game!: GameConfig;
|
||||
|
||||
@@ -4,38 +4,71 @@
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2023-02-14 14:27:22
|
||||
*/
|
||||
|
||||
import { oops } from "../../core/Oops";
|
||||
|
||||
/** 游戏自定义参数分组类型 */
|
||||
export enum GameConfigCustomType {
|
||||
/** 开发环境 */
|
||||
Dev = "dev",
|
||||
/** 测试环境 */
|
||||
Test = "test",
|
||||
/** 生产环境 */
|
||||
Prod = "prod",
|
||||
}
|
||||
|
||||
/* 游戏配置解析,对应 resources/config/config.json 配置 */
|
||||
export class GameConfig {
|
||||
/** 客户端版本号配置 */
|
||||
get version(): string {
|
||||
return this._data["config"]["version"];
|
||||
}
|
||||
/** 包名 */
|
||||
get package(): string {
|
||||
return this._data["config"]["package"];
|
||||
}
|
||||
/** 游戏每秒传输帧数 */
|
||||
get frameRate(): number {
|
||||
return this._data.config.frameRate;
|
||||
return this.data.version;
|
||||
}
|
||||
/** 本地存储内容加密 key */
|
||||
get localDataKey(): string {
|
||||
return this._data.config.localDataKey;
|
||||
return this.data.localDataKey;
|
||||
}
|
||||
/** 本地存储内容加密 iv */
|
||||
get localDataIv(): string {
|
||||
return this._data.config.localDataIv;
|
||||
return this.data.localDataIv;
|
||||
}
|
||||
/** 游戏每秒传输帧数 */
|
||||
get frameRate(): number {
|
||||
return this.data.frameRate;
|
||||
}
|
||||
/** 是否开启移动设备安全区域适配 */
|
||||
get mobileSafeArea(): boolean {
|
||||
return this.data.mobileSafeArea || false;
|
||||
}
|
||||
/** 加载界面资源超时提示 */
|
||||
get loadingTimeoutGui(): number {
|
||||
return this.data.loadingTimeoutGui || 1000;
|
||||
}
|
||||
/** 是否显示统计信息 */
|
||||
get stats(): number {
|
||||
return this.data.stats;
|
||||
}
|
||||
/** Http 服务器地址 */
|
||||
get httpServer(): string {
|
||||
return this._data.config.httpServer;
|
||||
return this.data.httpServer;
|
||||
}
|
||||
/** Http 请求超时时间 */
|
||||
get httpTimeout(): number {
|
||||
return this._data.config.httpTimeout;
|
||||
return this.data.httpTimeout;
|
||||
}
|
||||
/** WebSocket 服务器地址 */
|
||||
get webSocketServer(): string {
|
||||
return this.data.webSocketServer;
|
||||
}
|
||||
/** WebSocket 心跳间隔时间(毫秒) */
|
||||
get webSocketHeartTime(): number {
|
||||
return this.data.webSocketHeartTime;
|
||||
}
|
||||
/** WebSocket 指定时间没收到消息就断开连接(毫秒) */
|
||||
get webSocketReceiveTime(): number {
|
||||
return this.data.webSocketReceiveTime;
|
||||
}
|
||||
/** WebSocket 重连间隔时间(毫秒) */
|
||||
get webSocketReconnetTimeOut(): number {
|
||||
return this.data.webSocketReconnetTimeOut;
|
||||
}
|
||||
|
||||
/** 获取当前客户端支持的语言类型 */
|
||||
@@ -55,42 +88,31 @@ export class GameConfig {
|
||||
return this._data.language.default || "zh";
|
||||
}
|
||||
|
||||
/** 是否启用远程资源 */
|
||||
get bundleEnable(): string {
|
||||
return this._data.bundle.enable;
|
||||
}
|
||||
/** 远程资源服务器地址 */
|
||||
get bundleServer(): string {
|
||||
return this._data.bundle.server;
|
||||
}
|
||||
/** 远程资源名 */
|
||||
get bundleDefault(): string {
|
||||
return this._data.bundle.default;
|
||||
}
|
||||
/** 远程所有资源包配置 */
|
||||
get bundlePackages(): string {
|
||||
return this._data.bundle.packages;
|
||||
}
|
||||
|
||||
/** 加载界面资源超时提示 */
|
||||
get loadingTimeoutGui(): number {
|
||||
return this._data.config.loadingTimeoutGui || 1000;
|
||||
}
|
||||
|
||||
/** 是否开启移动设备安全区域适配 */
|
||||
get mobileSafeArea(): boolean {
|
||||
return this._data.config.mobileSafeArea || false;
|
||||
}
|
||||
|
||||
private readonly _data: any = null;
|
||||
private _data: any = null;
|
||||
/** 游戏配置数据 */
|
||||
get data(): any {
|
||||
return this._data;
|
||||
return this._data.config[this._configType];
|
||||
}
|
||||
|
||||
/** 当前游戏配置分组类型 */
|
||||
private _configType: GameConfigCustomType = GameConfigCustomType.Prod;
|
||||
|
||||
constructor(config: any) {
|
||||
this._data = Object.freeze(config.json);
|
||||
|
||||
this.setConfigType(this._data.type);
|
||||
oops.log.logConfig(this._data, "游戏配置");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置游戏参数类型
|
||||
* @param type
|
||||
*/
|
||||
setConfigType(type: GameConfigCustomType) {
|
||||
this._configType = type;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user