所有“修改为‘统一标准

This commit is contained in:
dgflash
2025-12-13 23:32:56 +08:00
parent 86729cd5ee
commit e4241ad217
154 changed files with 2673 additions and 2441 deletions

View File

@@ -4,25 +4,25 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-08-21 15:19:56
*/
import { DEBUG } from "cc/env";
import { EffectSingleCase } from "../libs/animator-effect/EffectSingleCase";
import { ecs } from "../libs/ecs/ECS";
import { ECSRootSystem } from "../libs/ecs/ECSSystem";
import { LanguageManager } from "../libs/gui/language/Language";
import { VM } from "../libs/model-view/ViewModel";
import { Config } from "../module/config/Config";
import { AudioManager } from "./common/audio/AudioManager";
import { MessageManager } from "./common/event/MessageManager";
import { ResLoader } from "./common/loader/ResLoader";
import { Logger } from "./common/log/Logger";
import { RandomManager } from "./common/random/RandomManager";
import { StorageManager } from "./common/storage/StorageManager";
import { TimerManager } from "./common/timer/TimerManager";
import { GameManager } from "./game/GameManager";
import { LayerManager } from "./gui/layer/LayerManager";
import { DEBUG } from 'cc/env';
import { EffectSingleCase } from '../libs/animator-effect/EffectSingleCase';
import { ecs } from '../libs/ecs/ECS';
import type { ECSRootSystem } from '../libs/ecs/ECSSystem';
import { LanguageManager } from '../libs/gui/language/Language';
import { VM } from '../libs/model-view/ViewModel';
import { Config } from '../module/config/Config';
import type { AudioManager } from './common/audio/AudioManager';
import type { MessageManager } from './common/event/MessageManager';
import type { ResLoader } from './common/loader/ResLoader';
import { Logger } from './common/log/Logger';
import { RandomManager } from './common/random/RandomManager';
import type { StorageManager } from './common/storage/StorageManager';
import type { TimerManager } from './common/timer/TimerManager';
import type { GameManager } from './game/GameManager';
import type { LayerManager } from './gui/layer/LayerManager';
/** 框架版本号 */
export var version: string = "2.1.0.20251026";
export var version = '2.1.0.20251026';
/** 框架核心模块访问入口 */
export class oops {
@@ -65,4 +65,4 @@ export class oops {
if (DEBUG) {
//@ts-ignore
window.oops = oops;
}
}

View File

@@ -4,19 +4,20 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-08-28 10:02:57
*/
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";
import { AudioManager } from "./common/audio/AudioManager";
import { EventMessage } from "./common/event/EventMessage";
import { message } from "./common/event/MessageManager";
import { resLoader } from "./common/loader/ResLoader";
import { IStorageSecurity, StorageManager } from "./common/storage/StorageManager";
import { StorageSecuritySimple } from "./common/storage/StorageSecuritySimple";
import { TimerManager } from "./common/timer/TimerManager";
import { GameManager } from "./game/GameManager";
import { LayerManager } from "./gui/layer/LayerManager";
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';
import { AudioManager } from './common/audio/AudioManager';
import { EventMessage } from './common/event/EventMessage';
import { message } from './common/event/MessageManager';
import { resLoader } from './common/loader/ResLoader';
import type { IStorageSecurity } from './common/storage/StorageManager';
import { StorageManager } from './common/storage/StorageManager';
import { StorageSecuritySimple } from './common/storage/StorageSecuritySimple';
import { TimerManager } from './common/timer/TimerManager';
import { GameManager } from './game/GameManager';
import { LayerManager } from './gui/layer/LayerManager';
const { property } = _decorator;
@@ -25,19 +26,19 @@ export class Root extends Component {
/** 游戏层节点 */
@property({
type: Node,
tooltip: "游戏层"
tooltip: '游戏层'
})
game: Node = null!; // 可使用多摄像机自定义二维或三维游戏场景
game: Node = null!; // 可使用多摄像机自定义二维或三维游戏场景
/** 界面层节点 */
@property({
type: Node,
tooltip: "界面层"
tooltip: '界面层'
})
gui: Node = null!;
gui: Node = null!;
/** 框架常驻节点 */
private persist: Node = null!
private persist: Node = null!;
onLoad() {
console.log(`Oops Framework ${version}`);
@@ -50,7 +51,7 @@ export class Root extends Component {
private initModule() {
// 创建持久根节点
this.persist = new Node("OopsFrameworkPersistNode");
this.persist = new Node('OopsFrameworkPersistNode');
director.addPersistRootNode(this.persist);
// Web平台查询参数管理
@@ -68,7 +69,7 @@ export class Root extends Component {
}
private async loadConfig() {
const config_name = "config";
const config_name = 'config';
resources.load(config_name, JsonAsset, (err, config) => {
if (err) {
this.loadConfig().then();
@@ -79,7 +80,7 @@ export class Root extends Component {
// 本地存储模块
oops.storage = new StorageManager();
let security: IStorageSecurity = new StorageSecuritySimple(); // new StorageSecurityCrypto();
const security: IStorageSecurity = new StorageSecuritySimple(); // new StorageSecurityCrypto();
security.key = oops.config.game.localDataKey;
security.iv = oops.config.game.localDataIv;
oops.storage.init(security);
@@ -145,33 +146,33 @@ export class Root extends Component {
// 游戏尺寸修改事件
if (!sys.isMobile) {
screen.on("window-resize", () => {
screen.on('window-resize', () => {
oops.message.dispatchEvent(EventMessage.GAME_RESIZE);
}, this);
screen.on("fullscreen-change", () => {
screen.on('fullscreen-change', () => {
oops.message.dispatchEvent(EventMessage.GAME_FULL_SCREEN);
}, this);
}
screen.on("orientation-change", () => {
screen.on('orientation-change', () => {
oops.message.dispatchEvent(EventMessage.GAME_ORIENTATION);
}, this);
}
private onShow() {
oops.timer.load(); // 处理回到游戏时减去逝去时间
oops.audio.resumeAll(); // 恢复所有暂停的音乐播放
director.resume(); // 恢复暂停场景的游戏逻辑,如果当前场景没有暂停将没任何事情发生
game.resume(); // 恢复游戏主循环。包含:游戏逻辑,渲染,事件处理,背景音乐和所有音效
oops.timer.load(); // 处理回到游戏时减去逝去时间
oops.audio.resumeAll(); // 恢复所有暂停的音乐播放
director.resume(); // 恢复暂停场景的游戏逻辑,如果当前场景没有暂停将没任何事情发生
game.resume(); // 恢复游戏主循环。包含:游戏逻辑,渲染,事件处理,背景音乐和所有音效
oops.message.dispatchEvent(EventMessage.GAME_SHOW);
}
private onHide() {
oops.timer.save(); // 处理切到后台后记录切出时间
oops.audio.pauseAll(); // 暂停所有音乐播放
director.pause(); // 暂停正在运行的场景,该暂停只会停止游戏逻辑执行,但是不会停止渲染和 UI 响应。 如果想要更彻底得暂停游戏,包含渲染,音频和事件
game.pause(); // 暂停游戏主循环。包含游戏逻辑、渲染、输入事件派发Web 和小游戏平台除外)
oops.timer.save(); // 处理切到后台后记录切出时间
oops.audio.pauseAll(); // 暂停所有音乐播放
director.pause(); // 暂停正在运行的场景,该暂停只会停止游戏逻辑执行,但是不会停止渲染和 UI 响应。 如果想要更彻底得暂停游戏,包含渲染,音频和事件
game.pause(); // 暂停游戏主循环。包含游戏逻辑、渲染、输入事件派发Web 和小游戏平台除外)
oops.message.dispatchEvent(EventMessage.GAME_HIDE);
}
}
}

View File

@@ -4,8 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 10:22:36
*/
import { AudioClip, AudioSource, _decorator } from 'cc';
import { IAudioParams } from './IAudio';
import type { AudioClip } from 'cc';
import { AudioSource, _decorator } from 'cc';
import type { IAudioParams } from './IAudio';
const { ccclass } = _decorator;
/** 游戏音效 */
@@ -14,11 +15,11 @@ export class AudioEffect extends AudioSource {
/** 唯一编号 */
key: string = null!;
/** 音效编号 */
aeid: number = -1;
aeid = -1;
/** 音效果资源路径 */
path: string | AudioClip = null!
path: string | AudioClip = null!;
/** 音效参数 */
params: IAudioParams = null!
params: IAudioParams = null!;
/** 背景音乐播放完成回调 */
onComplete: Function | null = null;
@@ -36,4 +37,4 @@ export class AudioEffect extends AudioSource {
this.path = null!;
this.params = null!;
}
}
}

View File

@@ -1,9 +1,9 @@
import { AudioClip, Node, NodePool } from "cc";
import { oops } from "../../Oops";
import { resLoader } from "../loader/ResLoader";
import { AudioEffect } from "./AudioEffect";
import { AudioEffectType } from "./AudioEnum";
import { IAudioData, IAudioParams } from "./IAudio";
import { AudioClip, Node, NodePool } from 'cc';
import { oops } from '../../Oops';
import { resLoader } from '../loader/ResLoader';
import { AudioEffect } from './AudioEffect';
import { AudioEffectType } from './AudioEnum';
import type { IAudioData, IAudioParams } from './IAudio';
/** 音乐效缓冲编号最大值 */
const AE_ID_MAX = 30000;
@@ -21,7 +21,7 @@ export class AudioEffectPool {
/** 外网远程资源记录(地址、音效对象) */
private res_remote: Map<string, AudioClip> = new Map();
private _aeId: number = 0;
private _aeId = 0;
/** 获取请求唯一编号 */
private getAeId() {
if (this._aeId == AE_ID_MAX) this._aeId = 1;
@@ -31,7 +31,7 @@ export class AudioEffectPool {
/**
* 注册音效类型
* @param type
* @param type
*/
register(type: string) {
this.data[type] = { switch: true, volume: 1 };
@@ -43,7 +43,7 @@ export class AudioEffectPool {
* @returns 音效开关
*/
getSwitch(type: string = AudioEffectType.Effect) {
let iad = this.data[type];
const iad = this.data[type];
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
return iad.switch;
}
@@ -53,7 +53,7 @@ export class AudioEffectPool {
* @param value 音效开关
*/
setSwitch(value: boolean, type: string = AudioEffectType.Effect) {
let iad = this.data[type];
const iad = this.data[type];
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
iad.switch = value;
@@ -66,7 +66,7 @@ export class AudioEffectPool {
* @returns 音效音量
*/
getVolume(type: string = AudioEffectType.Effect) {
let iad = this.data[type];
const iad = this.data[type];
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
return iad.volume;
}
@@ -77,18 +77,18 @@ export class AudioEffectPool {
* @param type 音效类型
*/
setVolume(value: number, type: string = AudioEffectType.Effect) {
let iad = this.data[type];
const iad = this.data[type];
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
iad.volume = value;
this.effects.forEach(ac => ac.volume = value);
this.effects.forEach((ac) => ac.volume = value);
}
/**
* 加载与播放音效
* @param path 音效资源地址与音效资源
* @param params 音效附加参数
* @returns
* @returns
*/
async loadAndPlay(path: string | AudioClip, params?: IAudioParams): Promise<AudioEffect> {
return new Promise(async (resolve, reject) => {
@@ -98,7 +98,7 @@ export class AudioEffectPool {
bundle: resLoader.defaultBundleName,
loop: false,
destroy: false
}
};
}
else {
if (params.type == null) params.type = AudioEffectType.Effect;
@@ -107,7 +107,7 @@ export class AudioEffectPool {
if (params.type == null) params.destroy = false;
}
let iad = this.data[params.type!];
const iad = this.data[params.type!];
if (iad == null) console.error(`类型为【${params.type!}】的音效配置不存在`);
if (!iad.switch) {
@@ -117,7 +117,7 @@ export class AudioEffectPool {
if (params.volume == null) params.volume = iad.volume;
let bundle = params.bundle!;
const bundle = params.bundle!;
let key: string = null!;
let clip: AudioClip | undefined;
// 通过预制自动加载的音效资源(音效内存跟随预制体的内存一并释放)
@@ -126,7 +126,7 @@ export class AudioEffectPool {
clip = path;
}
// 非引擎管理的远程资源加载
else if (path.indexOf("http") == 0) {
else if (path.indexOf('http') == 0) {
key = `${params.type}_${path}`;
clip = this.res_remote.get(path);
if (clip == null) {
@@ -160,14 +160,14 @@ export class AudioEffectPool {
}
// 获取音效果播放器播放音乐
let aeid: number = -1;
let aeid = -1;
let ae: AudioEffect;
let node: Node = null!;
if (this.pool.size() == 0) {
aeid = this.getAeId();
key += "_" + aeid;
key += '_' + aeid;
node = new Node("AudioEffect");
node = new Node('AudioEffect');
ae = node.addComponent(AudioEffect);
ae.key = key;
ae.aeid = aeid;
@@ -217,7 +217,7 @@ export class AudioEffectPool {
* @param ae loadAndPlay 方法返回的音效播放器对象
*/
put(ae: AudioEffect) {
let effect = this.effects.get(ae.key);
const effect = this.effects.get(ae.key);
if (effect && effect.clip) {
effect.reset();
@@ -228,7 +228,7 @@ export class AudioEffectPool {
/** 停止播放所有音效 */
stop() {
this.effects.forEach(ae => {
this.effects.forEach((ae) => {
ae.stop();
this.onAudioEffectPlayComplete(ae);
});
@@ -237,12 +237,12 @@ export class AudioEffectPool {
/** 恢复所有音效 */
play() {
this.effects.forEach(ae => ae.play());
this.effects.forEach((ae) => ae.play());
}
/** 暂停所有音效 */
pause() {
this.effects.forEach(ae => {
this.effects.forEach((ae) => {
ae.pause();
this.onAudioEffectPlayComplete(ae);
});
@@ -266,14 +266,14 @@ export class AudioEffectPool {
this.pool.clear();
// 释放正在播放的音效对象
this.effects.forEach(ae => ae.node.destroy());
this.effects.forEach((ae) => ae.node.destroy());
this.effects.clear();
}
/** 释放各个资源包中的音效资源 */
releaseRes() {
this.res_project.forEach((paths: string[], bundleName: string) => {
paths.forEach(path => resLoader.release(path, bundleName));
paths.forEach((path) => resLoader.release(path, bundleName));
});
}
@@ -284,4 +284,4 @@ export class AudioEffectPool {
});
this.res_remote.clear();
}
}
}

View File

@@ -1,7 +1,7 @@
/** 音乐音效默认类型 */
export enum AudioEffectType {
/** 背景音乐 */
Music = "music",
Music = 'music',
/** 音乐音效 */
Effect = "effect",
Effect = 'effect',
}

View File

@@ -1,11 +1,12 @@
import { AudioClip, Component } from "cc";
import { oops } from "../../Oops";
import { AudioEffect } from "./AudioEffect";
import { AudioEffectPool } from "./AudioEffectPool";
import { AudioEffectType } from "./AudioEnum";
import { AudioMusic } from "./AudioMusic";
import { IAudioData, IAudioParams } from "./IAudio";
import { GameStorage } from "db://oops-framework/module/common/GameStorage";
import type { AudioClip } from 'cc';
import { Component } from 'cc';
import { oops } from '../../Oops';
import type { AudioEffect } from './AudioEffect';
import { AudioEffectPool } from './AudioEffectPool';
import { AudioEffectType } from './AudioEnum';
import { AudioMusic } from './AudioMusic';
import type { IAudioData, IAudioParams } from './IAudio';
import { GameStorage } from 'db://oops-framework/module/common/GameStorage';
/**
* 音频管理
@@ -98,21 +99,21 @@ export class AudioManager extends Component {
if (typeof value === 'string') {
this.data[value] = { switch: true, volume: 1 };
switch (value) {
case AudioEffectType.Music:
//@ts-ignore
this.music.data = this.data;
this.music.setSwitch(true);
this.music.setVolume(1);
break;
default:
//@ts-ignore
this.effect.data = this.data;
this.effect.setSwitch(true, value);
this.effect.setVolume(1, value);
break;
case AudioEffectType.Music:
//@ts-ignore
this.music.data = this.data;
this.music.setSwitch(true);
this.music.setVolume(1);
break;
default:
//@ts-ignore
this.effect.data = this.data;
this.effect.setSwitch(true, value);
this.effect.setVolume(1, value);
break;
}
}
}
this.save();
}
}
}

View File

@@ -8,10 +8,10 @@ import { AudioClip, Node } from 'cc';
import { resLoader } from '../loader/ResLoader';
import { AudioEffect } from './AudioEffect';
import { AudioEffectType } from './AudioEnum';
import { IAudioData, IAudioParams } from './IAudio';
import type { IAudioData, IAudioParams } from './IAudio';
/**
* 背景音乐
/**
* 背景音乐
* 1、播放一个新背景音乐时先加载音乐资源然后停止正在播放的背景资源同时释放当前背景音乐资源最后播放新的背景音乐
* 2、背景音乐循环播放时不会触发播放完成事件
*/
@@ -19,8 +19,8 @@ export class AudioMusic extends Node {
/** 音效配置数据 */
private data: { [node: string]: IAudioData } = null!;
private _progress: number = 0;
private _isLoading: boolean = false;
private _progress = 0;
private _isLoading = false;
private _nextPath: string = null!;
private _nextParams: IAudioParams = null!;
private _ae: AudioEffect = null!;
@@ -75,7 +75,7 @@ export class AudioMusic extends Node {
constructor() {
super();
this.name = "AudioMusic";
this.name = 'AudioMusic';
this._ae = this.addComponent(AudioEffect);
this._ae.onComplete = this.onAudioEffectPlayComplete.bind(this);
}
@@ -91,7 +91,7 @@ export class AudioMusic extends Node {
* @param params 背景音乐资源播放参数
*/
async loadAndPlay(path: string, params?: IAudioParams) {
if (!this.getSwitch()) return; // 禁止播放音乐
if (!this.getSwitch()) return; // 禁止播放音乐
// 下一个加载的背景音乐资源
if (this._isLoading) {
@@ -106,19 +106,19 @@ export class AudioMusic extends Node {
bundle: resLoader.defaultBundleName,
loop: true,
volume: this.getVolume()
}
};
}
else {
if (params.type == null) params.type = AudioEffectType.Music;
if (params.bundle == null) params.bundle = resLoader.defaultBundleName;
if (params.loop == null) params.loop = true;
if (params.volume == null) params.volume = this.getVolume()
if (params.volume == null) params.volume = this.getVolume();
}
this._isLoading = true;
let clip: AudioClip = null!;
if (path.indexOf("http") == 0) {
if (path.indexOf('http') == 0) {
const extension = path.split('.').pop();
clip = await resLoader.loadRemote<AudioClip>(path, { ext: `.${extension}` });
}
@@ -176,4 +176,4 @@ export class AudioMusic extends Node {
this._ae.clip = null;
}
}
}
}

View File

@@ -18,4 +18,4 @@ export interface IAudioData {
switch: boolean;
/** 音量 */
volume: number;
}
}

View File

@@ -4,8 +4,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 10:57:01
*/
import { ListenerFunc } from "./EventMessage";
import { MessageEventData } from "./MessageManager";
import type { ListenerFunc } from './EventMessage';
import { MessageEventData } from './MessageManager';
/* 事件对象基类,继承该类将拥有发送和接送事件的能力 */
export class EventDispatcher {
@@ -34,8 +34,8 @@ export class EventDispatcher {
}
}
/**
* 触发全局事件
/**
* 触发全局事件
* @param event 事件名
* @param args 事件参数
*/
@@ -55,4 +55,4 @@ export class EventDispatcher {
}
this._msg = null;
}
}
}

View File

@@ -15,13 +15,13 @@ export type ListenerFunc = (event: string, ...args: any) => void
/** 框架内部全局事件 */
export enum EventMessage {
/** 游戏从后台进入事件 */
GAME_SHOW = "onGameShow",
GAME_SHOW = 'onGameShow',
/** 游戏切到后台事件 */
GAME_HIDE = "onGameHide",
GAME_HIDE = 'onGameHide',
/** 游戏画笔尺寸变化事件 */
GAME_RESIZE = "onGameResize",
GAME_RESIZE = 'onGameResize',
/** 游戏全屏事件 */
GAME_FULL_SCREEN = "onGameFullScreen",
GAME_FULL_SCREEN = 'onGameFullScreen',
/** 游戏旋转屏幕事件 */
GAME_ORIENTATION = "onGameOrientation"
GAME_ORIENTATION = 'onGameOrientation'
}

View File

@@ -1,10 +1,10 @@
import { log, warn } from "cc";
import { ListenerFunc } from "./EventMessage";
import { log, warn } from 'cc';
import type { ListenerFunc } from './EventMessage';
class EventData {
public event!: string;
public listener!: ListenerFunc;
public object: any;
event!: string;
listener!: ListenerFunc;
object: any;
}
/** 批量注册、移除全局事件对象 */
@@ -23,7 +23,7 @@ export class MessageEventData {
eds = [];
this.events.set(event, eds);
}
let ed: EventData = new EventData();
const ed: EventData = new EventData();
ed.event = event;
ed.listener = listener;
ed.object = object;
@@ -37,17 +37,17 @@ export class MessageEventData {
* @param event 事件名
*/
off(event: string) {
let eds = this.events.get(event);
const eds = this.events.get(event);
if (!eds) return;
for (let eb of eds) {
for (const eb of eds) {
message.off(event, eb.listener, eb.object);
}
this.events.delete(event);
}
/**
* 触发全局事件
/**
* 触发全局事件
* @param event 事件名
* @param args 事件参数
*/
@@ -58,28 +58,28 @@ export class MessageEventData {
/** 清除所有的全局事件监听 */
clear() {
const keys = Array.from(this.events.keys());
for (let event of keys) {
this.off(event)
for (const event of keys) {
this.off(event);
}
}
}
/**
/**
* 全局消息管理
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037894&doc_id=2873565
* @example
* @example
// 注册持续监听的全局事件
export class RoleViewComp extends Component{
onLoad(){
// 监听全局事件
oops.message.on(GameEvent.GameServerConnected, this.onHandler, this);
}
protected onDestroy() {
// 对象释放时取消注册的全局事件
oops.message.off(GameEvent.GameServerConnected, this.onHandler, this);
}
private onHandler(event: string, args: any) {
switch (event) {
case GameEvent.GameServerConnected:
@@ -95,7 +95,7 @@ export class RoleViewComp extends Component{
// 监听一次事件,事件响应后,该监听自动移除
oops.message.once(GameEvent.GameServerConnected, this.onHandler, this);
}
private onHandler(event: string, args: any) {
switch (event) {
case GameEvent.GameServerConnected:
@@ -126,16 +126,16 @@ export class MessageManager {
this.events.set(event, eds);
}
let length = eds.length;
const length = eds.length;
for (let i = 0; i < length; i++) {
let bin = eds[i];
const bin = eds[i];
if (bin.listener == listener && bin.object == object) {
warn(`名为【${event}】的事件重复注册侦听器`);
}
}
let data: EventData = new EventData();
const data: EventData = new EventData();
data.event = event;
data.listener = listener;
data.object = object;
@@ -153,7 +153,7 @@ export class MessageManager {
this.off(event, _listener, object);
_listener = null;
listener.call(object, $event, $args);
}
};
this.on(event, _listener, object);
}
@@ -164,16 +164,16 @@ export class MessageManager {
* @param object 侦听函数绑定的作用域对象
*/
off(event: string, listener: Function, object: object) {
let eds = this.events.get(event);
const eds = this.events.get(event);
if (!eds) {
log(`名为【${event}】的事件不存在`);
return;
}
let length = eds.length;
const length = eds.length;
for (let i = 0; i < length; i++) {
let bin: EventData = eds[i];
const bin: EventData = eds[i];
if (bin.listener == listener && bin.object == object) {
eds.splice(i, 1);
break;
@@ -185,16 +185,16 @@ export class MessageManager {
}
}
/**
* 触发全局事件
/**
* 触发全局事件
* @param event 事件名
* @param args 事件参数
*/
dispatchEvent(event: string, ...args: any) {
let list = this.events.get(event);
const list = this.events.get(event);
if (list != null) {
let eds: Array<EventData> = list.concat();
let length = eds.length;
const eds: Array<EventData> = list.concat();
const length = eds.length;
for (let i = 0; i < length; i++) {
const ed = eds[i];
ed.listener.call(ed.object, event, ...args);
@@ -202,7 +202,7 @@ export class MessageManager {
}
}
/**
/**
* 触发全局事件,支持同步与异步处理
* @param event 事件名
* @param args 事件参数
@@ -218,10 +218,10 @@ export class MessageManager {
*/
dispatchEventAsync(event: string, ...args: any): Promise<void> {
return new Promise(async (resolve, reject) => {
let list = this.events.get(event);
const list = this.events.get(event);
if (list != null) {
let eds: Array<EventData> = list.concat();
let length = eds.length;
const eds: Array<EventData> = list.concat();
const length = eds.length;
for (let i = 0; i < length; i++) {
const ed = eds[i];
await Promise.resolve(ed.listener.call(ed.object, event, ...args));
@@ -232,4 +232,4 @@ export class MessageManager {
}
}
export const message = new MessageManager();
export const message = new MessageManager();

View File

@@ -1,4 +1,5 @@
import { __private, AnimationClip, Asset, AssetManager, assetManager, AudioClip, Font, ImageAsset, js, JsonAsset, Material, Mesh, Prefab, resources, sp, SpriteFrame, Texture2D } from "cc";
import type { __private, AssetManager } from 'cc';
import { AnimationClip, Asset, assetManager, AudioClip, Font, ImageAsset, js, JsonAsset, Material, Mesh, Prefab, resources, sp, SpriteFrame, Texture2D } from 'cc';
export type AssetType<T = Asset> = __private.__types_globals__Constructor<T> | null;
export type Paths = string | string[];
@@ -23,18 +24,18 @@ interface ILoadResArgs<T extends Asset> {
preload?: boolean;
}
/**
/**
* 游戏资源管理
* 1、加载默认resources文件夹中资源
* 2、加载默认bundle远程资源
* 3、主动传递bundle名时优先加载传递bundle名资源包中的资源
*
*
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037901&doc_id=2873565
*/
export class ResLoader {
//#region 资源配置数据
/** 全局默认加载的资源包名 */
defaultBundleName: string = "resources";
defaultBundleName = 'resources';
/** 下载时的最大并发数 - 项目设置 -> 项目数据 -> 资源下载并发数设置默认值初始值为15 */
get maxConcurrency(): number {
@@ -79,10 +80,10 @@ export class ResLoader {
var data = await oops.res.loadRemote<ImageAsset>(this.url, opt);
const texture = new Texture2D();
texture.image = data;
const spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
var sprite = this.sprite.addComponent(Sprite);
sprite.spriteFrame = spriteFrame;
*/
@@ -133,7 +134,7 @@ export class ResLoader {
* @param bundleName 资源地址
*/
removeBundle(bundleName: string) {
let bundle = assetManager.bundles.get(bundleName);
const bundle = assetManager.bundles.get(bundleName);
if (bundle) {
bundle.releaseAll();
assetManager.removeBundle(bundle);
@@ -165,16 +166,16 @@ export class ResLoader {
onProgress?: ProgressCallback
) {
return new Promise((resolve, reject) => {
let onComplete = (err: Error | null, data: AssetManager.RequestItem) => {
const onComplete = (err: Error | null, data: AssetManager.RequestItem) => {
if (err) {
resolve(null!);
return;
}
resolve(data);
}
};
let args: ILoadResArgs<Asset> | null = null;
if (typeof paths === "string" || paths instanceof Array) {
if (typeof paths === 'string' || paths instanceof Array) {
args = this.parseLoadResArgs(paths, type, onProgress, onComplete);
args.bundle = bundleName;
}
@@ -211,7 +212,7 @@ export class ResLoader {
onComplete?: CompleteCallback,
) {
let args: ILoadResArgs<T> | null = null;
if (typeof dir === "string") {
if (typeof dir === 'string') {
args = this.parseLoadResArgs(dir, type, onProgress, onComplete);
args.bundle = bundleName;
}
@@ -236,16 +237,16 @@ export class ResLoader {
*/
load<T extends Asset>(bundleName: string, paths: Paths | AssetType<T>, type?: AssetType<T>) {
return new Promise<T>((resolve, reject) => {
let onComplete = (err: Error | null, data: T) => {
const onComplete = (err: Error | null, data: T) => {
if (err) {
resolve(null!);
return;
}
resolve(data);
}
};
let args: ILoadResArgs<T> | null = null;
if (typeof paths === "string" || paths instanceof Array) {
if (typeof paths === 'string' || paths instanceof Array) {
args = this.parseLoadResArgs(paths, type, onComplete);
args.bundle = bundleName;
}
@@ -266,7 +267,7 @@ export class ResLoader {
*/
loadAny<T extends Asset>(bundleName: string | string[], paths: string[] | ProgressCallback, onProgress?: ProgressCallback | CompleteCallback, onComplete?: CompleteCallback): void {
let args: ILoadResArgs<T> | null = null;
if (typeof bundleName === "string" && paths instanceof Array) {
if (typeof bundleName === 'string' && paths instanceof Array) {
args = this.parseLoadResArgs(paths, onProgress, onComplete);
args.bundle = bundleName;
}
@@ -289,7 +290,7 @@ export class ResLoader {
var onProgressCallback = (finished: number, total: number, item: any) => {
console.log("资源加载进度", finished, total);
}
// 加载完成事件
var onCompleteCallback = () => {
console.log("资源加载完成");
@@ -312,7 +313,7 @@ export class ResLoader {
onComplete?: CompleteCallback,
) {
let args: ILoadResArgs<T> | null = null;
if (typeof dir === "string") {
if (typeof dir === 'string') {
args = this.parseLoadResArgs(dir, type, onProgress, onComplete);
args.bundle = bundleName;
}
@@ -351,14 +352,14 @@ export class ResLoader {
const bundle: AssetManager.Bundle | null = assetManager.getBundle(bundleName);
if (bundle) {
var infos = bundle.getDirWithPath(path);
const infos = bundle.getDirWithPath(path);
if (infos) {
infos.map((info) => {
this.releasePrefabtDepsRecursively(info.uuid);
});
}
if (path == "" && bundleName != "resources") {
if (path == '' && bundleName != 'resources') {
assetManager.removeBundle(bundle);
}
}
@@ -368,11 +369,11 @@ export class ResLoader {
* 获取资源路径
* @param bundleName 资源包名
* @param uuid 资源唯一编号
* @returns
* @returns
*/
getAssetPath(bundleName: string, uuid: string): string {
let b = this.getBundle(bundleName)!;
let info = b.getAssetInfo(uuid)!;
const b = this.getBundle(bundleName)!;
const info = b.getAssetInfo(uuid)!;
//@ts-ignore
return info.path;
}
@@ -406,13 +407,13 @@ export class ResLoader {
* @param bundleName 远程资源包名
*/
get<T extends Asset>(path: string, type?: AssetType<T>, bundleName: string = this.defaultBundleName): T | null {
var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName)!;
const bundle: AssetManager.Bundle = assetManager.getBundle(bundleName)!;
return bundle.get(path, type);
}
//#endregion
private parseLoadResArgs<T extends Asset>(paths: Paths, type?: AssetType<T> | ProgressCallback | CompleteCallback, onProgress?: AssetType<T> | ProgressCallback | CompleteCallback, onComplete?: ProgressCallback | CompleteCallback) {
let pathsOut: any = paths;
const pathsOut: any = paths;
let typeOut: any = type;
let onProgressOut: any = onProgress;
let onCompleteOut: any = onComplete;
@@ -476,53 +477,53 @@ export class ResLoader {
dump() {
assetManager.assets.forEach((value: Asset, key: string) => {
console.log(`引用数量:${value.refCount}`, assetManager.assets.get(key));
})
});
console.log(`当前资源总数:${assetManager.assets.count}`);
}
private debugLogReleasedAsset(bundleName: string, asset: Asset) {
if (asset.refCount == 0) {
let path = this.getAssetPath(bundleName, asset.uuid);
let content: string = "";
const path = this.getAssetPath(bundleName, asset.uuid);
let content = '';
if (asset instanceof JsonAsset) {
content = "【释放资源】Json【路径】" + path;
content = '【释放资源】Json【路径】' + path;
}
else if (asset instanceof Prefab) {
content = "【释放资源】Prefab【路径】" + path;
content = '【释放资源】Prefab【路径】' + path;
}
else if (asset instanceof SpriteFrame) {
content = "【释放资源】SpriteFrame【路径】" + path;
content = '【释放资源】SpriteFrame【路径】' + path;
}
else if (asset instanceof Texture2D) {
content = "【释放资源】Texture2D【路径】" + path;
content = '【释放资源】Texture2D【路径】' + path;
}
else if (asset instanceof ImageAsset) {
content = "【释放资源】ImageAsset【路径】" + path;
content = '【释放资源】ImageAsset【路径】' + path;
}
else if (asset instanceof AudioClip) {
content = "【释放资源】AudioClip【路径】" + path;
content = '【释放资源】AudioClip【路径】' + path;
}
else if (asset instanceof AnimationClip) {
content = "【释放资源】AnimationClip【路径】" + path;
content = '【释放资源】AnimationClip【路径】' + path;
}
else if (asset instanceof Font) {
content = "【释放资源】Font【路径】" + path;
content = '【释放资源】Font【路径】' + path;
}
else if (asset instanceof Material) {
content = "【释放资源】Material【路径】" + path;
content = '【释放资源】Material【路径】' + path;
}
else if (asset instanceof Mesh) {
content = "【释放资源】Mesh【路径】" + path;
content = '【释放资源】Mesh【路径】' + path;
}
else if (asset instanceof sp.SkeletonData) {
content = "【释放资源】Spine【路径】" + path;
content = '【释放资源】Spine【路径】' + path;
}
else {
content = "【释放资源】未知【路径】" + path;
content = '【释放资源】未知【路径】' + path;
}
console.log(content);
}
}
}
export const resLoader = new ResLoader();
export const resLoader = new ResLoader();

View File

@@ -1,7 +1,7 @@
import { BufferAsset, SpriteFrame, Texture2D } from "cc";
import { resLoader } from "./ResLoader";
import { BufferAsset, SpriteFrame, Texture2D } from 'cc';
import { resLoader } from './ResLoader';
/**
/**
* 加载Zip资源
* 注:
* 1. 使用此功能需要教程项目中项目资源目录libs/jszip目录拷贝到自己的项目中
@@ -13,13 +13,13 @@ export class ZipLoader {
/**
* 加载ZIP资源包
* @param url
* @returns
* @param url
* @returns
*/
static load(url: string): Promise<JSZip> {
return new Promise(async (resolve, reject) => {
let asset = await resLoader.load(url, BufferAsset);
var zip = await JSZip.loadAsync(asset.buffer());
const asset = await resLoader.load(url, BufferAsset);
const zip = await JSZip.loadAsync(asset.buffer());
this.zips.set(url, zip);
resolve(zip);
});
@@ -27,34 +27,34 @@ export class ZipLoader {
static getJson(zipName: string, path: string): Promise<any> {
return new Promise(async (resolve, reject) => {
var zip = this.zips.get(zipName);
const 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"));
const file = zip.file(path);
const 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);
const 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();
const file = zip.file(path);
const buf = await file.async('base64');
const img = new Image();
img.src = 'data:image/png;base64,' + buf;
img.onload = () => {
var texture = new Texture2D();
const texture = new Texture2D();
texture.reset({
width: img.width,
height: img.height
@@ -62,11 +62,11 @@ export class ZipLoader {
texture.uploadData(img, 0, 0);
texture.loaded = true;
var sf = new SpriteFrame();
const sf = new SpriteFrame();
sf.texture = texture;
resolve(sf);
}
};
});
}
@@ -81,4 +81,4 @@ export class ZipLoader {
});
}
}
}
}

View File

@@ -1,4 +1,4 @@
import { log } from "cc";
import { log } from 'cc';
/** 日志类型 */
export enum LogType {
@@ -16,21 +16,21 @@ export enum LogType {
Trace = 32,
}
var names = {
"1": "网络日志",
"2": "数据日志",
"4": "业务日志",
"8": "视图日志",
"16": "配置日志",
"32": "标准日志",
}
const names = {
'1': '网络日志',
'2': '数据日志',
'4': '业务日志',
'8': '视图日志',
'16': '配置日志',
'32': '标准日志',
};
export interface ILoggerConsole {
trace(content: string, color: string): void;
}
/**
* 日志管理
/**
* 日志管理
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037904&doc_id=2873565
* @example
oops.log.trace("默认标准日志");
@@ -50,7 +50,7 @@ export class Logger {
return this._instance;
}
private tags: number = 0;
private tags = 0;
private lc: ILoggerConsole = null!;
/** 设置界面日志控制台 */
@@ -68,7 +68,7 @@ export class Logger {
LogType.Trace;
}
/**
/**
* 设置显示的日志类型,默认值为不显示任何类型日志
* @example
oops.log.setTags(LogType.View|LogType.Business)
@@ -89,7 +89,7 @@ oops.log.start();
...
oops.log.end();
*/
start(describe: string = "Time"): void {
start(describe = 'Time'): void {
console.time(describe);
}
@@ -103,7 +103,7 @@ oops.log.start();
...
oops.log.end();
*/
end(describe: string = "Time"): void {
end(describe = 'Time'): void {
console.timeEnd(describe);
}
@@ -126,7 +126,7 @@ oops.log.table(object);
* 打印标准日志
* @param msg 日志消息
*/
trace(msg: any, color: string = "#000000ff") {
trace(msg: any, color = '#000000ff') {
this.print(LogType.Trace, msg, color);
}
@@ -173,27 +173,27 @@ oops.log.table(object);
// 橙色
private orange(tag: LogType, msg: any, describe?: string) {
this.print(tag, msg, "#ee7700", describe)
this.print(tag, msg, '#ee7700', describe);
}
// 紫色
private violet(tag: LogType, msg: any, describe?: string) {
this.print(tag, msg, "#800080", describe)
this.print(tag, msg, '#800080', describe);
}
// 蓝色
private blue(tag: LogType, msg: any, describe?: string) {
this.print(tag, msg, "#3a5fcd", describe)
this.print(tag, msg, '#3a5fcd', describe);
}
// 绿色
private green(tag: LogType, msg: any, describe?: string) {
this.print(tag, msg, "#008000", describe)
this.print(tag, msg, '#008000', describe);
}
// 灰色
private gray(tag: LogType, msg: any, describe?: string) {
this.print(tag, msg, "#808080", describe)
this.print(tag, msg, '#808080', describe);
}
private isOpen(tag: LogType): boolean {
@@ -216,12 +216,12 @@ oops.log.table(object);
const type = names[tag];
if (this.lc == null) {
const backLog = console.log || log;
color = "color:" + color + ";";
color = 'color:' + color + ';';
if (describe) {
backLog.call(null, "%c%s%s%s:%s%o", color, this.getDateString(), '[' + type + ']', this.stack(5), describe, msg);
backLog.call(null, '%c%s%s%s:%s%o', color, this.getDateString(), '[' + type + ']', this.stack(5), describe, msg);
}
else {
backLog.call(null, "%c%s%s%s:%o", color, this.getDateString(), '[' + type + ']', this.stack(5), msg);
backLog.call(null, '%c%s%s%s:%o', color, this.getDateString(), '[' + type + ']', this.stack(5), msg);
}
}
else {
@@ -231,11 +231,11 @@ oops.log.table(object);
private stack(index: number): string {
const e = new Error();
const lines = e.stack!.split("\n");
const lines = e.stack!.split('\n');
const result: Array<any> = [];
lines.forEach((line) => {
line = line.substring(7);
var lineBreak = line.split(" ");
const lineBreak = line.split(' ');
if (lineBreak.length < 2) {
result.push(lineBreak[0]);
}
@@ -248,16 +248,16 @@ oops.log.table(object);
let splitList: Array<string> = [];
if (index < result.length - 1) {
let value: string;
for (let a in result[index]) {
splitList = a.split(".");
for (const a in result[index]) {
splitList = a.split('.');
if (splitList.length == 2) {
list = splitList.concat();
}
else {
value = result[index][a];
const start = value!.lastIndexOf("/");
const end = value!.lastIndexOf(".");
const start = value!.lastIndexOf('/');
const end = value!.lastIndexOf('.');
if (start > -1 && end > -1) {
const r = value!.substring(start + 1, end);
list.push(r);
@@ -270,29 +270,29 @@ oops.log.table(object);
}
if (list.length == 1) {
return "[" + list[0] + ".ts]";
return '[' + list[0] + '.ts]';
}
else if (list.length == 2) {
return "[" + list[0] + ".ts->" + list[1] + "]";
return '[' + list[0] + '.ts->' + list[1] + ']';
}
return "";
return '';
}
private getDateString(): string {
let d = new Date();
const d = new Date();
let str = d.getHours().toString();
let timeStr = "";
timeStr += (str.length == 1 ? "0" + str : str) + ":";
let timeStr = '';
timeStr += (str.length == 1 ? '0' + str : str) + ':';
str = d.getMinutes().toString();
timeStr += (str.length == 1 ? "0" + str : str) + ":";
timeStr += (str.length == 1 ? '0' + str : str) + ':';
str = d.getSeconds().toString();
timeStr += (str.length == 1 ? "0" + str : str) + ":";
timeStr += (str.length == 1 ? '0' + str : str) + ':';
str = d.getMilliseconds().toString();
if (str.length == 1) str = "00" + str;
if (str.length == 2) str = "0" + str;
if (str.length == 1) str = '00' + str;
if (str.length == 2) str = '0' + str;
timeStr += str;
timeStr = "[" + timeStr + "]";
timeStr = '[' + timeStr + ']';
return timeStr;
}
}
}

View File

@@ -1,7 +1,7 @@
/** 引擎 utils.ts 中有一些基础数学方法 */
/**
* 随机管理
/**
* 随机管理
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037911&doc_id=2873565
*/
export class RandomManager {
@@ -31,7 +31,7 @@ export class RandomManager {
* @param min 最小值
* @param max 最大值
*/
getRandomFloat(min: number = 0, max: number = 1): number {
getRandomFloat(min = 0, max = 1): number {
return this.getRandom() * (max - min) + min;
}
@@ -43,7 +43,7 @@ export class RandomManager {
* @example
var min = 1;
var max = 10;
// [min,max) 得到一个两数之间的随机整数,这个值不小于min如果min不是整数的话得到一个向上取整的 min并且小于但不等于max
// [min,max) 得到一个两数之间的随机整数,这个值不小于min如果min不是整数的话得到一个向上取整的 min并且小于但不等于max
RandomManager.instance.getRandomInt(min, max, 1);
// [min,max] 得到一个两数之间的随机整数,包括两个数在内,这个值比min大如果min不是整数那就不小于比min大的整数但小于但不等于max
@@ -52,16 +52,16 @@ export class RandomManager {
// (min,max) 得到一个两数之间的随机整数
RandomManager.instance.getRandomInt(min, max, 3);
*/
getRandomInt(min: number, max: number, type: number = 2): number {
getRandomInt(min: number, max: number, type = 2): number {
min = Math.ceil(min);
max = Math.floor(max);
switch (type) {
case 1: // [min,max) 得到一个两数之间的随机整数,这个值不小于min如果min不是整数的话得到一个向上取整的 min并且小于但不等于max
return Math.floor(this.getRandom() * (max - min)) + min;
case 2: // [min,max] 得到一个两数之间的随机整数,包括两个数在内,这个值比min大如果min不是整数那就不小于比min大的整数但小于但不等于max
return Math.floor(this.getRandom() * (max - min + 1)) + min;
case 3: // (min,max) 得到一个两数之间的随机整数
return Math.floor(this.getRandom() * (max - min - 1)) + min + 1;
case 1: // [min,max) 得到一个两数之间的随机整数,这个值不小于min如果min不是整数的话得到一个向上取整的 min并且小于但不等于max
return Math.floor(this.getRandom() * (max - min)) + min;
case 2: // [min,max] 得到一个两数之间的随机整数,包括两个数在内,这个值比min大如果min不是整数那就不小于比min大的整数但小于但不等于max
return Math.floor(this.getRandom() * (max - min + 1)) + min;
case 3: // (min,max) 得到一个两数之间的随机整数
return Math.floor(this.getRandom() * (max - min - 1)) + min + 1;
}
return 0;
}
@@ -76,9 +76,9 @@ export class RandomManager {
console.log("随机的数字", a);
*/
getRandomByMinMaxList(min: number, max: number, n: number): Array<number> {
var result: Array<number> = [];
const result: Array<number> = [];
for (let i = 0; i < n; i++) {
result.push(this.getRandomInt(min, max))
result.push(this.getRandomInt(min, max));
}
return result;
}
@@ -94,10 +94,10 @@ export class RandomManager {
console.log("随机的对象", r);
*/
getRandomByObjectList<T>(objects: Array<T>, n: number): Array<T> {
var temp: Array<T> = objects.slice();
var result: Array<T> = [];
const temp: Array<T> = objects.slice();
const result: Array<T> = [];
for (let i = 0; i < n; i++) {
let index = this.getRandomInt(0, temp.length, 1);
const index = this.getRandomInt(0, temp.length, 1);
result.push(temp.splice(index, 1)[0]);
}
return result;
@@ -127,4 +127,4 @@ export class RandomManager {
}
return result;
}
}
}

View File

@@ -1,4 +1,4 @@
import { RandomManager } from "./RandomManager";
import { RandomManager } from './RandomManager';
/** 伪随机 */
export class SeedRandom {
@@ -20,4 +20,4 @@ export class SeedRandom {
this.rm = null!;
this.sr = null!;
}
}
}

View File

@@ -1,5 +1,5 @@
import { sys } from "cc";
import { PREVIEW } from "cc/env";
import { sys } from 'cc';
import { PREVIEW } from 'cc/env';
export interface IStorageSecurity {
key: string;
@@ -10,8 +10,8 @@ export interface IStorageSecurity {
encryptKey(str: string): string;
}
/**
* 本地存储
/**
* 本地存储
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037957&doc_id=2873565
*/
export class StorageManager {
@@ -31,7 +31,7 @@ export class StorageManager {
/**
* 设置用户唯一标识
* @param id
* @param id
*/
setUser(id: string) {
this.id = id;
@@ -41,25 +41,25 @@ export class StorageManager {
* 存储本地数据
* @param key 存储key
* @param value 存储值
* @returns
* @returns
*/
set(key: string, value: any) {
let keywords = this.getKey(key);
if (null == key) {
console.error("存储的key不能为空");
console.error('存储的key不能为空');
return;
}
if (this.encrypted) {
keywords = this.iss.encryptKey(keywords);
}
if (null == value) {
console.warn("存储的值为空,则直接移除该存储");
console.warn('存储的值为空,则直接移除该存储');
this.remove(key);
return;
}
if (typeof value === 'function') {
console.error("储存的值不能为方法");
console.error('储存的值不能为方法');
return;
}
if (typeof value === 'object') {
@@ -72,7 +72,7 @@ export class StorageManager {
}
}
else if (typeof value === 'number') {
value = value + "";
value = value + '';
}
else if (typeof value === 'boolean') {
value = String(value);
@@ -88,11 +88,11 @@ export class StorageManager {
* 获取指定关键字的数据
* @param key 获取的关键字
* @param defaultValue 获取的默认值
* @returns
* @returns
*/
get(key: string, defaultValue: any = ""): string {
get(key: string, defaultValue: any = ''): string {
if (null == key) {
console.error("存储的key不能为空");
console.error('存储的key不能为空');
return null!;
}
@@ -114,9 +114,9 @@ export class StorageManager {
}
/** 获取指定关键字的数值 */
getNumber(key: string, defaultValue: number = 0): number {
getNumber(key: string, defaultValue = 0): number {
const r = this.get(key);
if (r == "0") {
if (r == '0') {
return Number(r);
}
return Number(r) || defaultValue;
@@ -137,11 +137,11 @@ export class StorageManager {
/**
* 删除指定关键字的数据
* @param key 需要移除的关键字
* @returns
* @returns
*/
remove(key: string) {
if (null == key) {
console.error("存储的key不能为空");
console.error('存储的key不能为空');
return;
}
@@ -160,9 +160,9 @@ export class StorageManager {
/** 获取数据分组关键字 */
private getKey(key: string): string {
if (this.id == null || this.id == "") {
if (this.id == null || this.id == '') {
return key;
}
return `${this.id}_${key}`;
}
}
}

View File

@@ -31,4 +31,4 @@
// encryptKey(str: string): string {
// return EncryptUtil.md5(str);
// }
// }
// }

View File

@@ -1,4 +1,4 @@
import { IStorageSecurity } from './StorageManager';
import type { IStorageSecurity } from './StorageManager';
/**
* 本地存储加密
@@ -27,7 +27,7 @@ export class StorageSecuritySimple implements IStorageSecurity {
encrypt(data: string): string {
let encryptedText = '';
for (let i = 0; i < data.length; i++) {
let charCode = data.charCodeAt(i);
const charCode = data.charCodeAt(i);
encryptedText += String.fromCharCode(charCode + this.secretkey.length);
}
return encryptedText;
@@ -37,7 +37,7 @@ export class StorageSecuritySimple implements IStorageSecurity {
decrypt(encryptedData: string): string {
let decryptedText = '';
for (let i = 0; i < encryptedData.length; i++) {
let charCode = encryptedData.charCodeAt(i);
const charCode = encryptedData.charCodeAt(i);
decryptedText += String.fromCharCode(charCode - this.secretkey.length);
}
return decryptedText;
@@ -46,4 +46,4 @@ export class StorageSecuritySimple implements IStorageSecurity {
encryptKey(str: string): string {
return this.encrypt(str);
}
}
}

View File

@@ -5,8 +5,8 @@
* @LastEditTime: 2023-01-19 14:28:05
*/
/**
* 定时触发组件
/**
* 定时触发组件
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037964&doc_id=2873565
* @example
export class Test extends Component {
@@ -23,20 +23,20 @@
export class Timer {
callback: Function | null = null;
private _elapsedTime: number = 0;
private _elapsedTime = 0;
get elapsedTime(): number {
return this._elapsedTime;
}
private _step: number = -1;
private _step = -1;
/** 触发间隔时间(秒) */
get step(): number {
return this._step;
}
set step(step: number) {
this._step = step; // 每次修改时间
this._elapsedTime = 0; // 逝去时间
this._step = step; // 每次修改时间
this._elapsedTime = 0; // 逝去时间
}
get progress(): number {
@@ -47,7 +47,7 @@ export class Timer {
* 定时触发组件
* @param step 触发间隔时间(秒)
*/
constructor(step: number = 0) {
constructor(step = 0) {
this.step = step;
}
@@ -72,4 +72,4 @@ export class Timer {
this._elapsedTime = 0;
this.step = -1;
}
}
}

View File

@@ -4,9 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-01-19 14:37:19
*/
import { Component, game } from "cc";
import { StringUtil } from "../../utils/StringUtil";
import { Timer } from "./Timer";
import { Component, game } from 'cc';
import { StringUtil } from '../../utils/StringUtil';
import { Timer } from './Timer';
interface ITimer {
/** 倒计时编号 */
@@ -36,15 +36,15 @@ export class TimerManager extends Component {
/** 服务器初始时间 */
private date_s_start: Date = new Date();
/** 服务器时间后修正时间 */
private polymeric_s: number = 0;
private polymeric_s = 0;
/** 客户端时间 */
private date_c: Date = new Date();
/** 后台管理倒计时完成事件 */
protected update(dt: number) {
for (let key in this.times) {
let data = this.times[key];
let timer = data.timer;
for (const key in this.times) {
const data = this.times[key];
const timer = data.timer;
if (timer.update(dt)) {
if (data.object[data.field] > 0) {
data.object[data.field]--;
@@ -53,9 +53,9 @@ export class TimerManager extends Component {
if (data.object[data.field] == 0) {
this.onTimerComplete(data);
}
// 触发每秒回调事件
// 触发每秒回调事件
else if (data.onSeconds) {
data.onSeconds.forEach(fn => fn.call(data.object));
data.onSeconds.forEach((fn) => fn.call(data.object));
}
}
}
@@ -64,7 +64,7 @@ export class TimerManager extends Component {
/** 触发倒计时完成事件 */
private onTimerComplete(data: ITimer) {
if (data.onCompletes) data.onCompletes.forEach(fn => fn.call(data.target, data.object));
if (data.onCompletes) data.onCompletes.forEach((fn) => fn.call(data.target, data.object));
delete this.times[data.id];
}
@@ -79,12 +79,12 @@ export class TimerManager extends Component {
* @example
export class Test extends Component {
private timeId!: string;
start() {
// 在指定对象上注册一个倒计时的回调管理器
this.timeId = oops.timer.register(this, "countDown", this, this.onSecond, this.onComplete);
}
private onSecond() {
console.log("每秒触发一次");
}
@@ -98,7 +98,7 @@ export class TimerManager extends Component {
const timer = new Timer();
timer.step = 1;
let data: ITimer = {
const data: ITimer = {
id: StringUtil.guid(),
timer: timer,
object: object,
@@ -122,15 +122,15 @@ export class TimerManager extends Component {
* @param onComplete 倒计时完成事件
*/
addCallback(id: string, onSecond?: Function, onComplete?: Function) {
let data = this.times[id];
const data = this.times[id];
if (data) {
if (onSecond) data.onSeconds.push(onSecond);
if (onComplete) data.onCompletes.push(onComplete);
}
}
/**
* 在指定对象上注销一个倒计时的回调管理器
/**
* 在指定对象上注销一个倒计时的回调管理器
* @param id 时间对象唯一表示
* @example
export class Test extends Component {
@@ -188,17 +188,17 @@ export class TimerManager extends Component {
/** 游戏最小化时记录时间数据 */
save(): void {
for (let key in this.times) {
let data: ITimer = this.times[key];
for (const key in this.times) {
const data: ITimer = this.times[key];
data.startTime = this.getTime();
}
}
/** 游戏最大化时恢复时间数据 */
load(): void {
for (let key in this.times) {
let data = this.times[key];
let interval = Math.floor((this.getTime() - (data.startTime || this.getTime())) / 1000);
for (const key in this.times) {
const data = this.times[key];
const 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;
@@ -206,4 +206,4 @@ export class TimerManager extends Component {
}
}
}
}
}

View File

@@ -4,7 +4,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 12:09:55
*/
import { Node, director } from 'cc';
import type { Node } from 'cc';
import { director } from 'cc';
import { GameComponent } from '../../module/common/GameComponent';
import { resLoader } from '../common/loader/ResLoader';
import { ViewUtil } from '../utils/ViewUtil';
@@ -34,7 +35,7 @@ export class GameManager {
*/
open(parent: Node | GameComponent, prefabPath: string, params?: ElementParams): Promise<Node> {
return new Promise(async (resolve, reject) => {
let bundleName: string = null!
let bundleName: string = null!;
if (params && params.bundle) {
bundleName = params.bundle;
}
@@ -73,4 +74,4 @@ export class GameManager {
//@ts-ignore
return director.globalGameTimeScale;
}
}
}

View File

@@ -1,7 +1,7 @@
import { UIConfigMap } from "./layer/LayerEnum";
import { UIConfig } from "./layer/UIConfig";
import type { UIConfigMap } from './layer/LayerEnum';
import type { UIConfig } from './layer/UIConfig';
var configs: UIConfigMap = {};
const configs: UIConfigMap = {};
export namespace gui {
/** 注册界面组件 */
@@ -16,7 +16,7 @@ export namespace gui {
/** 框架内部使用方法 */
export namespace internal {
/** 界面唯一标记变量名 */
export const GUI_KEY = "OOPS_GUI_KEY";
export const GUI_KEY = 'OOPS_GUI_KEY';
/** 获取界面唯一关键字 */
export function getKey(ctor: any) {
@@ -30,7 +30,7 @@ export namespace gui {
/** 获取界面组件配置 */
export function setConfig(key: string, config: UIConfig) {
let c = getConfig(key);
const c = getConfig(key);
if (c == null) {
configs[key] = config;
}
@@ -46,4 +46,4 @@ export namespace gui {
}
}
}
}
}

View File

@@ -6,4 +6,4 @@ export enum PromptResType {
Wait = 'common/prefab/wait',
/** 遮罩层 */
Mask = 'common/prefab/mask',
}
}

View File

@@ -4,10 +4,10 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-07-24 17:14:57
*/
import { Node } from "cc";
import { LayerPopUp } from "./LayerPopup";
import { UIParam, UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
import type { Node } from 'cc';
import { LayerPopUp } from './LayerPopup';
import type { UIParam, UIState } from './LayerUIElement';
import type { UIConfig } from './UIConfig';
/** 模式弹窗数据 */
type DialogParam = {
@@ -28,8 +28,8 @@ export class LayerDialog extends LayerPopUp {
/** 当前打开的界面 */
private current: Node = null!;
/**
* 添加模式窗口
/**
* 添加模式窗口
* 1. 同时添加多个模式窗口时,第一个之后的窗口会先队列起来,在第一个关闭后在加载与显示第二个;同时方法返回节点保持只返回当前显示的界面节点
*/
add(uiid: string, config: UIConfig, params?: UIParam): Promise<Node> {
@@ -49,8 +49,8 @@ export class LayerDialog extends LayerPopUp {
/** 显示模式弹窗 */
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);
const state = this.initUIConfig(uiid, config, param);
const node = await this.load(state);
resolve(node);
});
}
@@ -68,8 +68,8 @@ export class LayerDialog extends LayerPopUp {
private next() {
if (this.params.length > 0) {
let param = this.params.shift()!;
const param = this.params.shift()!;
this.showDialog(param.uiid, param.config, param.params);
}
}
}
}

View File

@@ -1,4 +1,4 @@
import { UIConfig } from "./UIConfig";
import type { UIConfig } from './UIConfig';
/** 界面编号 */
export type Uiid = number | string | UIConfig | Function;
@@ -18,37 +18,37 @@ export enum ScreenAdapterType {
/** 自定义层类型 */
export enum LayerCustomType {
/** 二维游戏层 */
Game = "LayerGame",
Game = 'LayerGame',
/** 消息提示层 */
Notify = "LayerNotify",
Notify = 'LayerNotify',
/** 新手引导层 */
Guide = "LayerGuide"
Guide = 'LayerGuide'
}
/** 界面层类型 */
export enum LayerType {
/** 主界面层 */
UI = "LayerUI",
UI = 'LayerUI',
/** 弹窗层 */
PopUp = "LayerPopUp",
PopUp = 'LayerPopUp',
/** 模式窗口层 */
Dialog = "LayerDialog",
Dialog = 'LayerDialog',
/** 系统触发模式窗口层 */
System = "LayerSystem",
System = 'LayerSystem',
}
/** 界面层组件类型 */
export enum LayerTypeCls {
/** 主界面层 */
UI = "UI",
UI = 'UI',
/** 弹窗层 */
PopUp = "PopUp",
PopUp = 'PopUp',
/** 模式窗口层 */
Dialog = "Dialog",
Dialog = 'Dialog',
/** 消息提示层 */
Notify = "Notify",
Notify = 'Notify',
/** 游戏层 */
Game = "Game",
Game = 'Game',
/** 自定义节点层 */
Node = "Node"
}
Node = 'Node'
}

View File

@@ -4,13 +4,13 @@
* @LastEditors: dgflash
* @LastEditTime: 2025-08-15 10:06:47
*/
import { Node, NodePool, Vec3, warn } from "cc";
import { resLoader } from "../../common/loader/ResLoader";
import { ViewUtil } from "../../utils/ViewUtil";
import { LayerCustomType } from "./LayerEnum";
import { GameElementParams, LayerGameElement } from "./LayerGameElement";
import { LayerHelper } from "./LayerHelper";
import { GameElementConfig } from "./UIConfig";
import { Node, NodePool, Vec3, warn } from 'cc';
import { resLoader } from '../../common/loader/ResLoader';
import { ViewUtil } from '../../utils/ViewUtil';
import { LayerCustomType } from './LayerEnum';
import { GameElementParams, LayerGameElement } from './LayerGameElement';
import { LayerHelper } from './LayerHelper';
import type { GameElementConfig } from './UIConfig';
/* 二维游戏层 */
export class LayerGame extends Node {
@@ -29,13 +29,13 @@ export class LayerGame extends Node {
*/
add(prefab: string, config: GameElementConfig = {}): Promise<Node> {
return new Promise(async (resolve, reject) => {
let params = this.setParams(prefab, config, false);
let node = await ViewUtil.createPrefabNodeAsync(prefab, params.config.bundle);
const params = this.setParams(prefab, config, false);
const node = await ViewUtil.createPrefabNodeAsync(prefab, params.config.bundle);
if (node) {
// 设置自定义属性
this.setNode(node, config);
let lge = node.addComponent(LayerGameElement);
const lge = node.addComponent(LayerGameElement);
lge.params = params;
params.nodes.push(node);
}
@@ -50,7 +50,7 @@ export class LayerGame extends Node {
*/
addPool(prefab: string, config: GameElementConfig = {}): Promise<Node> {
return new Promise(async (resolve, reject) => {
let params = this.setParams(prefab, config, true);
const params = this.setParams(prefab, config, true);
let node: Node = null!;
if (params.pool.size() > 0) {
node = params.pool.get()!;
@@ -63,7 +63,7 @@ export class LayerGame extends Node {
// 设置自定义属性
this.setNode(node, config);
let lge = node.getComponent(LayerGameElement)!;
const lge = node.getComponent(LayerGameElement)!;
lge.params = params;
resolve(node);
@@ -72,9 +72,9 @@ export class LayerGame extends Node {
/** 清理池数据 */
clearPool(node: Node) {
let lge = node.getComponent(LayerGameElement)!;
const lge = node.getComponent(LayerGameElement)!;
if (lge) {
let params = this.elements.get(lge.params.uiid);
const params = this.elements.get(lge.params.uiid);
if (params) params.pool.clear();
}
}
@@ -84,14 +84,14 @@ export class LayerGame extends Node {
* @param node 游戏元素节点
*/
remove(node: Node) {
let lge = node.getComponent(LayerGameElement)!;
const lge = node.getComponent(LayerGameElement)!;
if (lge) {
if (lge.params.pool) {
lge.params.pool.put(node);
}
else {
let nodes = lge.params.nodes;
let index = nodes.indexOf(node);
const nodes = lge.params.nodes;
const index = nodes.indexOf(node);
if (index != -1) {
nodes.splice(index, 1);
if (nodes.length == 0) {
@@ -103,14 +103,14 @@ export class LayerGame extends Node {
}
}
else {
warn(`当前删除游戏元素的 Node 不是通过框架添加的`);
warn('当前删除游戏元素的 Node 不是通过框架添加的');
}
}
/** 设置元素参数 */
private setParams(prefab: string, config: GameElementConfig, pool: boolean) {
let bundleName = config.bundle ? config.bundle : resLoader.defaultBundleName;
let uuid = bundleName + "_" + prefab;
const bundleName = config.bundle ? config.bundle : resLoader.defaultBundleName;
const uuid = bundleName + '_' + prefab;
let params = this.elements.get(uuid);
if (params == null) {
config.prefab = prefab;
@@ -137,4 +137,4 @@ export class LayerGame extends Node {
node.parent = config.parent ? config.parent : this;
if (config.siblingIndex != null) node.setSiblingIndex(config.siblingIndex);
}
}
}

View File

@@ -1,5 +1,6 @@
import { _decorator, Component, Node, NodePool } from "cc";
import { GameElementConfig } from "./UIConfig";
import type { Node, NodePool } from 'cc';
import { _decorator, Component } from 'cc';
import type { GameElementConfig } from './UIConfig';
const { ccclass } = _decorator;
@@ -19,9 +20,9 @@ export class GameElementParams {
/** 游戏元素唯一编号 */
uiid: string = null!;
/** 游戏元素配置 */
config: GameElementConfig = null!
config: GameElementConfig = null!;
/** 同类游戏元素集合 */
nodes: Node[] = null!;
/** 同类游戏元素对象池 */
pool: NodePool = null!;
}
}

View File

@@ -1,5 +1,6 @@
import { Layers } from "cc";
import { Node, Widget } from "cc";
import { Layers } from 'cc';
import type { Node } from 'cc';
import { Widget } from 'cc';
/** 界面层辅助工具 */
export class LayerHelper {
@@ -17,4 +18,4 @@ export class LayerHelper {
node.layer = Layers.Enum.UI_2D;
return widget;
}
}
}

View File

@@ -1,15 +1,17 @@
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, UIParam } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
import { Camera, Node, ResolutionPolicy, SafeArea, screen, view, warn } from 'cc';
import { oops } from '../../Oops';
import { gui } from '../Gui';
import { LayerDialog } from './LayerDialog';
import type { UIConfigMap, Uiid } from './LayerEnum';
import { LayerCustomType, LayerTypeCls } from './LayerEnum';
import { LayerGame } from './LayerGame';
import { LayerHelper } from './LayerHelper';
import { LayerNotify } from './LayerNotify';
import { LayerPopUp } from './LayerPopup';
import { LayerUI } from './LayerUI';
import type { UIParam } from './LayerUIElement';
import { LayerUIElement } from './LayerUIElement';
import type { UIConfig } from './UIConfig';
/** 界面层级管理器 */
export class LayerManager {
@@ -23,11 +25,11 @@ export class LayerManager {
guide!: Node;
/** 窗口宽高比例 */
windowAspectRatio: number = 0;
windowAspectRatio = 0;
/** 设计宽高比例 */
designAspectRatio: number = 0;
designAspectRatio = 0;
/** 是否开启移动设备安全区域适配 */
mobileSafeArea: boolean = false;
mobileSafeArea = false;
/** 消息提示控制器请使用show方法来显示 */
private notify!: LayerNotify;
@@ -52,7 +54,7 @@ export class LayerManager {
*/
registerLayerCls(type: string, cls: any) {
if (this.clsLayers.has(type)) {
console.error("已存在自定义界面层类型", type);
console.error('已存在自定义界面层类型', type);
return;
}
this.clsLayers.set(type, cls);
@@ -64,7 +66,7 @@ export class LayerManager {
*/
private initLayer(root: Node, config: any) {
if (config == null) {
console.error("请升级到最新版本框架,界面层级管理修改为数据驱动。参考模板项目中的config.json配置文件");
console.error('请升级到最新版本框架,界面层级管理修改为数据驱动。参考模板项目中的config.json配置文件');
return;
}
this.root = root;
@@ -73,23 +75,23 @@ export class LayerManager {
// 创建界面层
for (let i = 0; i < config.length; i++) {
let data = config[i];
const data = config[i];
let layer: Node = null!;
if (data.type == LayerTypeCls.Node) {
switch (data.name) {
case LayerCustomType.Guide:
this.guide = this.create_node(data.name);
layer = this.guide;
break
case LayerCustomType.Guide:
this.guide = this.create_node(data.name);
layer = this.guide;
break;
}
}
else {
let cls = this.clsLayers.get(data.type);
const cls = this.clsLayers.get(data.type);
if (cls) {
layer = new cls(data.name);
}
else {
console.error("未识别的界面层类型", data.type);
console.error('未识别的界面层类型', data.type);
}
}
root.addChild(layer);
@@ -110,24 +112,24 @@ export class LayerManager {
this.windowAspectRatio = ws.width / ws.height;
this.designAspectRatio = drs.width / drs.height;
let finalW: number = 0;
let finalH: number = 0;
let finalW = 0;
let finalH = 0;
if (this.windowAspectRatio > this.designAspectRatio) {
finalH = drs.height;
finalW = finalH * ws.width / ws.height;
oops.log.logView("适配屏幕高度", "【横屏】");
oops.log.logView('适配屏幕高度', '【横屏】');
}
else {
finalW = drs.width;
finalH = finalW * ws.height / ws.width;
oops.log.logView("适配屏幕宽度", "【竖屏】");
oops.log.logView('适配屏幕宽度', '【竖屏】');
}
view.setDesignResolutionSize(finalW, finalH, ResolutionPolicy.UNKNOWN);
if (this.mobileSafeArea) {
this.root.addComponent(SafeArea);
oops.log.logView("开启移动设备安全区域适配");
oops.log.logView('开启移动设备安全区域适配');
}
}
@@ -146,18 +148,18 @@ export class LayerManager {
setOpenFailure(callback: Function) {
this.uiLayers.forEach((layer: LayerUI) => {
layer.onOpenFailure = callback;
})
});
}
/**
* 渐隐飘过提示
* @param content 文本表示
* @param useI18n 是否使用多语言
* @example
* @example
* oops.gui.toast("提示内容");
*/
toast(content: string, useI18n: boolean = false) {
this.notify.toast(content, useI18n)
toast(content: string, useI18n = false) {
this.notify.toast(content, useI18n);
}
/** 打开等待提示 */
@@ -172,12 +174,12 @@ export class LayerManager {
/** 获取界面信息 */
private getInfo(uiid: Uiid): { key: string; config: UIConfig } {
let key = "";
let key = '';
let config: UIConfig = null!;
// 界面配置
if (typeof uiid === 'object') {
key = uiid.bundle + "_" + uiid.prefab;
key = uiid.bundle + '_' + uiid.prefab;
config = gui.internal.getConfig(key);
if (config == null) {
config = uiid;
@@ -211,17 +213,17 @@ export class LayerManager {
var comp = node.getComponent(LoadingViewComp) as ecs.Comp;
}
onRemoved:(node: Node | null, params: any) => {
}
};
oops.gui.open(UIID.Loading);
*/
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);
const info = this.getInfo(uiid);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
let node = await layer.add(info.key, info.config, param);
const node = await layer.add(info.key, info.config, param);
resolve(node);
}
else {
@@ -232,8 +234,8 @@ export class LayerManager {
/** 显示指定界面 */
show(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
const info = this.getInfo(uiid);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.show(info.config.prefab);
}
@@ -249,8 +251,8 @@ export class LayerManager {
* oops.gui.remove(UIID.Loading);
*/
remove(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
const info = this.getInfo(uiid);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.remove(info.config.prefab);
}
@@ -266,8 +268,8 @@ export class LayerManager {
* oops.gui.removeCache(UIID.Loading);
*/
removeCache(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
const info = this.getInfo(uiid);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.removeCache(info.config.prefab);
}
@@ -284,16 +286,16 @@ export class LayerManager {
*/
removeByNode(node: Node) {
if (node instanceof Node) {
let comp = node.getComponent(LayerUIElement);
const comp = node.getComponent(LayerUIElement);
if (comp && comp.state) {
// 释放显示的界面
if (node.parent) {
let uiid = gui.internal.getConfig(comp.state.uiid);
const uiid = gui.internal.getConfig(comp.state.uiid);
this.remove(uiid);
}
// 释放缓存中的界面
else {
let layer = this.uiLayers.get(comp.state.config.layer);
const layer = this.uiLayers.get(comp.state.config.layer);
if (layer) {
// @ts-ignore 注:不对外使用
layer.removeCache(comp.state.config.prefab);
@@ -301,7 +303,7 @@ export class LayerManager {
}
}
else {
warn(`当前删除的 Node 不是通过界面管理器添加的`);
warn('当前删除的 Node 不是通过界面管理器添加的');
node.destroy();
}
}
@@ -315,7 +317,7 @@ export class LayerManager {
*/
replace(removeUiId: Uiid, openUiid: Uiid, param?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
let node = await this.open(openUiid, param);
const node = await this.open(openUiid, param);
this.remove(removeUiId);
resolve(node);
});
@@ -328,9 +330,9 @@ export class LayerManager {
* oops.gui.has(UIID.Loading);
*/
has(uiid: Uiid): boolean {
let info = this.getInfo(uiid);
const info = this.getInfo(uiid);
let result = false;
let layer = this.uiLayers.get(info.config.layer);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
result = layer.has(info.config.prefab);
}
@@ -348,9 +350,9 @@ export class LayerManager {
* oops.gui.has(UIID.Loading);
*/
get(uiid: Uiid): Node {
let info = this.getInfo(uiid);
const info = this.getInfo(uiid);
let result: Node = null!;
let layer = this.uiLayers.get(info.config.layer);
const layer = this.uiLayers.get(info.config.layer);
if (layer) {
result = layer.get(info.config.prefab);
}
@@ -366,10 +368,10 @@ export class LayerManager {
* @example
* oops.gui.clear();
*/
clear(isDestroy: boolean = true) {
clear(isDestroy = true) {
this.uiLayers.forEach((layer: LayerUI) => {
layer.clear(isDestroy);
})
});
}
private create_node(name: string) {
@@ -377,4 +379,4 @@ export class LayerManager {
LayerHelper.setFullScreen(node);
return node;
}
}
}

View File

@@ -4,12 +4,12 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 13:44:12
*/
import { BlockInputEvents, Node, instantiate } from "cc";
import { EDITOR } from "cc/env";
import { ViewUtil } from "../../utils/ViewUtil";
import { PromptResType } from "../GuiEnum";
import { Notify } from "../prompt/Notify";
import { LayerHelper } from "./LayerHelper";
import { BlockInputEvents, Node, instantiate } from 'cc';
import { EDITOR } from 'cc/env';
import { ViewUtil } from '../../utils/ViewUtil';
import { PromptResType } from '../GuiEnum';
import { Notify } from '../prompt/Notify';
import { LayerHelper } from './LayerHelper';
/* 滚动消息提示层 */
export class LayerNotify extends Node {
@@ -74,9 +74,9 @@ export class LayerNotify extends Node {
}
this.notify.parent = this;
let childNode = instantiate(this.notifyItem);
let prompt = childNode.getChildByName("prompt")!;
let toastCom = prompt.getComponent(Notify)!;
const childNode = instantiate(this.notifyItem);
const prompt = childNode.getChildByName('prompt')!;
const toastCom = prompt.getComponent(Notify)!;
childNode.parent = this.notify;
toastCom.onComplete = () => {
@@ -91,4 +91,4 @@ export class LayerNotify extends Node {
this.notify.children[0].destroy();
}
}
}
}

View File

@@ -3,12 +3,13 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 13:44:28
*/
import { BlockInputEvents, EventTouch, Node } from "cc";
import { ViewUtil } from "../../utils/ViewUtil";
import { PromptResType } from "../GuiEnum";
import { LayerUI } from "./LayerUI";
import { UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
import type { EventTouch } from 'cc';
import { BlockInputEvents, Node } from 'cc';
import { ViewUtil } from '../../utils/ViewUtil';
import { PromptResType } from '../GuiEnum';
import { LayerUI } from './LayerUI';
import type { UIState } from './LayerUIElement';
import type { UIConfig } from './UIConfig';
/* 弹窗层,允许同时弹出多个窗口 */
export class LayerPopUp extends LayerUI {
@@ -62,7 +63,7 @@ export class LayerPopUp extends LayerUI {
if (this.mask == null) return;
let flag = true;
for (let value of this.ui_nodes.values()) {
for (const value of this.ui_nodes.values()) {
if (value.config.mask) {
flag = false;
break;
@@ -97,7 +98,7 @@ export class LayerPopUp extends LayerUI {
/** 关闭触摸非窗口区域关闭 */
protected closeVacancyRemove() {
let flag = true;
for (let value of this.ui_nodes.values()) {
for (const value of this.ui_nodes.values()) {
if (value.config.vacancy) {
flag = false;
break;
@@ -112,7 +113,7 @@ export class LayerPopUp extends LayerUI {
/** 触摸非窗口区域关闭 */
private onTouchEnd(event: EventTouch) {
if (this.ui_nodes.size > 0) {
let vp = this.ui_nodes.array[this.ui_nodes.size - 1];
const vp = this.ui_nodes.array[this.ui_nodes.size - 1];
if (vp.valid && vp.config.vacancy) {
this.remove(vp.config.prefab);
}
@@ -120,7 +121,7 @@ export class LayerPopUp extends LayerUI {
}
clear(isDestroy: boolean) {
super.clear(isDestroy)
super.clear(isDestroy);
this.closeBlack();
}
}
}

View File

@@ -1,11 +1,12 @@
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, UIParam, UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
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 type { Uiid } from './LayerEnum';
import { LayerHelper } from './LayerHelper';
import type { UIParam } from './LayerUIElement';
import { LayerUIElement, UIState } from './LayerUIElement';
import type { UIConfig } from './UIConfig';
/** 界面层对象 */
export class LayerUI extends Node {
@@ -54,7 +55,7 @@ export class LayerUI extends Node {
}
// 检查缓存中是否存界面
let state = this.initUIConfig(uiid, config, params);
const state = this.initUIConfig(uiid, config, params);
await this.load(state);
resolve(state.node);
});
@@ -89,7 +90,7 @@ export class LayerUI extends Node {
return new Promise<Node>(async (resolve, reject) => {
// 加载界面资源超时提示
if (state.node == null) {
let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
const timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
const res = await resLoader.load(state.config.bundle!, state.config.prefab, Prefab);
@@ -127,7 +128,7 @@ export class LayerUI extends Node {
const comp = state.node.getComponent(LayerUIElement)!;
const r: boolean = await comp.add();
if (r) {
state.valid = true; // 标记界面为使用状态
state.valid = true; // 标记界面为使用状态
if (!state.params.preload) {
state.params.preload = false;
state.node.parent = this;
@@ -164,7 +165,7 @@ export class LayerUI extends Node {
remove(prefabPath: string): void {
const state = this.ui_nodes.get(prefabPath);
if (state) {
let release: boolean = state.config.destroy!;
const release: boolean = state.config.destroy!;
// 不释放界面,缓存起来待下次使用
if (release === false) this.ui_cache.set(state.config.prefab, state);
@@ -231,4 +232,4 @@ export class LayerUI extends Node {
});
}
}
}
}

View File

@@ -4,13 +4,14 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-01-09 11:55:03
*/
import { Component, Node, _decorator } from "cc";
import { oops } from "../../Oops";
import { UIConfig } from "./UIConfig";
import type { Node } from 'cc';
import { Component, _decorator } from 'cc';
import { oops } from '../../Oops';
import type { UIConfig } from './UIConfig';
const EventOnAdded: string = "onAdded";
const EventOnBeforeRemove: string = "onBeforeRemove";
const EventOnRemoved: string = "onRemoved";
const EventOnAdded = 'onAdded';
const EventOnBeforeRemove = 'onBeforeRemove';
const EventOnRemoved = 'onRemoved';
const { ccclass } = _decorator;
@@ -38,7 +39,7 @@ export class LayerUIElement extends Component {
}
// 触发外部窗口显示前的事件(辅助实现自定义动画逻辑)
if (typeof this.state.params.onAdded === "function") {
if (typeof this.state.params.onAdded === 'function') {
this.state.params.onAdded(this.node, this.state.params.data);
}
@@ -53,7 +54,7 @@ export class LayerUIElement extends Component {
this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.state.params.data);
// 通知外部对象窗口组件上移除之前的事件(关闭窗口前的关闭动画处理)
if (typeof this.state.params.onBeforeRemove === "function") {
if (typeof this.state.params.onBeforeRemove === 'function') {
this.state.params.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy));
}
else {
@@ -69,7 +70,7 @@ export class LayerUIElement extends Component {
private onBeforeRemoveNext(isDestroy: boolean) {
this.state.valid = false;
if (this.state.params && typeof this.state.params.onRemoved === "function") {
if (this.state.params && typeof this.state.params.onRemoved === 'function') {
this.state.params.onRemoved(this.node, this.state.params.data);
}
@@ -118,7 +119,7 @@ export class UIState {
/** 窗口事件 */
params: UIParam = null!;
/** 是否在使用状态 */
valid: boolean = true;
valid = true;
/** 界面根节点 */
node: Node = null!;
}
@@ -138,9 +139,9 @@ export interface UIParam {
*/
onAdded?: (node: Node, params: any) => void,
/**
/**
* 如果指定onBeforeRemoved则next必须调用否则节点不会被正常删除。
*
*
* 比如希望节点做一个FadeOut然后删除则可以在`onBeforeRemoved`当中播放action动画动画结束后调用next
* @param node 当前界面节点
* @param next 回调方法
@@ -153,4 +154,4 @@ export interface UIParam {
* @param params 外部传递参数
*/
onRemoved?: (node: Node, params: any) => void
}
}

View File

@@ -1,6 +1,6 @@
import { Node, Vec3 } from "cc";
import type { Node, Vec3 } from 'cc';
/**
/**
* 界面配置结构体
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037986&doc_id=2873565
* @example

View File

@@ -4,23 +4,23 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 14:08:39
*/
import { Component, Node, _decorator } from "cc";
import { Component, Node, _decorator } from 'cc';
const { ccclass, property } = _decorator;
/** 加载延时提示动画 */
@ccclass("LoadingIndicator")
@ccclass('LoadingIndicator')
export class LoadingIndicator extends Component {
@property(Node)
private loading: Node | null = null;
private loading_rotate: number = 0;
private loading_rotate = 0;
update(dt: number) {
this.loading_rotate += dt * 220;
this.loading!.setRotationFromEuler(0, 0, -this.loading_rotate % 360)
this.loading!.setRotationFromEuler(0, 0, -this.loading_rotate % 360);
if (this.loading_rotate > 360) {
this.loading_rotate -= 360;
}
}
}
}

View File

@@ -4,8 +4,8 @@
* @LastEditors: bansomin
* @LastEditTime: 2025-01-02 10:47:47
*/
import { Animation, Component, Label, _decorator } from "cc";
import { LanguageLabel } from "../../../libs/gui/language/LanguageLabel";
import { Animation, Component, Label, _decorator } from 'cc';
import { LanguageLabel } from '../../../libs/gui/language/LanguageLabel';
const { ccclass, property } = _decorator;
@@ -38,7 +38,7 @@ export class Notify extends Component {
* @param useI18n 设置为 true 时,使用多语言功能 msg 参数为多语言 key
*/
toast(msg: string, useI18n: boolean) {
let label = this.lab_content.getComponent(LanguageLabel)!;
const label = this.lab_content.getComponent(LanguageLabel)!;
if (useI18n) {
label.enabled = true;
label.dataID = msg;
@@ -48,4 +48,4 @@ export class Notify extends Component {
this.lab_content.string = msg;
}
}
}
}

View File

@@ -31,10 +31,10 @@ export class ArrayUtil {
/**
* 复制二维数组
* @param array 目标数组
* @param array 目标数组
*/
static copy2DArray(array: any[][]): any[][] {
let newArray: any[][] = [];
const newArray: any[][] = [];
for (let i = 0; i < array.length; i++) {
newArray.push(array[i].concat());
}
@@ -48,8 +48,8 @@ export class ArrayUtil {
static fisherYatesShuffle(array: any[]): any[] {
let count = array.length;
while (count) {
let index = Math.floor(Math.random() * count--);
let temp = array[count];
const index = Math.floor(Math.random() * count--);
const temp = array[count];
array[count] = array[index];
array[index] = temp;
}
@@ -69,7 +69,7 @@ export class ArrayUtil {
* @param array 目标数组
*/
static flattening(array: any[]) {
for (; array.some(v => Array.isArray(v));) { // 判断 array 中是否有数组
for (; array.some((v) => Array.isArray(v));) { // 判断 array 中是否有数组
array = [].concat.apply([], array); // 压扁数组
}
return array;
@@ -107,7 +107,7 @@ export class ArrayUtil {
/**
* 随机打乱数组
* @param array 目标数组
* @example [1,2,3,4,5] --> [5, 1, 2, 3, 4]
* @example [1,2,3,4,5] --> [5, 1, 2, 3, 4]
*/
static shuffleArray<T>(array: T[]): T[] {
// 创建一个原数组的副本
@@ -127,7 +127,7 @@ export class ArrayUtil {
* 获取连续数字数组, 范围在[start, end]之间
* @param start 开始数字
* @param end 结束数字
* @example getNumsBetween(1, 10) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
* @example getNumsBetween(1, 10) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
*/
static getNumsBetween(start: number, end: number): number[] {
return Array.from({ length: end - start + 1 }, (_, i) => start + i);

View File

@@ -4,7 +4,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 14:50:16
*/
import { Camera, Vec3, view } from "cc";
import type { Camera } from 'cc';
import { Vec3, view } from 'cc';
/** 摄像机工具 */
export class CameraUtil {
@@ -28,4 +29,4 @@ export class CameraUtil {
&& (viewPos.x <= viewportRect.width) && (viewPos.x >= 0)
&& (viewPos.y <= viewportRect.height) && (viewPos.y >= 0);
}
}
}

View File

@@ -1,4 +1,4 @@
import { sys } from "cc";
import { sys } from 'cc';
/** 设备工具 */
export class DeviceUtil {
@@ -8,53 +8,87 @@ export class DeviceUtil {
}
/** 当前平台 */
static get platform() { return sys.platform; }
static get platform() {
return sys.platform;
}
/** 当前操作系统 */
static get os() { return sys.os; }
static get os() {
return sys.os;
}
/** 是否为原生环境 */
static get isNative() { return sys.isNative; }
static get isNative() {
return sys.isNative;
}
/** 是否为浏览器环境 */
static get isBrowser() { return sys.isBrowser; }
static get isBrowser() {
return sys.isBrowser;
}
/** 是否为手机 */
static get isMobile() { return sys.isMobile; }
static get isMobile() {
return sys.isMobile;
}
/** 是否为安卓手机 */
static get isAndroid() { return sys.platform === sys.Platform.ANDROID; }
static get isAndroid() {
return sys.platform === sys.Platform.ANDROID;
}
/** 是否为苹果手机 */
static get isIPhone() { return sys.platform === sys.Platform.IOS; }
static get isIPhone() {
return sys.platform === sys.Platform.IOS;
}
/** 是否为手机浏览器 */
static get isMobileBrowser() { return sys.platform === sys.Platform.MOBILE_BROWSER; }
static get isMobileBrowser() {
return sys.platform === sys.Platform.MOBILE_BROWSER;
}
/** 是否为桌面浏览器 */
static get isDesktopBrowser() { return sys.platform === sys.Platform.DESKTOP_BROWSER; }
static get isDesktopBrowser() {
return sys.platform === sys.Platform.DESKTOP_BROWSER;
}
/** 是否为微信小游戏 */
static get isWeChat() { return sys.platform === sys.Platform.WECHAT_GAME; }
static get isWeChat() {
return sys.platform === sys.Platform.WECHAT_GAME;
}
/** 是否为字节小游戏 */
static get isByteDance() { return sys.platform === sys.Platform.BYTEDANCE_MINI_GAME; }
static get isByteDance() {
return sys.platform === sys.Platform.BYTEDANCE_MINI_GAME;
}
/** 是否为 vivo 小游戏 */
static get isVivo() { return sys.platform === sys.Platform.VIVO_MINI_GAME; }
static get isVivo() {
return sys.platform === sys.Platform.VIVO_MINI_GAME;
}
/** 是否为 OPPO 小游戏 */
static get isOPPO() { return sys.platform === sys.Platform.OPPO_MINI_GAME; }
static get isOPPO() {
return sys.platform === sys.Platform.OPPO_MINI_GAME;
}
/** 是否为小米小游戏 */
static get isXiaomi() { return sys.platform === sys.Platform.XIAOMI_QUICK_GAME; }
static get isXiaomi() {
return sys.platform === sys.Platform.XIAOMI_QUICK_GAME;
}
/** 是否为华为小游戏 */
static get isHuawei() { return sys.platform === sys.Platform.HUAWEI_QUICK_GAME; }
static get isHuawei() {
return sys.platform === sys.Platform.HUAWEI_QUICK_GAME;
}
/** 是否为支付宝小游戏 */
static get isAlipay() { return sys.platform === sys.Platform.ALIPAY_MINI_GAME; }
static get isAlipay() {
return sys.platform === sys.Platform.ALIPAY_MINI_GAME;
}
/** 是否为开源鸿蒙小游戏 */
static get isOpenHarmony() { return sys.platform === sys.Platform.OPENHARMONY; }
static get isOpenHarmony() {
return sys.platform === sys.Platform.OPENHARMONY;
}
}

View File

@@ -52,4 +52,4 @@
// // 将解密结果从WordArray转换为UTF-8字符串
// return decrypted.toString(Utf8);
// }
// }
// }

View File

@@ -4,7 +4,7 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 14:49:42
*/
import { Color, Texture2D } from "cc";
import { Color, Texture2D } from 'cc';
/**
* 图像工具
@@ -42,7 +42,7 @@ cc.color(50, 100, 123, 255);
* @param callback 完成回调
*/
static imageToBase64(url: string, callback?: (dataURL: string) => void): Promise<string> {
return new Promise(res => {
return new Promise((res) => {
let extname = /\.png|\.jpg|\.jpeg/.exec(url)?.[0];
//@ts-ignore
if (['.png', '.jpg', '.jpeg'].includes(extname)) {
@@ -60,12 +60,12 @@ cc.color(50, 100, 123, 255);
res(dataURL);
image.remove();
canvas.remove();
}
};
}
else {
console.warn('Not a jpg/jpeg or png resource!');
callback && callback("");
res("");
callback && callback('');
res('');
}
});
}

View File

@@ -5,14 +5,14 @@
* @LastEditTime: 2023-08-22 15:48:02
*/
import { JsonAsset } from "cc";
import { ZipLoader } from "db://oops-framework/core/common/loader/ZipLoader";
import { resLoader } from "../common/loader/ResLoader";
import { JsonAsset } from 'cc';
import { ZipLoader } from 'db://oops-framework/core/common/loader/ZipLoader';
import { resLoader } from '../common/loader/ResLoader';
/** 资源路径 */
const pathJson: string = "config/game/";
const pathJson = 'config/game/';
/** 压缩包资源路径 */
const pathZip: string = "config/game/game";
const pathZip = 'config/game/game';
/** 数据缓存 */
const data: Map<string, any> = new Map();
@@ -20,7 +20,7 @@ const data: Map<string, any> = new Map();
/** JSON数据表工具 */
export class JsonUtil {
/** 是否使用压缩包加载配置表 */
static zip: boolean = false;
static zip = false;
/**
* 通知资源名从缓存中获取一个Json数据表
@@ -69,9 +69,9 @@ export class JsonUtil {
static loadDir(): Promise<void> {
return new Promise(async (resolve, reject) => {
if (this.zip) {
let zip = await ZipLoader.load(pathZip);
for (let key in zip.files) {
let name = key.replace(".json", "");
const zip = await ZipLoader.load(pathZip);
for (const key in zip.files) {
const name = key.replace('.json', '');
data.set(name, ZipLoader.getJson(pathZip, `${name}.json`));
}
ZipLoader.release(pathZip);
@@ -84,7 +84,7 @@ export class JsonUtil {
resolve();
}
else {
assets.forEach(asset => {
assets.forEach((asset) => {
data.set(asset.name, asset.json);
});
resLoader.releaseDir(pathJson);
@@ -107,4 +107,4 @@ export class JsonUtil {
static clear() {
data.clear();
}
}
}

View File

@@ -4,7 +4,7 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 12:05:38
*/
import { Node } from "cc";
import type { Node } from 'cc';
/** 游戏摄像机层数据 */
export class LayerItem {
@@ -58,7 +58,7 @@ export class LayerUtil {
*/
static setNodeLayer(item: LayerItem, node: Node): void {
node.layer = item.mask;
node.children.forEach(n => {
node.children.forEach((n) => {
n.layer = item.mask;
LayerUtil.setNodeLayer(item, n);
});

View File

@@ -13,7 +13,7 @@ export class MathUtil {
/**
* 获得随机方向
* @param x -1为左1为右
* @returns
* @returns
*/
static sign(x: number) {
if (x > 0) {
@@ -46,7 +46,7 @@ export class MathUtil {
t = 1;
}
else if (t < 0) {
t = 0
t = 0;
}
return numStart * (1 - t) + (numEnd * t);
@@ -127,4 +127,4 @@ export class MathUtil {
static probability(value: number) {
return Math.random() < value;
}
}
}

View File

@@ -72,13 +72,13 @@ export class ObjectUtil {
// 检查是否是特殊值
if (obj === Infinity || obj === -Infinity) return true;
// 检测是否包含空格的字符串
if (typeof obj === "string" && obj.trim() === "") return true;
if (typeof obj === 'string' && obj.trim() === '') return true;
// 检查是否是无效的数字
if (Number.isNaN(obj)) return true;
// 检查是否是空数组
if (Array.isArray(obj) && obj.length <= 0) return true;
// 检查是否是空对象
if (typeof (obj) == "object" && Object.keys(obj).length <= 0) return true;
if (typeof (obj) === 'object' && Object.keys(obj).length <= 0) return true;
return false;
}
}

View File

@@ -4,7 +4,7 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 14:40:28
*/
import { Node } from "cc";
import type { Node } from 'cc';
/** 物理分组数据 */
export class GroupItem {
@@ -49,9 +49,9 @@ export class PhysicsUtil {
static setNodeLayer(item: GroupItem, node: Node) {
node.layer = item.mask;
node.children.forEach(n => {
node.children.forEach((n) => {
n.layer = item.mask;
PhysicsUtil.setNodeLayer(item, n);
});
}
}
}

View File

@@ -3,7 +3,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 14:39:03
*/
import { __private, native, sys } from "cc";
import type { __private } from 'cc';
import { native, sys } from 'cc';
/** 平台数据 */
export class PlatformUtil {
@@ -31,7 +32,7 @@ export class PlatformUtil {
native.copyTextToClipboard(text);
}
else {
await navigator.clipboard.writeText(text)
await navigator.clipboard.writeText(text);
}
}
}

View File

@@ -4,8 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 12:08:28
*/
import { Node, Quat, toRadian, Vec3 } from "cc";
import { Vec3Util } from "./Vec3Util";
import type { Node } from 'cc';
import { Quat, toRadian, Vec3 } from 'cc';
import { Vec3Util } from './Vec3Util';
/** 旋转工具 */
export class RotateUtil {
@@ -34,8 +35,8 @@ export class RotateUtil {
*/
static rotateAroundTarget(lookAt: Node, target: Node, axis: Vec3, rad: number) {
// 计算坐标
const point_lookAt = lookAt.worldPosition; // 锚点坐标
const point_target = target.worldPosition; // 目标坐标
const point_lookAt = lookAt.worldPosition; // 锚点坐标
const point_target = target.worldPosition; // 目标坐标
const quat = new Quat();
const vec3 = new Vec3();
@@ -62,8 +63,8 @@ export class RotateUtil {
* @param angle 角度
*/
static circularEdgePosition(center: Vec3, radius: number, angle: number): Vec3 {
const edge = Vec3Util.z.multiplyScalar(radius); // 距离圆心Z抽的距离
const dir = Vec3Util.sub(edge, center); // 初始圆心与目标位置的方向
const edge = Vec3Util.z.multiplyScalar(radius); // 距离圆心Z抽的距离
const dir = Vec3Util.sub(edge, center); // 初始圆心与目标位置的方向
const vec3 = new Vec3();
const quat = new Quat();
@@ -76,4 +77,4 @@ export class RotateUtil {
return vec3;
}
}
}

View File

@@ -2,12 +2,12 @@
export class StringUtil {
/** 获取一个唯一标识的字符串 */
static guid() {
let guid: string = "";
let guid = '';
for (let i = 1; i <= 32; i++) {
let n = Math.floor(Math.random() * 16.0).toString(16);
const n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
if ((i == 8) || (i == 12) || (i == 16) || (i == 20))
guid += "-";
guid += '-';
}
return guid;
}
@@ -29,7 +29,7 @@ export class StringUtil {
* @example
* 12345 = 12.35K
*/
static numberToThousand(value: number, fixed: number = 2): string {
static numberToThousand(value: number, fixed = 2): string {
const k = 1000;
const sizes = ['', 'K', 'M', 'G'];
if (value < k) {
@@ -49,7 +49,7 @@ export class StringUtil {
* @example
* 12345 = 1.23万
*/
static numberToTenThousand(value: number, fixed: number = 2): string {
static numberToTenThousand(value: number, fixed = 2): string {
const k = 10000;
const sizes = ['', '万', '亿', '万亿'];
if (value < k) {
@@ -66,10 +66,10 @@ export class StringUtil {
* @param str 字符串
*/
static stringToArray1(str: string) {
if (str == "") {
if (str == '') {
return [];
}
return str.split(",");
return str.split(',');
}
/**
@@ -77,10 +77,10 @@ export class StringUtil {
* @param str 字符串
*/
static stringToArray2(str: string) {
if (str == "") {
if (str == '') {
return [];
}
return str.split("|");
return str.split('|');
}
/**
@@ -88,10 +88,10 @@ export class StringUtil {
* @param str 字符串
*/
static stringToArray3(str: string) {
if (str == "") {
if (str == '') {
return [];
}
return str.split(":");
return str.split(':');
}
/**
@@ -99,10 +99,10 @@ export class StringUtil {
* @param str 字符串
*/
static stringToArray4(str: string) {
if (str == "") {
if (str == '') {
return [];
}
return str.split(";");
return str.split(';');
}
/**
@@ -111,14 +111,16 @@ export class StringUtil {
* @param n 截取长度
* @param showdot 是否把截取的部分用省略号代替
*/
static sub(str: string, n: number, showdot: boolean = false) {
static sub(str: string, n: number, showdot = false) {
const r = /[^\x00-\xff]/g;
if (str.replace(r, "mm").length <= n) { return str; }
if (str.replace(r, 'mm').length <= n) {
return str;
}
const m = Math.floor(n / 2);
for (let i = m; i < str.length; i++) {
if (str.substr(0, i).replace(r, "mm").length >= n) {
if (str.substr(0, i).replace(r, 'mm').length >= n) {
if (showdot) {
return str.substr(0, i) + "...";
return str.substr(0, i) + '...';
}
else {
return str.substr(0, i);
@@ -177,8 +179,8 @@ export class StringUtil {
args = rest;
}
for (let i: number = 0; i < len; i++) {
str = str.replace(new RegExp("\\{" + i + "\\}", "g"), args[i]);
for (let i = 0; i < len; i++) {
str = str.replace(new RegExp('\\{' + i + '\\}', 'g'), args[i]);
}
return str;

View File

@@ -4,16 +4,16 @@ export class TimeUtil {
* 间隔天数
* @param time1 开始时间
* @param time2 结束时间
* @returns
* @returns
*/
static daysBetween(time1: number | string | Date, time2: number | string | Date): number {
if (time2 == undefined) {
time2 = +new Date();
}
let startDate = new Date(time1).toLocaleDateString()
let endDate = new Date(time2).toLocaleDateString()
let startTime = new Date(startDate).getTime();
let endTime = new Date(endDate).getTime();
const startDate = new Date(time1).toLocaleDateString();
const endDate = new Date(time2).toLocaleDateString();
const startTime = new Date(startDate).getTime();
const endTime = new Date(endDate).getTime();
return Math.abs((startTime - endTime)) / (1000 * 60 * 60 * 24);
}
@@ -32,24 +32,24 @@ export class TimeUtil {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, ms)
}, ms);
});
}
/** 格式化字符串 */
static format(countDown: number) {
let result: string = "";
let result = '';
let c: number = countDown;
let date: number = Math.floor(c / 86400);
const date: number = Math.floor(c / 86400);
c = c - date * 86400;
let hours: number = Math.floor(c / 3600);
c = c - hours * 3600;
let minutes: number = Math.floor(c / 60);
const minutes: number = Math.floor(c / 60);
c = c - minutes * 60;
let seconds: number = c;
const seconds: number = c;
if (date == 0 && hours == 0 && minutes == 0 && seconds == 0) {
result = "00:00:00";
result = '00:00:00';
}
else {
hours += date * 24;
@@ -60,7 +60,7 @@ export class TimeUtil {
/** 个位数的时间数据将字符串补位 */
private static coverString(value: number) {
if (value < 10) return "0" + value;
if (value < 10) return '0' + value;
return value.toString();
}
}
}

View File

@@ -1,5 +1,5 @@
import {Mat4, Vec3} from "cc";
import {MathUtil} from "./MathUtil";
import { Mat4, Vec3 } from 'cc';
import { MathUtil } from './MathUtil';
/** 向量工具 */
export class Vec3Util {
@@ -175,7 +175,7 @@ export class Vec3Util {
*/
static direction(pos1: Vec3, pos2: Vec3): Vec3 {
const outPos: Vec3 = new Vec3();
Vec3.subtract(outPos, pos2, pos1)
Vec3.subtract(outPos, pos2, pos1);
return outPos.normalize();
}
@@ -207,12 +207,13 @@ export class Vec3Util {
static slerp(from: Vec3, to: Vec3, t: number): Vec3 {
if (t <= 0) {
return from;
} else if (t >= 1) {
}
else if (t >= 1) {
return to;
}
var dir: Vec3 = this.rotateTo(from, to, (Vec3.angle(from, to) / Math.PI * 180) * t);
var lenght: number = to.length() * t + from.length() * (1 - t);
const dir: Vec3 = this.rotateTo(from, to, (Vec3.angle(from, to) / Math.PI * 180) * t);
const lenght: number = to.length() * t + from.length() * (1 - t);
return (dir.normalize()).multiplyScalar(lenght);
}
@@ -229,7 +230,7 @@ export class Vec3Util {
return to;
}
const axis: Vec3 = new Vec3(); // 获得旋转轴
const axis: Vec3 = new Vec3(); // 获得旋转轴
Vec3.cross(axis, from, to);
axis.normalize();
@@ -254,12 +255,13 @@ export class Vec3Util {
static bezierOne(t: number, posStart: Vec3, posEnd: Vec3): Vec3 {
if (t > 1) {
t = 1;
} else if (t < 0) {
t = 0
}
else if (t < 0) {
t = 0;
}
var pStart: Vec3 = posStart.clone();
var pEnd: Vec3 = posEnd.clone();
const pStart: Vec3 = posStart.clone();
const pEnd: Vec3 = posEnd.clone();
return pStart.multiplyScalar(1 - t).add(pEnd.multiplyScalar(t));
}
@@ -275,8 +277,9 @@ export class Vec3Util {
static bezierTwo(t: number, posStart: Vec3, posCon: Vec3, posEnd: Vec3): Vec3 {
if (t > 1) {
t = 1;
} else if (t < 0) {
t = 0
}
else if (t < 0) {
t = 0;
}
const n = (1 - t);
@@ -307,8 +310,9 @@ export class Vec3Util {
static bezierThree(t: number, posStart: Vec3, posCon1: Vec3, posCon2: Vec3, posEnd: Vec3): Vec3 {
if (t > 1) {
t = 1;
} else if (t < 0) {
t = 0
}
else if (t < 0) {
t = 0;
}
const n = (1 - t);
@@ -387,4 +391,4 @@ export class Vec3Util {
return angle * sign;
}
}
}

View File

@@ -4,8 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-01-19 14:52:12
*/
import { Animation, AnimationClip, EventTouch, instantiate, Node, Prefab, Size, UITransform, v3, Vec3 } from "cc";
import { resLoader } from "../common/loader/ResLoader";
import type { EventTouch, Node, Vec3 } from 'cc';
import { Animation, AnimationClip, instantiate, Prefab, Size, UITransform, v3 } from 'cc';
import { resLoader } from '../common/loader/ResLoader';
/** 显示对象工具 */
export class ViewUtil {
@@ -16,10 +17,10 @@ export class ViewUtil {
* @param obj 绑定的js对象 (可选)
*/
static nodeTreeInfoLite(parent: Node, obj?: Map<string, Node>): Map<string, Node> | null {
let map: Map<string, Node> = obj || new Map();
let items = parent.children;
const map: Map<string, Node> = obj || new Map();
const items = parent.children;
for (let i = 0; i < items.length; i++) {
let _node = items[i];
const _node = items[i];
if (_node.name.length > 0) {
if (map.has(_node.name))
console.error(`使用ViewUtil.nodeTreeInfoLite方法时发现重复的节点名称【${_node.name}`);
@@ -38,10 +39,10 @@ export class ViewUtil {
* @param nodes 返回的数组(可选)
*/
static findNodes(reg: RegExp, parent: Node, nodes?: Array<Node>): Array<Node> {
let ns: Array<Node> = nodes || [];
let items = parent.children;
const ns: Array<Node> = nodes || [];
const items = parent.children;
for (let i = 0; i < items.length; i++) {
let _name: string = items[i].name;
const _name: string = items[i].name;
if (reg.test(_name)) {
ns.push(items[i]);
}
@@ -125,7 +126,7 @@ export class ViewUtil {
* @param onlyOne 是否唯一
* @param isDefaultClip 是否播放默认动画剪辑
*/
static addNodeAnimation(path: string, node: Node, onlyOne: boolean = true, isDefaultClip: boolean = false) {
static addNodeAnimation(path: string, node: Node, onlyOne = true, isDefaultClip = false) {
if (!node || !node.isValid) {
return;
}
@@ -159,9 +160,9 @@ export class ViewUtil {
if (anim.getState(clip.name)) {
anim.play(clip.name);
return
return;
}
anim.createState(clip, clip!.name);
anim.play(clip!.name);
}
}
}

View File

@@ -1,12 +1,13 @@
import { CCInteger, Component, Material, Sprite, _decorator } from 'cc';
import type { Material } from 'cc';
import { CCInteger, Component, Sprite, _decorator } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('Ambilight')
/** 流光效果 */
export class Ambilight extends Component {
@property
_max: number = 1;
_max = 1;
@property(CCInteger)
get max(): number {
return this._max;

View File

@@ -3,9 +3,9 @@ const { ccclass, property } = _decorator;
@ccclass('FlashSpine')
export default class FlashSpine extends Component {
duration: number = 0.5;
_median: number = 0;
_time: number = 0;
duration = 0.5;
_median = 0;
_time = 0;
_material: Material = null!;
_skeleton: sp.Skeleton = null!;
@@ -16,7 +16,7 @@ export default class FlashSpine extends Component {
this._skeleton = this.node.getComponent(sp.Skeleton)!;
this._material = this._skeleton.customMaterial!;
// 设置材质对应的属性
this._material.setProperty("u_rate", 1);
this._material.setProperty('u_rate', 1);
}
update(dt: number) {
@@ -24,15 +24,15 @@ export default class FlashSpine extends Component {
this._time -= dt;
this._time = this._time < 0 ? 0 : this._time;
let rate = Math.abs(this._time - this._median) * 2 / this.duration;
const rate = Math.abs(this._time - this._median) * 2 / this.duration;
let mat = new Material();
const mat = new Material();
mat.copy(this._material);
this._skeleton.customMaterial = mat;
mat.setProperty("u_rate", rate);
mat.setProperty('u_rate', rate);
}
}
clickFlash() {
this._time = this.duration;
}

View File

@@ -1,11 +1,12 @@
import { Component, Material, Sprite, _decorator } from 'cc';
import type { Material } from 'cc';
import { Component, Sprite, _decorator } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('FlashSprite')
export default class FlashSprite extends Component {
duration: number = 0.5;
_median: number = 0;
_time: number = 0;
duration = 0.5;
_median = 0;
_time = 0;
_material: Material = null!;
@@ -14,7 +15,7 @@ export default class FlashSprite extends Component {
// 获取材质
this._material = this.node.getComponent(Sprite)!.getMaterial(0)!;
// 设置材质对应的属性
this._material.setProperty("u_rate", 1);
this._material.setProperty('u_rate', 1);
}
update(dt: number) {
@@ -22,8 +23,8 @@ export default class FlashSprite extends Component {
this._time -= dt;
this._time = this._time < 0 ? 0 : this._time;
let rate = Math.abs(this._time - this._median) * 2 / this.duration;
this._material.setProperty("u_rate", rate);
const rate = Math.abs(this._time - this._median) * 2 / this.duration;
this._material.setProperty('u_rate', rate);
}
}

View File

@@ -13,7 +13,7 @@ const { ccclass, property } = _decorator;
@ccclass('SpineFinishedRelease')
export class SpineFinishedRelease extends Component {
@property
isDestroy: boolean = true;
isDestroy = true;
private spine!: sp.Skeleton;
private resPath: string = null!;
@@ -31,15 +31,15 @@ export class SpineFinishedRelease extends Component {
this.loadSkeletonData();
}
else {
this.spine.setAnimation(0, "animation", false);
this.spine.setAnimation(0, 'animation', false);
}
}
private async loadSkeletonData() {
let sd = await oops.res.load(this.resPath, sp.SkeletonData);
const sd = await oops.res.load(this.resPath, sp.SkeletonData);
if (sd) {
this.spine.skeletonData = sd;
this.spine.setAnimation(0, "animation", false);
this.spine.setAnimation(0, 'animation', false);
}
}

View File

@@ -5,26 +5,27 @@
* @LastEditTime: 2022-09-22 14:53:47
*/
import {_decorator, Camera, Component, Node, Vec3} from "cc";
import {oops} from "../../core/Oops";
import {MathUtil} from "../../core/utils/MathUtil";
import type { Camera } from 'cc';
import { _decorator, Component, Node, Vec3 } from 'cc';
import { oops } from '../../core/Oops';
import { MathUtil } from '../../core/utils/MathUtil';
const { ccclass, property } = _decorator;
/** 2D节点跟随3D节点 */
@ccclass("Effect2DFollow3D")
@ccclass('Effect2DFollow3D')
export class Effect2DFollow3D extends Component {
/** 3D世界节点 */
@property({ type: Node })
node3d: Node = null!;
node3d: Node = null!;
/** 2D界面界面 */
@property({ type: Node })
nodeUi: Node = null!;
nodeUi: Node = null!;
/** 距离 */
@property
distance: number = 10;
distance = 10;
/** 3D摄像机 */
camera: Camera = null!;

View File

@@ -14,7 +14,7 @@ const { ccclass, property } = _decorator;
export class EffectDelayRelease extends Component {
/** 延时释放时间(单位秒) */
@property
public delay: number = 1;
delay = 1;
protected onEnable() {
this.scheduleOnce(this.onDelay, this.delay);

View File

@@ -1,5 +1,5 @@
/** 特效管理模块事件 */
export enum EffectEvent {
/** 回收节点 */
Put = "EffectEvent_Put"
}
Put = 'EffectEvent_Put'
}

View File

@@ -9,21 +9,21 @@ import { Animation, Component, ParticleSystem, _decorator, sp } from 'cc';
import { EffectEvent } from './EffectEvent';
import { message } from '../../core/common/event/MessageManager';
const { ccclass, property } = _decorator;
const { ccclass } = _decorator;
/** 动画播放完释放特效 - Animation、ParticleSystem */
@ccclass('EffectFinishedRelease')
export class EffectFinishedRelease extends Component {
/** 动画最大播放时间 */
private maxDuration: number = 0;
private maxDuration = 0;
protected onEnable() {
// SPINE动画
let spine = this.getComponent(sp.Skeleton);
const spine = this.getComponent(sp.Skeleton);
if (spine) {
// 播放第一个动画
let json = (spine.skeletonData!.skeletonJson! as any).animations;
for (let name in json) {
const json = (spine.skeletonData!.skeletonJson! as any).animations;
for (const name in json) {
spine.setCompleteListener(this.onRecovery.bind(this));
spine.setAnimation(0, name, false);
break;
@@ -31,14 +31,14 @@ export class EffectFinishedRelease extends Component {
}
else {
// COCOS动画
let anims: Animation[] = this.node.getComponentsInChildren(Animation);
const anims: Animation[] = this.node.getComponentsInChildren(Animation);
if (anims.length > 0) {
anims.forEach(animator => {
let aniName = animator.defaultClip?.name;
anims.forEach((animator) => {
const aniName = animator.defaultClip?.name;
if (aniName) {
let aniState = animator.getState(aniName);
const aniState = animator.getState(aniName);
if (aniState) {
let duration = aniState.duration;
const duration = aniState.duration;
this.maxDuration = duration > this.maxDuration ? duration : this.maxDuration;
}
}
@@ -48,13 +48,13 @@ export class EffectFinishedRelease extends Component {
}
// 粒子动画
else if (ParticleSystem) {
let particles: ParticleSystem[] = this.node.getComponentsInChildren(ParticleSystem);
particles.forEach(particle => {
const particles: ParticleSystem[] = this.node.getComponentsInChildren(ParticleSystem);
particles.forEach((particle) => {
particle.clear();
particle.stop();
particle.play()
particle.play();
let duration: number = particle.duration;
const duration: number = particle.duration;
this.maxDuration = duration > this.maxDuration ? duration : this.maxDuration;
});
this.scheduleOnce(this.onRecovery.bind(this), this.maxDuration);

View File

@@ -4,7 +4,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-03-06 14:40:34
*/
import { Animation, Node, NodePool, ParticleSystem, Prefab, sp, Vec3 } from 'cc';
import type { Node, Vec3 } from 'cc';
import { Animation, NodePool, ParticleSystem, Prefab, sp } from 'cc';
import { message } from '../../core/common/event/MessageManager';
import { resLoader } from '../../core/common/loader/ResLoader';
import { ViewUtil } from '../../core/utils/ViewUtil';
@@ -38,7 +39,7 @@ export class EffectSingleCase {
return this._instance;
}
private _speed: number = 1;
private _speed = 1;
/** 全局动画播放速度 */
get speed(): number {
return this._speed;
@@ -70,7 +71,7 @@ export class EffectSingleCase {
* @param path 预制资源路径
*/
getCount(path: string): number {
var np = this.effects.get(path);
const np = this.effects.get(path);
if (np) {
return np.size();
}
@@ -90,7 +91,7 @@ export class EffectSingleCase {
await resLoader.load(bundleName, path, Prefab);
for (let i = 0; i < count; i++) {
let node = ViewUtil.createPrefabNode(path, bundleName);
const node = ViewUtil.createPrefabNode(path, bundleName);
//@ts-ignore
node.res_path = path;
np.put(node);
@@ -107,7 +108,7 @@ export class EffectSingleCase {
*/
loadAndShow(path: string, parent?: Node, params?: IEffectParams): Promise<Node> {
return new Promise(async (resolve, reject) => {
var np = this.effects.get(path);
const np = this.effects.get(path);
if (np == undefined) {
if (params && params.bundleName) {
this.res.set(path, params.bundleName);
@@ -135,16 +136,16 @@ export class EffectSingleCase {
* @param params 显示参数
*/
show(path: string, parent?: Node, params?: IEffectParams): Node {
var np = this.effects.get(path);
let np = this.effects.get(path);
if (np == null) {
np = new NodePool();
this.effects.set(path, np);
}
var node: Node;
let node: Node;
// 创建池中新显示对象
if (np.size() == 0) {
var bundleName = resLoader.defaultBundleName;
let bundleName = resLoader.defaultBundleName;
if (params && params.bundleName) bundleName = params.bundleName;
node = ViewUtil.createPrefabNode(path, bundleName);
//@ts-ignore
@@ -206,7 +207,7 @@ export class EffectSingleCase {
if (np) np.clear();
}
else {
this.effects.forEach(np => {
this.effects.forEach((np) => {
np.clear();
});
this.effects.clear();
@@ -232,14 +233,14 @@ export class EffectSingleCase {
this.res.forEach((bundleName: string, path: string) => {
resLoader.release(path, bundleName);
});
this.res.clear()
this.res.clear();
}
}
/** 设置动画速度 */
private setSpeed(node: Node) {
// SPINE动画
let spine = node.getComponent(sp.Skeleton);
const spine = node.getComponent(sp.Skeleton);
if (spine) {
spine.timeScale = this.speed;
}
@@ -247,10 +248,10 @@ export class EffectSingleCase {
// COCOS动画
const anims: Animation[] = node.getComponentsInChildren(Animation);
if (anims.length > 0) {
anims.forEach(animator => {
let aniName = animator.defaultClip?.name;
anims.forEach((animator) => {
const aniName = animator.defaultClip?.name;
if (aniName) {
let aniState = animator.getState(aniName);
const aniState = animator.getState(aniName);
if (aniState) {
aniState.speed = this.speed;
}
@@ -260,10 +261,10 @@ export class EffectSingleCase {
// 粒子动画
else if (ParticleSystem) {
const particles: ParticleSystem[] = node.getComponentsInChildren(ParticleSystem);
particles.forEach(particle => {
particles.forEach((particle) => {
particle.simulationSpeed = this.speed;
});
}
}
}
}
}

View File

@@ -4,7 +4,7 @@ const { ccclass, property } = _decorator;
const v3_0 = new Vec3();
const v3_1 = new Vec3();
/**
/**
* 物理方式移动
* 1. 施加线性数度
* 2. 施加阻尼
@@ -14,58 +14,60 @@ const v3_1 = new Vec3();
@ccclass('MoveRigidBody')
export class MoveRigidBody extends Component {
@property({ tooltip: '阻尼' })
damping: number = 0.5;
damping = 0.5;
@property({ tooltip: '重力' })
gravity: number = -10;
gravity = -10;
@property
private _speed: number = 5;
private _speed = 5;
@property({ tooltip: '移动速度' })
public get speed(): number {
get speed(): number {
return this._speed;
}
public set speed(value: number) {
set speed(value: number) {
this._speed = value;
this._curMaxSpeed = value * this.ratio;
}
@property
private _ratio: number = 1;
private _ratio = 1;
@property({ tooltip: '速度比率' })
public get ratio(): number {
get ratio(): number {
return this._ratio;
}
public set ratio(value: number) {
set ratio(value: number) {
this._ratio = value;
this._curMaxSpeed = this.speed * value;
}
private _rigidBody: RigidBody = null!;
private _grounded = true; // 是否着地
private _curMaxSpeed: number = 0; // 当前最大速度
private _prevAngleY: number = 0; // 之前的Y角度值
private _stateX: number = 0;
private _stateZ: number = 0;
private _grounded = true; // 是否着地
private _curMaxSpeed = 0; // 当前最大速度
private _prevAngleY = 0; // 之前的Y角度值
private _stateX = 0;
private _stateZ = 0;
/** 是否着地 */
get grounded() { return this._grounded; }
get grounded() {
return this._grounded;
}
private _velocity: Vec3 = new Vec3();
/** 移动方向 */
public get velocity(): Vec3 {
get velocity(): Vec3 {
return this._velocity;
}
public set velocity(value: Vec3) {
set velocity(value: Vec3) {
this._velocity = value;
var x = value.x;
var z = value.z;
const x = value.x;
const z = value.z;
if ((x > 0 && this._stateX < 0) ||
(x < 0 && this._stateX > 0) ||
(z > 0 && this._stateZ < 0) ||
(z < 0 && this._stateZ > 0)) {
this._rigidBody.clearVelocity(); // 当前跟之前方向不一致则清除速度,避免惯性太大
this._rigidBody.clearVelocity(); // 当前跟之前方向不一致则清除速度,避免惯性太大
}
this._stateX = x;
@@ -81,7 +83,7 @@ export class MoveRigidBody extends Component {
stop() {
this._stateX = 0;
this._stateZ = 0;
this._rigidBody.clearVelocity(); // 清除移动速度
this._rigidBody.clearVelocity(); // 清除移动速度
}
update(dt: number) {
@@ -145,4 +147,4 @@ export class MoveRigidBody extends Component {
this._rigidBody.setLinearVelocity(v3_1);
}
}
}
}

View File

@@ -5,9 +5,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-01-19 14:59:50
*/
import { Component, Node, Vec3, _decorator } from "cc";
import { Timer } from "../../core/common/timer/Timer";
import { Vec3Util } from "../../core/utils/Vec3Util";
import { Component, Node, Vec3, _decorator } from 'cc';
import { Timer } from '../../core/common/timer/Timer';
import { Vec3Util } from '../../core/utils/Vec3Util';
const { ccclass, property } = _decorator;
@@ -19,14 +19,14 @@ export class MoveTo extends Component {
/** 移动方向 */
velocity: Vec3 = Vec3Util.zero;
/** 移动速度(每秒移动的像素距离) */
speed: number = 0;
speed = 0;
/** 是否计算将 Y 轴带入计算 */
hasYAxis: boolean = true;
hasYAxis = true;
/** 坐标标(默认本地坐标) */
ns: number = Node.NodeSpace.LOCAL;
/** 偏移距离 */
offset: number = 0;
offset = 0;
/** 偏移向量 */
offsetVector: Vec3 | null = null;
/** 移动开始 */
@@ -53,7 +53,7 @@ export class MoveTo extends Component {
let end: Vec3;
if (this.speed <= 0) {
console.error("移动速度必须要大于零");
console.error('移动速度必须要大于零');
return;
}
@@ -80,11 +80,11 @@ export class MoveTo extends Component {
if (this.hasYAxis == false) target.y = 0;
// 移动方向与移动数度
let start = this.ns == Node.NodeSpace.WORLD ? this.node.worldPosition : this.node.position;
const start = this.ns == Node.NodeSpace.WORLD ? this.node.worldPosition : this.node.position;
this.velocity = Vec3Util.sub(target, start).normalize();
// 移动时间与目标偏位置计算
let distance = Vec3.distance(start, target) - this.offset;
const distance = Vec3.distance(start, target) - this.offset;
// 目标位置修改事件
this.onChange?.call(this);
@@ -101,7 +101,7 @@ export class MoveTo extends Component {
}
if (this.speed > 0) {
let trans = Vec3Util.mul(this.velocity, this.speed * dt);
const trans = Vec3Util.mul(this.velocity, this.speed * dt);
if (this.ns == Node.NodeSpace.WORLD)
this.node.worldPosition = Vec3Util.add(this.node.worldPosition, trans);
else
@@ -137,4 +137,4 @@ export class MoveTo extends Component {
this.timer.reset();
this.end = null;
}
}
}

View File

@@ -5,8 +5,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-07-25 11:52:23
*/
import { Component, Node, Vec3, _decorator } from "cc";
import { Vec3Util } from "../../core/utils/Vec3Util";
import { Component, Node, Vec3, _decorator } from 'cc';
import { Vec3Util } from '../../core/utils/Vec3Util';
const { ccclass, property } = _decorator;
@@ -16,7 +16,7 @@ export class MoveTranslate extends Component {
/** 移动方向 */
velocity: Vec3 = Vec3Util.zero;
/** 移动速度 */
speed: number = 0;
speed = 0;
private vector: Vec3 = new Vec3();
@@ -26,4 +26,4 @@ export class MoveTranslate extends Component {
this.node.translate(this.vector, Node.NodeSpace.WORLD);
}
}
}
}

View File

@@ -1,10 +1,12 @@
import { Animation, AnimationState, _decorator } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import { AnimatorStateLogic } from "./core/AnimatorStateLogic";
import type { AnimationState } from 'cc';
import { Animation, _decorator } from 'cc';
import type { AnimationPlayer } from './core/AnimatorBase';
import AnimatorBase from './core/AnimatorBase';
import type { AnimatorStateLogic } from './core/AnimatorStateLogic';
const { ccclass, property, requireComponent, disallowMultiple, menu, help } = _decorator;
/**
/**
* Cocos Animation状态机组件
*/
@ccclass
@@ -42,7 +44,7 @@ export default class AnimatorAnimation extends AnimatorBase {
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}

View File

@@ -1,10 +1,11 @@
import { _decorator } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import { AnimatorStateLogic } from "./core/AnimatorStateLogic";
import { _decorator } from 'cc';
import type { AnimationPlayer } from './core/AnimatorBase';
import AnimatorBase from './core/AnimatorBase';
import type { AnimatorStateLogic } from './core/AnimatorStateLogic';
const { ccclass, property, disallowMultiple, menu, help } = _decorator;
/**
/**
* 自定义动画控制的状态机组件
*/
@ccclass
@@ -14,7 +15,7 @@ const { ccclass, property, disallowMultiple, menu, help } = _decorator;
export default class AnimatorCustomization extends AnimatorBase {
/** 此组件必须主动调用onInit初始化 */
@property({ override: true, visible: false })
PlayOnStart: boolean = false;
PlayOnStart = false;
/**
* 手动初始化状态机可传入0-3个参数类型如下
@@ -23,7 +24,7 @@ export default class AnimatorCustomization extends AnimatorBase {
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this._hasInit) {
return;
}

View File

@@ -1,10 +1,11 @@
import { _decorator, dragonBones } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import { AnimatorStateLogic } from "./core/AnimatorStateLogic";
import { _decorator, dragonBones } from 'cc';
import type { AnimationPlayer } from './core/AnimatorBase';
import AnimatorBase from './core/AnimatorBase';
import type { AnimatorStateLogic } from './core/AnimatorStateLogic';
const { ccclass, property, requireComponent, disallowMultiple, menu, help } = _decorator;
/**
/**
* DragonBones状态机组件
*/
@ccclass
@@ -37,7 +38,7 @@ export default class AnimatorDragonBones extends AnimatorBase {
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}

View File

@@ -18,12 +18,12 @@ const { ccclass, property, requireComponent, disallowMultiple, menu, help } = _d
export class AnimatorSkeletal extends AnimatorAnimation {
@property({
type: CCFloat,
tooltip: "动画切换过度时间"
tooltip: '动画切换过度时间'
})
private duration: number = 0.3;
private duration = 0.3;
private cross_duration: number = 0; // 防止切换动画时间少于间隔时间导致动画状态错乱的问题
private current_time: number = 0; // 上一次切换状态时间
private cross_duration = 0; // 防止切换动画时间少于间隔时间导致动画状态错乱的问题
private current_time = 0; // 上一次切换状态时间
onLoad() {
this.cross_duration = this.duration * 1000;
@@ -56,6 +56,6 @@ export class AnimatorSkeletal extends AnimatorAnimation {
this._wrapModeMap.set(this._animState, this._animState.wrapMode);
}
// this._animState.wrapMode = loop ? 2 : this._wrapModeMap.get(this._animState)!;
this._animState.wrapMode = loop ? 2 : 1; // 2为循环播放1为单次播放
this._animState.wrapMode = loop ? 2 : 1; // 2为循环播放1为单次播放
}
}

View File

@@ -1,11 +1,12 @@
import { _decorator, sp } from "cc";
import AnimatorSpineSecondary from "./AnimatorSpineSecondary";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import { AnimatorStateLogic } from "./core/AnimatorStateLogic";
import { _decorator, sp } from 'cc';
import type AnimatorSpineSecondary from './AnimatorSpineSecondary';
import type { AnimationPlayer } from './core/AnimatorBase';
import AnimatorBase from './core/AnimatorBase';
import type { AnimatorStateLogic } from './core/AnimatorStateLogic';
const { ccclass, property, requireComponent, disallowMultiple, menu, help } = _decorator;
/**
/**
* Spine状态机组件主状态机trackIndex为0
*/
@ccclass
@@ -43,7 +44,7 @@ export default class AnimatorSpine extends AnimatorBase {
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
@@ -62,13 +63,13 @@ export default class AnimatorSpine extends AnimatorBase {
/** ---------- 后续扩展代码 开始 ---------- */
public getBone(name: string): any {
getBone(name: string): any {
const bone = this._spine.findBone(name);
return bone
return bone;
}
private onSpineEvent(trackEntry: any, event: any) {
const animationName = trackEntry.animation ? event.data.name : "";
const animationName = trackEntry.animation ? event.data.name : '';
this._animationPlayer?.onFrameEventCallback(animationName, this);
}
@@ -76,8 +77,12 @@ export default class AnimatorSpine extends AnimatorBase {
private onSpineComplete(entry: any) {
entry.trackIndex === 0 && this.onAnimFinished();
this._completeListenerMap.forEach((target, cb) => { target ? cb.call(target, entry) : cb(entry); });
this._secondaryListenerMap.forEach((target, cb) => { entry.trackIndex === target.TrackIndex && cb.call(target, entry); });
this._completeListenerMap.forEach((target, cb) => {
target ? cb.call(target, entry) : cb(entry);
});
this._secondaryListenerMap.forEach((target, cb) => {
entry.trackIndex === target.TrackIndex && cb.call(target, entry);
});
}
/**
@@ -108,7 +113,7 @@ export default class AnimatorSpine extends AnimatorBase {
/**
* 注册次状态机动画结束的回调(状态机内部方法,不能由外部直接调用)
*/
public addSecondaryListener(cb: (entry?: any) => void, target: AnimatorSpineSecondary) {
addSecondaryListener(cb: (entry?: any) => void, target: AnimatorSpineSecondary) {
this._secondaryListenerMap.set(cb, target);
}
@@ -117,7 +122,7 @@ export default class AnimatorSpine extends AnimatorBase {
* @param cb 回调
* @param target 调用回调的this对象
*/
public addCompleteListener(cb: (entry?: any) => void, target: any = null) {
addCompleteListener(cb: (entry?: any) => void, target: any = null) {
if (this._completeListenerMap.has(cb)) {
return;
}
@@ -128,14 +133,14 @@ export default class AnimatorSpine extends AnimatorBase {
* 注销动画完成的监听
* @param cb 回调
*/
public removeCompleteListener(cb: (entry?: any) => void) {
removeCompleteListener(cb: (entry?: any) => void) {
this._completeListenerMap.delete(cb);
}
/**
* 清空动画完成的监听
*/
public clearCompleteListener() {
clearCompleteListener() {
this._completeListenerMap.clear;
}
}

View File

@@ -1,11 +1,12 @@
import { _decorator, sp } from "cc";
import AnimatorSpine from "./AnimatorSpine";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import { AnimatorStateLogic } from "./core/AnimatorStateLogic";
import { _decorator, sp } from 'cc';
import AnimatorSpine from './AnimatorSpine';
import type { AnimationPlayer } from './core/AnimatorBase';
import AnimatorBase from './core/AnimatorBase';
import type { AnimatorStateLogic } from './core/AnimatorStateLogic';
const { ccclass, property, requireComponent, menu, help } = _decorator;
/**
/**
* Spine状态机组件次状态机同一节点可添加多个用于在不同track中播放动画trackIndex必须大于0
*/
@ccclass
@@ -13,7 +14,7 @@ const { ccclass, property, requireComponent, menu, help } = _decorator;
@menu('OopsFramework/Animator/AnimatorSpine Spine 次状态机)')
@help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12036279&doc_id=2873565')
export default class AnimatorSpineSecondary extends AnimatorBase {
@property({ tooltip: '动画播放的trackIndex必须大于0' }) TrackIndex: number = 1;
@property({ tooltip: '动画播放的trackIndex必须大于0' }) TrackIndex = 1;
/** 主状态机 */
private _main: AnimatorSpine = null!;
@@ -42,7 +43,7 @@ export default class AnimatorSpineSecondary extends AnimatorBase {
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}

View File

@@ -1,7 +1,7 @@
import { Component, JsonAsset, _decorator } from 'cc';
import AnimatorController from "./AnimatorController";
import AnimatorState from "./AnimatorState";
import { AnimatorStateLogic } from './AnimatorStateLogic';
import AnimatorController from './AnimatorController';
import type AnimatorState from './AnimatorState';
import type { AnimatorStateLogic } from './AnimatorStateLogic';
const { ccclass, property, executionOrder, menu } = _decorator;
@@ -36,16 +36,16 @@ export default class AnimatorBase extends Component {
/** ---------- 后续扩展代码 结束 ---------- */
@property({ type: JsonAsset, tooltip: '状态机json文件' })
AssetRawUrl: JsonAsset = null!;
AssetRawUrl: JsonAsset = null!;
@property({ tooltip: '是否在start中自动启动状态机' })
PlayOnStart: boolean = true;
PlayOnStart = true;
@property({ tooltip: '是否在update中自动触发状态机逻辑更新' })
AutoUpdate: boolean = true;
AutoUpdate = true;
/** 是否初始化 */
protected _hasInit: boolean = false;
protected _hasInit = false;
/** 状态机控制 */
protected _ac: AnimatorController = null!;
@@ -57,16 +57,16 @@ export default class AnimatorBase extends Component {
protected _animationPlayer: AnimationPlayer = null!;
/** 当前状态名 */
public get curStateName(): string {
get curStateName(): string {
return this._ac.curState.name;
}
/** 当前动画名 */
public get curStateMotion(): string {
get curStateMotion(): string {
return this._ac.curState.motion;
}
/** 获取指定状态 */
public getState(name: string): AnimatorState | undefined {
getState(name: string): AnimatorState | undefined {
return this._ac.states.get(name);
}
@@ -77,7 +77,7 @@ export default class AnimatorBase extends Component {
* - animationPlayer 自定义动画控制
* @virtual
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
}
/**
@@ -112,7 +112,7 @@ export default class AnimatorBase extends Component {
// 更新动画状态逻辑
if (this._stateLogicMap) {
let curLogic = this._stateLogicMap.get(this._ac.curState.name);
const curLogic = this._stateLogicMap.get(this._ac.curState.name);
curLogic && curLogic.onUpdate();
}
@@ -129,7 +129,7 @@ export default class AnimatorBase extends Component {
/**
* 手动调用更新
*/
public manualUpdate() {
manualUpdate() {
if (this._hasInit && !this.AutoUpdate) {
this.updateAnimator();
}
@@ -167,18 +167,18 @@ export default class AnimatorBase extends Component {
protected scaleTime(scale: number) {
}
/**
/**
* 状态切换时的逻辑(状态机内部方法,不能由外部直接调用)
*/
public onStateChange(fromState: AnimatorState, toState: AnimatorState) {
onStateChange(fromState: AnimatorState, toState: AnimatorState) {
this.playAnimation(toState.motion, toState.loop);
let fromStateName = fromState ? fromState.name : '';
const fromStateName = fromState ? fromState.name : '';
if (this._stateLogicMap) {
let fromLogic = this._stateLogicMap.get(fromStateName);
const fromLogic = this._stateLogicMap.get(fromStateName);
fromLogic && fromLogic.onExit();
let toLogic = this._stateLogicMap.get(toState.name);
const toLogic = this._stateLogicMap.get(toState.name);
toLogic && toLogic.onEntry();
}
@@ -188,49 +188,49 @@ export default class AnimatorBase extends Component {
/**
* 设置boolean类型参数的值
*/
public setBool(key: string, value: boolean) {
setBool(key: string, value: boolean) {
this._ac.params.setBool(key, value);
}
/**
* 获取boolean类型参数的值
*/
public getBool(key: string): boolean {
getBool(key: string): boolean {
return this._ac.params.getBool(key) !== 0;
}
/**
* 设置number类型参数的值
*/
public setNumber(key: string, value: number) {
setNumber(key: string, value: number) {
this._ac.params.setNumber(key, value);
}
/**
* 获取number类型参数的值
*/
public getNumber(key: string): number {
getNumber(key: string): number {
return this._ac.params.getNumber(key);
}
/**
* 设置trigger类型参数的值
*/
public setTrigger(key: string) {
setTrigger(key: string) {
this._ac.params.setTrigger(key);
}
/**
* 重置trigger类型参数的值
*/
public resetTrigger(key: string) {
resetTrigger(key: string) {
this._ac.params.resetTrigger(key);
}
/**
* 设置autoTrigger类型参数的值autoTrigger类型参数不需要主动reset每次状态机更新结束后会自动reset
*/
public autoTrigger(key: string) {
autoTrigger(key: string) {
this._ac.params.autoTrigger(key);
}
@@ -238,7 +238,7 @@ export default class AnimatorBase extends Component {
* 无视条件直接跳转状态
* @param 状态名
*/
public play(stateName: string) {
play(stateName: string) {
if (!this._hasInit) {
return;
}

View File

@@ -1,5 +1,5 @@
import { error } from "cc";
import AnimatorController from "./AnimatorController";
import { error } from 'cc';
import type AnimatorController from './AnimatorController';
/** 参数类型 */
export enum ParamType {
@@ -26,9 +26,9 @@ export enum LogicType {
export default class AnimatorCondition {
private _ac: AnimatorController;
/** 此条件对应的参数名 */
private _param: string = "";
private _param = '';
/** 此条件对应的值 */
private _value: number = 0;
private _value = 0;
/** 此条件与值比较的逻辑 */
private _logic: LogicType = LogicType.EQUAL;
@@ -39,42 +39,46 @@ export default class AnimatorCondition {
this._logic = data.logic;
}
public getParamName() {
getParamName() {
return this._param;
}
public getParamType(): ParamType {
getParamType(): ParamType {
return this._ac.params.getParamType(this._param);
}
/** 判断此条件是否满足 */
public check(): boolean {
let type: ParamType = this.getParamType();
check(): boolean {
const type: ParamType = this.getParamType();
if (type === ParamType.BOOLEAN) {
return this._ac.params.getBool(this._param) === this._value;
} else if (type === ParamType.NUMBER) {
let value: number = this._ac.params.getNumber(this._param);
}
else if (type === ParamType.NUMBER) {
const value: number = this._ac.params.getNumber(this._param);
switch (this._logic) {
case LogicType.EQUAL:
return value === this._value;
case LogicType.NOTEQUAL:
return value !== this._value;
case LogicType.GREATER:
return value > this._value;
case LogicType.LESS:
return value < this._value;
case LogicType.GREATER_EQUAL:
return value >= this._value;
case LogicType.LESS_EQUAL:
return value <= this._value;
default:
return false;
case LogicType.EQUAL:
return value === this._value;
case LogicType.NOTEQUAL:
return value !== this._value;
case LogicType.GREATER:
return value > this._value;
case LogicType.LESS:
return value < this._value;
case LogicType.GREATER_EQUAL:
return value >= this._value;
case LogicType.LESS_EQUAL:
return value <= this._value;
default:
return false;
}
} else if (type === ParamType.AUTO_TRIGGER) {
}
else if (type === ParamType.AUTO_TRIGGER) {
return this._ac.params.getAutoTrigger(this._param) !== 0;
} else if (type === ParamType.TRIGGER) {
}
else if (type === ParamType.TRIGGER) {
return this._ac.params.getTrigger(this._param) !== 0;
} else {
}
else {
error(`[AnimatorCondition.check] 错误的type: ${type}`);
return false;
}

View File

@@ -1,7 +1,7 @@
import { error } from "cc";
import AnimatorBase from "./AnimatorBase";
import AnimatorParams from "./AnimatorParams";
import AnimatorState from "./AnimatorState";
import { error } from 'cc';
import type AnimatorBase from './AnimatorBase';
import AnimatorParams from './AnimatorParams';
import AnimatorState from './AnimatorState';
/**
* 状态机控制类
@@ -16,15 +16,21 @@ export default class AnimatorController {
private _curState: AnimatorState = null!;
/** 状态切换次数 */
private _changeCount: number = 0;
private _changeCount = 0;
/** 对应animComplete的状态 */
public animCompleteState: AnimatorState = null!;
animCompleteState: AnimatorState = null!;
/** 动画播放完毕的标记 */
public animComplete: boolean = false;
animComplete = false;
/** 当前运行的状态 */
public get curState(): AnimatorState { return this._curState; }
public get params(): AnimatorParams { return this._params; }
public get states(): Map<string, AnimatorState> { return this._states }
get curState(): AnimatorState {
return this._curState;
}
get params(): AnimatorParams {
return this._params;
}
get states(): Map<string, AnimatorState> {
return this._states;
}
constructor(player: AnimatorBase, json: any) {
this._animator = player;
@@ -39,14 +45,14 @@ export default class AnimatorController {
*/
private init(json: any) {
if (json.states.length <= 0) {
error(`[AnimatorController.init] 状态机json错误`);
error('[AnimatorController.init] 状态机json错误');
return;
}
let defaultState: string = json.defaultState;
const defaultState: string = json.defaultState;
this._anyState = new AnimatorState(json.anyState, this);
for (let i = 0; i < json.states.length; i++) {
let state: AnimatorState = new AnimatorState(json.states[i], this);
const state: AnimatorState = new AnimatorState(json.states[i], this);
this._states.set(state.name, state);
}
this.changeState(defaultState);
@@ -62,7 +68,7 @@ export default class AnimatorController {
/**
* 更新状态机逻辑
*/
public updateAnimator() {
updateAnimator() {
// 重置计数
this._changeCount = 0;
@@ -76,7 +82,7 @@ export default class AnimatorController {
this.params.resetAllAutoTrigger();
}
public onAnimationComplete() {
onAnimationComplete() {
this.animComplete = true;
this.animCompleteState = this._curState;
// cc.log(`animation complete: ${this._curState.name}`);
@@ -86,7 +92,7 @@ export default class AnimatorController {
* 无视条件直接跳转状态
* @param 状态名
*/
public play(stateName: string) {
play(stateName: string) {
if (!this._states.has(stateName) || this._curState.name === stateName) {
return;
}
@@ -99,7 +105,7 @@ export default class AnimatorController {
/**
* 切换动画状态
*/
public changeState(stateName: string) {
changeState(stateName: string) {
this._changeCount++;
if (this._changeCount > 1000) {
error('[AnimatorController.changeState] error: 状态切换递归调用超过1000次transition设置可能出错!');
@@ -107,7 +113,7 @@ export default class AnimatorController {
}
if (this._states.has(stateName) && (this._curState === null || this._curState.name !== stateName)) {
let oldState = this._curState;
const oldState = this._curState;
this._curState = this._states.get(stateName)!;
this._animator.onStateChange(oldState, this._curState);

View File

@@ -1,4 +1,4 @@
import { ParamType } from "./AnimatorCondition";
import { ParamType } from './AnimatorCondition';
/**
* 参数结构
@@ -16,7 +16,7 @@ export default class AnimatorParams {
constructor(dataArr: any[]) {
dataArr.forEach((data: any) => {
let param: Param = {
const param: Param = {
type: data.type,
value: data.init
};
@@ -24,58 +24,59 @@ export default class AnimatorParams {
});
}
public getParamType(key: string): ParamType {
let param: Param = this._paramMap.get(key)!;
getParamType(key: string): ParamType {
const param: Param = this._paramMap.get(key)!;
if (param) {
return param.type;
} else {
}
else {
return null!;
}
}
public setNumber(key: string, value: number) {
let param: Param = this._paramMap.get(key)!;
setNumber(key: string, value: number) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.NUMBER) {
param.value = value;
}
}
public setBool(key: string, value: boolean) {
let param: Param = this._paramMap.get(key)!;
setBool(key: string, value: boolean) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.BOOLEAN) {
param.value = value ? 1 : 0;
}
}
public setTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
setTrigger(key: string) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
param.value = 1;
}
}
public resetTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
resetTrigger(key: string) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
param.value = 0;
}
}
public autoTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
autoTrigger(key: string) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
param.value = 1;
}
}
public resetAutoTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
resetAutoTrigger(key: string) {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
param.value = 0;
}
}
public resetAllAutoTrigger() {
resetAllAutoTrigger() {
this._paramMap.forEach((param: Param, key: string) => {
if (param.type === ParamType.AUTO_TRIGGER) {
param.value = 0;
@@ -83,38 +84,42 @@ export default class AnimatorParams {
});
}
public getNumber(key: string): number {
let param: Param = this._paramMap.get(key)!;
getNumber(key: string): number {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.NUMBER) {
return param.value;
} else {
}
else {
return 0;
}
}
public getBool(key: string): number {
let param: Param = this._paramMap.get(key)!;
getBool(key: string): number {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.BOOLEAN) {
return param.value;
} else {
}
else {
return 0;
}
}
public getTrigger(key: string): number {
let param: Param = this._paramMap.get(key)!;
getTrigger(key: string): number {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
return param.value;
} else {
}
else {
return 0;
}
}
public getAutoTrigger(key: string): number {
let param: Param = this._paramMap.get(key)!;
getAutoTrigger(key: string): number {
const param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
return param.value;
} else {
}
else {
return 0;
}
}

View File

@@ -1,30 +1,42 @@
import AnimatorController from "./AnimatorController";
import AnimatorTransition from "./AnimatorTransition";
import type AnimatorController from './AnimatorController';
import AnimatorTransition from './AnimatorTransition';
/**
* 状态管理类
*/
export default class AnimatorState {
private _name: string = "";
private _motion: string = "";
private _loop: boolean = false;
private _speed: number = 1;
private _multi: string = "";
private _name = '';
private _motion = '';
private _loop = false;
private _speed = 1;
private _multi = '';
private _transitions: AnimatorTransition[] = [];
private _ac: AnimatorController = null!;
/** 状态名 */
public get name() { return this._name; }
get name() {
return this._name;
}
/** 动画名 */
public get motion() { return this._motion; }
get motion() {
return this._motion;
}
/** 动画是否循环播放 */
public get loop() { return this._loop; }
get loop() {
return this._loop;
}
/** 动画播放速度的混合参数 */
public get multi() { return this._multi; }
get multi() {
return this._multi;
}
/** 动画播放速度 */
public get speed() { return this._speed; }
public set speed(value: number) { this._speed = value; }
get speed() {
return this._speed;
}
set speed(value: number) {
this._speed = value;
}
constructor(data: any, ac: AnimatorController) {
this._name = data.state;
@@ -36,7 +48,7 @@ export default class AnimatorState {
this._ac = ac;
for (let i = 0; i < data.transitions.length; i++) {
let transition: AnimatorTransition = new AnimatorTransition(data.transitions[i], ac);
const transition: AnimatorTransition = new AnimatorTransition(data.transitions[i], ac);
transition.isValid() && this._transitions.push(transition);
}
}
@@ -44,9 +56,9 @@ export default class AnimatorState {
/**
* 判断各个分支是否满足条件,满足则转换状态
*/
public checkAndTrans() {
checkAndTrans() {
for (let i = 0; i < this._transitions.length; i++) {
let transition: AnimatorTransition = this._transitions[i];
const transition: AnimatorTransition = this._transitions[i];
if (transition && transition.check()) {
transition.doTrans();
return;

View File

@@ -6,20 +6,20 @@ export class AnimatorStateLogic {
* 进入状态时调用
* @virtual
*/
public onEntry() {
onEntry() {
}
/**
* 每次状态机逻辑更新时调用
* @virtual
*/
public onUpdate() {
onUpdate() {
}
/**
* 离开状态时调用
* @virtual
*/
public onExit() {
onExit() {
}
}

View File

@@ -1,12 +1,12 @@
import AnimatorCondition, { ParamType } from "./AnimatorCondition";
import AnimatorController from "./AnimatorController";
import AnimatorCondition, { ParamType } from './AnimatorCondition';
import type AnimatorController from './AnimatorController';
/**
* 状态过渡类
*/
export default class AnimatorTransition {
private _toStateName: string = '';
private _hasExitTime: boolean = false;
private _toStateName = '';
private _hasExitTime = false;
private _conditions: AnimatorCondition[] = [];
private _ac: AnimatorController = null!;
@@ -15,7 +15,7 @@ export default class AnimatorTransition {
this._hasExitTime = data.hasExitTime;
this._ac = ac;
for (let i = 0; i < data.conditions.length; i++) {
let condition: AnimatorCondition = new AnimatorCondition(data.conditions[i], ac);
const condition: AnimatorCondition = new AnimatorCondition(data.conditions[i], ac);
this._conditions.push(condition);
}
}
@@ -23,14 +23,14 @@ export default class AnimatorTransition {
/**
* 返回该transition是否有效当未勾选hasExitTime以及没有添加任何condition时此transition无效并忽略
*/
public isValid(): boolean {
isValid(): boolean {
return this._hasExitTime || this._conditions.length > 0;
}
/**
* 判断是否满足所有转换条件
*/
public check(): boolean {
check(): boolean {
if (this._toStateName === this._ac.curState.name) {
return false;
}
@@ -50,18 +50,19 @@ export default class AnimatorTransition {
/**
* 转换状态
*/
public doTrans() {
doTrans() {
// 满足条件时重置动画播完标记
if (this._hasExitTime) {
this._ac.animComplete = false;
}
// 满足状态转换条件时重置trigger和autoTrigger
for (let i = 0; i < this._conditions.length; i++) {
let type = this._conditions[i].getParamType();
let name = this._conditions[i].getParamName();
const type = this._conditions[i].getParamType();
const name = this._conditions[i].getParamName();
if (type === ParamType.TRIGGER) {
this._ac.params.resetTrigger(name);
} else if (type === ParamType.AUTO_TRIGGER) {
}
else if (type === ParamType.AUTO_TRIGGER) {
this._ac.params.resetAutoTrigger(name);
}
}

View File

@@ -4,7 +4,7 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-07-20 14:04:44
*/
import { IControl } from './IControl';
import type { IControl } from './IControl';
/** 行为树节点 */
export abstract class BTreeNode implements IControl {
@@ -41,4 +41,4 @@ export abstract class BTreeNode implements IControl {
fail() {
this._control.fail();
}
}
}

View File

@@ -1,5 +1,5 @@
import { BTreeNode } from './BTreeNode';
import { IControl } from './IControl';
import type { IControl } from './IControl';
let countUnnamed = 0;
@@ -12,7 +12,7 @@ export class BehaviorTree implements IControl {
/** 当前执行节点 */
private _current!: BTreeNode;
/** 是否已开始执行 */
private _started: boolean = false;
private _started = false;
/** 外部参数对象 */
private _blackboard: any;

View File

@@ -30,7 +30,7 @@ export abstract class BranchNode extends BTreeNode {
}
run(blackboard?: any) {
if (this.children.length == 0) { // 没有子任务直接视为执行失败
if (this.children.length == 0) { // 没有子任务直接视为执行失败
this._control.fail();
}
else {
@@ -46,7 +46,7 @@ export abstract class BranchNode extends BTreeNode {
/** 执行当前节点逻辑 */
protected _run(blackboard?: any) {
var node = BehaviorTree.getNode(this.children[this._actualTask]);
const node = BehaviorTree.getNode(this.children[this._actualTask]);
this._runningNode = node;
node.setControl(this);
node.start(this._blackboard);

View File

@@ -7,15 +7,15 @@
import { BehaviorTree } from './BehaviorTree';
import { BTreeNode } from './BTreeNode';
/**
* 装饰器是条件语句只能附加在其他节点上并且定义所附加的节点是否执行
/**
* 装饰器是条件语句只能附加在其他节点上并且定义所附加的节点是否执行
* 如果装饰器是true 它所在的子树会被执行如果是false 所在的子树不会被执行
*/
export class Decorator extends BTreeNode {
node!: BTreeNode;
constructor(node?: string | BTreeNode) {
super()
super();
if (node)
this.node = BehaviorTree.getNode(node);

View File

@@ -14,7 +14,7 @@ export interface IControl {
/** 处理行为逻辑 */
run(blackboard?: any): void;
/** 正在处理中 */
running(blackboard?: any): void;
}
}

View File

@@ -6,18 +6,18 @@
*/
import { BranchNode } from './BranchNode';
/**
/**
* 逻辑或关系
* 只要子节点有一个返回true则停止执行其它子节点并且Selector返回true。如果所有子节点都返回false则Selector返回false。
*/
export class Selector extends BranchNode {
success() {
super.success()
super.success();
this._control.success();
}
fail() {
super.fail()
super.fail();
this._actualTask += 1;
if (this._actualTask < this.children.length) {

View File

@@ -5,9 +5,9 @@
* @LastEditTime: 2022-07-20 14:05:22
*/
import { BranchNode } from './BranchNode';
import { BTreeNode } from './BTreeNode';
import type { BTreeNode } from './BTreeNode';
/**
/**
* 逻辑与关系
* 只要有一个子节点返回false则停止执行其它子节点并且Sequence返回false。如果所有子节点都返回true则Sequence返回true。
*/

View File

@@ -5,4 +5,4 @@ export * from './BTreeNode';
export * from './Priority';
export * from './Sequence';
export * from './Task';
export * from './Selector';
export * from './Selector';

View File

@@ -9,7 +9,8 @@
* 6、只支持PC上使用
*/
import { CCFloat, Component, EventKeyboard, EventMouse, EventTouch, game, Input, input, KeyCode, math, _decorator } from 'cc';
import type { EventKeyboard, EventMouse, EventTouch } from 'cc';
import { CCFloat, Component, game, Input, input, KeyCode, math, _decorator } from 'cc';
const { ccclass, property, menu } = _decorator;
const { Vec2, Vec3, Quat } = math;
@@ -28,41 +29,41 @@ const KEYCODE = {
SHIFT: KeyCode.SHIFT_LEFT
};
@ccclass("FreeFlightCamera")
@ccclass('FreeFlightCamera')
@menu('OopsFramework/Camera/FreeFlightCamera (自由飞行摄像机)')
export class FreeFlightCamera extends Component {
@property({
type: CCFloat,
tooltip: "移动速度"
tooltip: '移动速度'
})
public moveSpeed: number = 1;
moveSpeed = 1;
@property({
type: CCFloat,
tooltip: "按Shift键后的速度"
tooltip: '按Shift键后的速度'
})
public moveSpeedShiftScale: number = 5;
moveSpeedShiftScale = 5;
@property({
type: CCFloat,
slide: true,
range: [0.05, 0.5, 0.01],
tooltip: "移动后惯性效果"
tooltip: '移动后惯性效果'
})
public damp: number = 0.2;
damp = 0.2;
@property({
type: CCFloat,
tooltip: "旋转速度"
tooltip: '旋转速度'
})
public rotateSpeed: number = 1;
rotateSpeed = 1;
public _euler = new Vec3();
public _velocity = new Vec3();
public _position = new Vec3();
public _speedScale = 1;
_euler = new Vec3();
_velocity = new Vec3();
_position = new Vec3();
_speedScale = 1;
public onLoad() {
onLoad() {
input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
@@ -74,7 +75,7 @@ export class FreeFlightCamera extends Component {
Vec3.copy(this._position, this.node.position);
}
public onDestroy() {
onDestroy() {
input.off(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
@@ -83,45 +84,97 @@ export class FreeFlightCamera extends Component {
input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
}
public update(dt: number) {
update(dt: number) {
// position
Vec3.transformQuat(v3_1, this._velocity, this.node.rotation);
Vec3.scaleAndAdd(this._position, this._position, v3_1, this.moveSpeed * this._speedScale);
Vec3.lerp(v3_1, this.node.position, this._position, dt / this.damp); // 向量线性插值产生位移惯性效果
Vec3.lerp(v3_1, this.node.position, this._position, dt / this.damp); // 向量线性插值产生位移惯性效果
this.node.setPosition(v3_1);
// rotation
Quat.fromEuler(qt_1, this._euler.x, this._euler.y, this._euler.z);
Quat.slerp(qt_1, this.node.rotation, qt_1, dt / this.damp); // 四元素线性插值产生旋转惯性效果
Quat.slerp(qt_1, this.node.rotation, qt_1, dt / this.damp); // 四元素线性插值产生旋转惯性效果
this.node.setRotation(qt_1);
}
public onMouseWheel(event: EventMouse) {
const delta = -event.getScrollY() * this.moveSpeed * 0.1; // 向下滚动时增量为正
onMouseWheel(event: EventMouse) {
const delta = -event.getScrollY() * this.moveSpeed * 0.1; // 向下滚动时增量为正
Vec3.transformQuat(v3_1, Vec3.UNIT_Z, this.node.rotation);
Vec3.scaleAndAdd(this._position, this.node.position, v3_1, delta);
}
public onKeyDown(event: EventKeyboard) {
onKeyDown(event: EventKeyboard) {
const v = this._velocity;
if (event.keyCode === KEYCODE.SHIFT) { this._speedScale = this.moveSpeedShiftScale; }
else if (event.keyCode === KEYCODE.W) { if (v.z === 0) { v.z = -1; } }
else if (event.keyCode === KEYCODE.S) { if (v.z === 0) { v.z = 1; } }
else if (event.keyCode === KEYCODE.A) { if (v.x === 0) { v.x = -1; } }
else if (event.keyCode === KEYCODE.D) { if (v.x === 0) { v.x = 1; } }
else if (event.keyCode === KEYCODE.Q) { if (v.y === 0) { v.y = -1; } }
else if (event.keyCode === KEYCODE.E) { if (v.y === 0) { v.y = 1; } }
if (event.keyCode === KEYCODE.SHIFT) {
this._speedScale = this.moveSpeedShiftScale;
}
else if (event.keyCode === KEYCODE.W) {
if (v.z === 0) {
v.z = -1;
}
}
else if (event.keyCode === KEYCODE.S) {
if (v.z === 0) {
v.z = 1;
}
}
else if (event.keyCode === KEYCODE.A) {
if (v.x === 0) {
v.x = -1;
}
}
else if (event.keyCode === KEYCODE.D) {
if (v.x === 0) {
v.x = 1;
}
}
else if (event.keyCode === KEYCODE.Q) {
if (v.y === 0) {
v.y = -1;
}
}
else if (event.keyCode === KEYCODE.E) {
if (v.y === 0) {
v.y = 1;
}
}
}
public onKeyUp(event: EventKeyboard) {
onKeyUp(event: EventKeyboard) {
const v = this._velocity;
if (event.keyCode === KEYCODE.SHIFT) { this._speedScale = 1; }
else if (event.keyCode === KEYCODE.W) { if (v.z < 0) { v.z = 0; } }
else if (event.keyCode === KEYCODE.S) { if (v.z > 0) { v.z = 0; } }
else if (event.keyCode === KEYCODE.A) { if (v.x < 0) { v.x = 0; } }
else if (event.keyCode === KEYCODE.D) { if (v.x > 0) { v.x = 0; } }
else if (event.keyCode === KEYCODE.Q) { if (v.y < 0) { v.y = 0; } }
else if (event.keyCode === KEYCODE.E) { if (v.y > 0) { v.y = 0; } }
if (event.keyCode === KEYCODE.SHIFT) {
this._speedScale = 1;
}
else if (event.keyCode === KEYCODE.W) {
if (v.z < 0) {
v.z = 0;
}
}
else if (event.keyCode === KEYCODE.S) {
if (v.z > 0) {
v.z = 0;
}
}
else if (event.keyCode === KEYCODE.A) {
if (v.x < 0) {
v.x = 0;
}
}
else if (event.keyCode === KEYCODE.D) {
if (v.x > 0) {
v.x = 0;
}
}
else if (event.keyCode === KEYCODE.Q) {
if (v.y < 0) {
v.y = 0;
}
}
else if (event.keyCode === KEYCODE.E) {
if (v.y > 0) {
v.y = 0;
}
}
}
private onTouchStart(e: EventTouch) {
@@ -130,12 +183,12 @@ export class FreeFlightCamera extends Component {
private onTouchMove(e: EventTouch) {
e.getStartLocation(v2_1);
if (v2_1.x > game.canvas!.width * 0.4) { // rotation
if (v2_1.x > game.canvas!.width * 0.4) { // rotation
e.getDelta(v2_2);
this._euler.y -= v2_2.x * this.rotateSpeed * 0.1; // 上下旋转
this._euler.x += v2_2.y * this.rotateSpeed * 0.1; // 左右旋转
this._euler.y -= v2_2.x * this.rotateSpeed * 0.1; // 上下旋转
this._euler.x += v2_2.y * this.rotateSpeed * 0.1; // 左右旋转
}
else { // position
else { // position
e.getLocation(v2_2);
Vec2.subtract(v2_2, v2_2, v2_1);
this._velocity.x = v2_2.x * 0.01;
@@ -149,9 +202,9 @@ export class FreeFlightCamera extends Component {
}
e.getStartLocation(v2_1);
if (v2_1.x < game.canvas!.width * 0.4) { // position
if (v2_1.x < game.canvas!.width * 0.4) { // position
this._velocity.x = 0;
this._velocity.z = 0;
}
}
}
}

View File

@@ -1,13 +1,14 @@
import { _decorator, Component, EventMouse, EventTouch, input, Input, lerp, Node, Quat, Vec2, Vec3 } from 'cc';
import type { EventMouse, EventTouch } from 'cc';
import { _decorator, Component, input, Input, lerp, Node, Quat, Vec2, Vec3 } from 'cc';
import { EDITOR } from 'cc/env';
const { ccclass, property, menu } = _decorator;
let tempVec3 = new Vec3;
let tempVec3_2 = new Vec3;
let tempQuat = new Quat;
const tempVec3 = new Vec3;
const tempVec3_2 = new Vec3;
const tempQuat = new Quat;
const DeltaFactor = 1 / 200;
/**
/**
* 轨道摄影机
* 1、触摸自由旋转
* 2、镜头远近鼠标滚轮调节
@@ -17,71 +18,71 @@ const DeltaFactor = 1 / 200;
@menu('OopsFramework/Camera/OrbitCamera (轨道摄影机)')
export class OrbitCamera extends Component {
@property({
tooltip: "是否启动触摸控制"
tooltip: '是否启动触摸控制'
})
enableTouch = true;
enableTouch = true;
@property({
tooltip: "是否开启启用缩放半径(鼠标滚轮控制摄像机与目标距离)"
tooltip: '是否开启启用缩放半径(鼠标滚轮控制摄像机与目标距离)'
})
enableScaleRadius = false;
enableScaleRadius = false;
@property({
tooltip: "摄像机与目标的半径缩放速度",
tooltip: '摄像机与目标的半径缩放速度',
visible: function () {
//@ts-ignore
return this.enableScaleRadius === true;
}
})
radiusScaleSpeed = 1;
radiusScaleSpeed = 1;
@property({
tooltip: "摄像机与目标的半径最小值",
tooltip: '摄像机与目标的半径最小值',
visible: function () {
//@ts-ignore
return this.enableScaleRadius === true;
}
})
minRadius = 5;
minRadius = 5;
@property({
tooltip: "摄像机与目标的半径最大值",
tooltip: '摄像机与目标的半径最大值',
visible: function () {
//@ts-ignore
return this.enableScaleRadius === true;
}
})
maxRadius = 10;
maxRadius = 10;
@property({
tooltip: "自动旋转是否开启"
tooltip: '自动旋转是否开启'
})
autoRotate = false;
autoRotate = false;
@property({
tooltip: "自动旋转速度",
tooltip: '自动旋转速度',
visible: function () {
//@ts-ignore
return this.autoRotate === true;
}
})
autoRotateSpeed = 90;
autoRotateSpeed = 90;
@property({
tooltip: "旋转速度"
tooltip: '旋转速度'
})
rotateSpeed = 1;
rotateSpeed = 1;
@property({
tooltip: "跟随速度"
tooltip: '跟随速度'
})
followSpeed = 1;
followSpeed = 1;
@property({
tooltip: "X轴旋转范围人物上下看的角度控制"
tooltip: 'X轴旋转范围人物上下看的角度控制'
})
xRotationRange = new Vec2(5, 70);
xRotationRange = new Vec2(5, 70);
@property
private _targetRadius = 10;
@property({
tooltip: "摄像机与目标的距离(以玩家为中心环绕球半径)"
tooltip: '摄像机与目标的距离(以玩家为中心环绕球半径)'
})
get radius(): number {
return this._targetRadius;
@@ -91,10 +92,10 @@ export class OrbitCamera extends Component {
}
@property
_target: Node = null!;
_target: Node = null!;
@property({
type: Node,
tooltip: "跟随目标"
tooltip: '跟随目标'
})
get target(): Node {
return this._target;
@@ -109,7 +110,7 @@ export class OrbitCamera extends Component {
private _startRotation = new Vec3;
@property({
type: Vec3,
tooltip: "目标旋转偏移量(初始旋转向量)"
tooltip: '目标旋转偏移量(初始旋转向量)'
})
get targetRotation(): Vec3 {
if (!EDITOR) {
@@ -123,16 +124,16 @@ export class OrbitCamera extends Component {
}
@property({
tooltip: "是否跟随目标 Y 轴旋转"
tooltip: '是否跟随目标 Y 轴旋转'
})
followTargetRotationY = false;
followTargetRotationY = false;
private _center = new Vec3; // 摄像机视口方向量
private _targetCenter = new Vec3; // 摄像机中心点位置(目标位置)
private _touched = false; // 是否触摸屏幕
private _targetRotation = new Vec3; // 目标旋转向量
private _rotation = new Quat; // 摄像机旋转四元素
private _radius = 10; // 当前玩家与目标半径距离
private _center = new Vec3; // 摄像机视口方向量
private _targetCenter = new Vec3; // 摄像机中心点位置(目标位置)
private _touched = false; // 是否触摸屏幕
private _targetRotation = new Vec3; // 目标旋转向量
private _rotation = new Quat; // 摄像机旋转四元素
private _radius = 10; // 当前玩家与目标半径距离
start() {
if (this.enableTouch) {
@@ -157,7 +158,7 @@ export class OrbitCamera extends Component {
this._radius = this.radius;
this.limitRotation()
this.limitRotation();
}
/** 重置摄像机到初始位置 */
@@ -172,13 +173,13 @@ export class OrbitCamera extends Component {
/** 限制 X 轴旋转(上下看) */
private limitRotation() {
let rotation = this._targetRotation;
const rotation = this._targetRotation;
if (rotation.x < this.xRotationRange.x) {
rotation.x = this.xRotationRange.x
rotation.x = this.xRotationRange.x;
}
else if (rotation.x > this.xRotationRange.y) {
rotation.x = this.xRotationRange.y
rotation.x = this.xRotationRange.y;
}
rotation.z = 0;
@@ -192,7 +193,7 @@ export class OrbitCamera extends Component {
private onTouchMove(event: EventTouch) {
if (!this._touched) return;
let delta = event.touch!.getDelta()
const delta = event.touch!.getDelta();
Quat.fromEuler(tempQuat, this._targetRotation.x, this._targetRotation.y, this._targetRotation.z);
Quat.rotateX(tempQuat, tempQuat, -delta.y * DeltaFactor);
@@ -208,8 +209,8 @@ export class OrbitCamera extends Component {
//#endregion
private onMouseWheel(event: EventMouse) {
let scrollY = event.getScrollY();
this._targetRadius += this.radiusScaleSpeed * -Math.sign(scrollY); // 滚轮向前为负,滚轮向后为正
const scrollY = event.getScrollY();
this._targetRadius += this.radiusScaleSpeed * -Math.sign(scrollY); // 滚轮向前为负,滚轮向后为正
this._targetRadius = Math.min(this.maxRadius, Math.max(this.minRadius, this._targetRadius));
}
@@ -228,23 +229,23 @@ export class OrbitCamera extends Component {
if (this.followTargetRotationY) {
targetRotation = tempVec3_2.set(targetRotation);
Quat.toEuler(tempVec3, this.target.worldRotation);
targetRotation.y += tempVec3.y; // 运行时,只变化 Y 旋转
targetRotation.y += tempVec3.y; // 运行时,只变化 Y 旋转
}
}
Quat.fromEuler(tempQuat, targetRotation.x, targetRotation.y, targetRotation.z); // 获取目标对象的旋转四元素(人物面向与摄像机一至)
Quat.fromEuler(tempQuat, targetRotation.x, targetRotation.y, targetRotation.z); // 获取目标对象的旋转四元素(人物面向与摄像机一至)
Quat.slerp(this._rotation, this._rotation, tempQuat, dt * 7 * this.rotateSpeed); // 旋转线性插值(平滑摄像机视口旋转)
Vec3.lerp(this._center, this._center, this._targetCenter, dt * 5 * this.followSpeed); // 摄像机跟随位移线性插值(平滑摄像机节点位置移动)
Quat.slerp(this._rotation, this._rotation, tempQuat, dt * 7 * this.rotateSpeed); // 旋转线性插值(平滑摄像机视口旋转)
Vec3.lerp(this._center, this._center, this._targetCenter, dt * 5 * this.followSpeed); // 摄像机跟随位移线性插值(平滑摄像机节点位置移动)
this._radius = lerp(this._radius, this._targetRadius, dt * 5); // 摄像机与目标距离半径线性插值(镜头平滑前后移动)
this._radius = lerp(this._radius, this._targetRadius, dt * 5); // 摄像机与目标距离半径线性插值(镜头平滑前后移动)
Vec3.transformQuat(tempVec3, Vec3.FORWARD, this._rotation); // 计算摄像机旋转后的方向量
Vec3.multiplyScalar(tempVec3, tempVec3, this._radius); // 计算摄像机与目标半径向量
tempVec3.add(this._center); // 计算摄像机与目标偏移后的位置
Vec3.transformQuat(tempVec3, Vec3.FORWARD, this._rotation); // 计算摄像机旋转后的方向量
Vec3.multiplyScalar(tempVec3, tempVec3, this._radius); // 计算摄像机与目标半径向量
tempVec3.add(this._center); // 计算摄像机与目标偏移后的位置
this.node.position = tempVec3; // 设置摄像机位置
this.node.lookAt(this._center); // 设置摄像机视口方向
this.node.position = tempVec3; // 设置摄像机位置
this.node.lookAt(this._center); // 设置摄像机视口方向
}
/** 摄像机立即跟随到制定目标的位置 */
@@ -259,21 +260,21 @@ export class OrbitCamera extends Component {
if (this.followTargetRotationY) {
targetRotation = tempVec3_2.set(targetRotation);
Quat.toEuler(tempVec3, this.target.worldRotation);
targetRotation.y += tempVec3.y; // 运行时,只变化 Y 旋转
targetRotation.y += tempVec3.y; // 运行时,只变化 Y 旋转
}
}
Quat.fromEuler(tempQuat, targetRotation.x, targetRotation.y, targetRotation.z); // 获取目标对象的旋转四元素(人物面向与摄像机一至)
Quat.fromEuler(tempQuat, targetRotation.x, targetRotation.y, targetRotation.z); // 获取目标对象的旋转四元素(人物面向与摄像机一至)
this._rotation = tempQuat;
this._center = this._targetCenter;
this._radius = this._targetRadius;
Vec3.transformQuat(tempVec3, Vec3.FORWARD, this._rotation); // 计算摄像机旋转后的方向量
Vec3.multiplyScalar(tempVec3, tempVec3, this._radius); // 计算摄像机与目标半径向量
tempVec3.add(this._center); // 计算摄像机与目标偏移后的位置
Vec3.transformQuat(tempVec3, Vec3.FORWARD, this._rotation); // 计算摄像机旋转后的方向量
Vec3.multiplyScalar(tempVec3, tempVec3, this._radius); // 计算摄像机与目标半径向量
tempVec3.add(this._center); // 计算摄像机与目标偏移后的位置
this.node.position = tempVec3; // 设置摄像机位置
this.node.lookAt(this._center); // 设置摄像机视口方向
this.node.position = tempVec3; // 设置摄像机位置
this.node.lookAt(this._center); // 设置摄像机视口方向
}
}
}

View File

@@ -1,4 +1,4 @@
import { log, warn } from "cc";
import { log, warn } from 'cc';
export type NextFunction = (nextArgs?: any) => void;
@@ -38,7 +38,7 @@ queue.play();
*/
export class AsyncQueue {
// 任务task的唯一标识
private static _$uuid_count: number = 1;
private static _$uuid_count = 1;
// 正在运行的任务
private _runningAsyncTask: AsyncTask | null = null;
@@ -51,8 +51,8 @@ export class AsyncQueue {
}
// 正在执行的异步任务标识
private _isProcessingTaskUUID: number = 0;
private _enable: boolean = true;
private _isProcessingTaskUUID = 0;
private _enable = true;
/** 是否开启可用 */
get enable() {
@@ -80,12 +80,12 @@ export class AsyncQueue {
* @param params 参数
*/
push(callback: AsyncCallback, params: any = null): number {
let uuid = AsyncQueue._$uuid_count++;
const uuid = AsyncQueue._$uuid_count++;
this._queues.push({
uuid: uuid,
callbacks: [callback],
params: params
})
});
return uuid;
}
@@ -93,15 +93,15 @@ export class AsyncQueue {
* 添加多个任务,多个任务函数会同时执行
* @param params 参数据
* @param callbacks 回调
* @returns
* @returns
*/
pushMulti(params: any, ...callbacks: AsyncCallback[]): number {
let uuid = AsyncQueue._$uuid_count++;
const uuid = AsyncQueue._$uuid_count++;
this._queues.push({
uuid: uuid,
callbacks: callbacks,
params: params
})
});
return uuid;
}
@@ -111,7 +111,7 @@ export class AsyncQueue {
*/
remove(uuid: number) {
if (this._runningAsyncTask?.uuid === uuid) {
warn("正在执行的任务不可以移除");
warn('正在执行的任务不可以移除');
return;
}
for (let i = 0; i < this._queues.length; i++) {
@@ -178,31 +178,31 @@ export class AsyncQueue {
return;
}
let actionData: AsyncTask = this._queues.shift()!;
const actionData: AsyncTask = this._queues.shift()!;
if (actionData) {
this._runningAsyncTask = actionData;
let taskUUID: number = actionData.uuid;
const taskUUID: number = actionData.uuid;
this._isProcessingTaskUUID = taskUUID;
let callbacks: Array<AsyncCallback> = actionData.callbacks;
const callbacks: Array<AsyncCallback> = actionData.callbacks;
if (callbacks.length == 1) {
let nextFunc: NextFunction = (nextArgs: any = null) => {
const nextFunc: NextFunction = (nextArgs: any = null) => {
this.next(taskUUID, nextArgs);
}
};
callbacks[0](nextFunc, actionData.params, args);
}
else {
// 多个任务函数同时执行
let fnum: number = callbacks.length;
let nextArgsArr: any[] = [];
let nextFunc: NextFunction = (nextArgs: any = null) => {
const nextArgsArr: any[] = [];
const nextFunc: NextFunction = (nextArgs: any = null) => {
--fnum;
nextArgsArr.push(nextArgs || null);
if (fnum === 0) {
this.next(taskUUID, nextArgsArr);
}
}
let knum = fnum;
};
const knum = fnum;
for (let i = 0; i < knum; i++) {
callbacks[i](nextFunc, actionData.params, args);
}
@@ -223,16 +223,16 @@ export class AsyncQueue {
* @param callback (可选参数)时间到了之后回调
*/
yieldTime(time: number, callback: Function | null = null) {
let task = function (next: Function, params: any, args: any) {
let _t = setTimeout(() => {
const task = function (next: Function, params: any, args: any) {
const _t = setTimeout(() => {
clearTimeout(_t);
if (callback) {
callback();
}
next(args);
}, time);
}
this.push(task, { des: "AsyncQueue.yieldTime" });
};
this.push(task, { des: 'AsyncQueue.yieldTime' });
}
protected next(taskUUID: number, args: any = null) {
@@ -250,18 +250,18 @@ export class AsyncQueue {
/**
* 返回一个执行函数执行函数调用count次后next将触发
* @param count
* @param next
* @param count
* @param next
* @return 返回一个匿名函数
*/
static excuteTimes(count: number, next: Function | null = null): Function {
let fnum: number = count;
let call = () => {
const call = () => {
--fnum;
if (fnum === 0) {
next && next();
}
}
};
return call;
}
}
}

View File

@@ -6,7 +6,7 @@
*/
/** 支持Map与Array功能的集合对象 */
export class Collection<K, V> extends Map<K, V>{
export class Collection<K, V> extends Map<K, V> {
private _array: V[] = [];
/** 获取数组对象 */
@@ -21,8 +21,8 @@ export class Collection<K, V> extends Map<K, V>{
*/
set(key: K, value: V) {
if (this.has(key)) {
var old = this.get(key)!;
var index = this._array.indexOf(old);
const old = this.get(key)!;
const index = this._array.indexOf(old);
this._array[index] = value;
}
else {
@@ -50,4 +50,4 @@ export class Collection<K, V> extends Map<K, V>{
this._array.splice(0, this._array.length);
super.clear();
}
}
}

View File

@@ -1,15 +1,16 @@
import { ECSComp } from "./ECSComp";
import { ECSEntity } from "./ECSEntity";
import { ECSMatcher } from "./ECSMatcher";
import { CompCtor, CompType, ECSModel, EntityCtor } from "./ECSModel";
import { ECSComblockSystem, ECSRootSystem, ECSSystem } from "./ECSSystem";
import { ECSComp } from './ECSComp';
import { ECSEntity } from './ECSEntity';
import { ECSMatcher } from './ECSMatcher';
import type { CompCtor, CompType, EntityCtor } from './ECSModel';
import { ECSModel } from './ECSModel';
import { ECSComblockSystem, ECSRootSystem, ECSSystem } from './ECSSystem';
/**
/**
* ECSEntity对象在destroy后会回收到ECSModel.entityPool实体对象池中
* ECSComp对象从ECSEntity.remove后数据组件会回收到ECSModel.compPools组件对象池中
*/
/**
/**
* Entity-Component-System实体-组件-系统)框架
* 文档https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12033388&doc_id=2873565
*/
@@ -122,15 +123,15 @@ export namespace ecs {
@ecs.register('RoleView', false)
export class RoleViewComp extends CCComp {
onLoad(){
}
}
*/
export function register<T>(name: string, canNew: boolean = true) {
export function register<T>(name: string, canNew = true) {
return function (ctor: any) {
// 注册系统
if (ctor.s) {
var system = ECSModel.systems.get(name);
let system = ECSModel.systems.get(name);
if (system == null) {
system = new ecs.System();
ECSModel.systems.set(name, system);
@@ -146,7 +147,7 @@ export namespace ecs {
if (ctor.tid === -1) {
ctor.tid = ECSModel.compTid++;
ctor.compName = name;
ECSModel.compCtors.push(ctor); // 注册不同类型的组件
ECSModel.compCtors.push(ctor); // 注册不同类型的组件
if (canNew) {
ECSModel.compPools.set(ctor.tid, []);
}
@@ -156,7 +157,7 @@ export namespace ecs {
throw new Error(`ECS 组件重复注册: ${name}.`);
}
}
}
};
}
/**
@@ -165,18 +166,18 @@ export namespace ecs {
*/
export function getEntity<T extends Entity>(ctor: EntityCtor<T>): T {
// 获取实体对象名
var entityName = ECSModel.entityCtors.get(ctor);
const entityName = ECSModel.entityCtors.get(ctor);
if (entityName == undefined)
console.error(`${ctor.name} 实体没有注册`);
// 获取实体对象池
var entitys = ECSModel.entityPool.get(entityName!) || [];
var entity: any = entitys.pop();
const entitys = ECSModel.entityPool.get(entityName!) || [];
let entity: any = entitys.pop();
// 缓存中没有同类实体,则创建一个新的
if (!entity) {
entity = new ctor();
entity.eid = ECSModel.eid++; // 实体唯一编号
entity.eid = ECSModel.eid++; // 实体唯一编号
entity.name = entityName;
}
@@ -215,7 +216,7 @@ export namespace ecs {
ECSModel.groups.forEach((group) => {
group.clear();
});
ECSModel.compAddOrRemove.forEach(callbackLst => {
ECSModel.compAddOrRemove.forEach((callbackLst) => {
callbackLst.length = 0;
});
ECSModel.eid2Entity.clear();
@@ -237,18 +238,18 @@ export namespace ecs {
/** 创建实体 */
function createEntity<E extends Entity = Entity>(): E {
let entity = new Entity();
entity.eid = ECSModel.eid++; // 实体id也是有限的资源
const entity = new Entity();
entity.eid = ECSModel.eid++; // 实体id也是有限的资源
ECSModel.eid2Entity.set(entity.eid, entity);
return entity as E;
}
/**
* 指定一个组件创建实体,返回组件对象。
* @param ctor
* @param ctor
*/
function createEntityWithComp<T extends IComp>(ctor: CompCtor<T>): T {
let entity = createEntity();
const entity = createEntity();
return entity.add(ctor);
}
@@ -256,7 +257,7 @@ export namespace ecs {
/**
* 表示只关心这些组件的添加和删除动作。虽然实体可能有这些组件之外的组件,但是它们的添加和删除没有被关注,所以不会存在对关注之外的组件
* 进行添加操作引发Group重复添加实体。
* @param args
* @param args
* @example
* ecs.allOf(AComponent, BComponent, CComponent);
*/
@@ -294,7 +295,7 @@ export namespace ecs {
* @param args 组件类
* @example
// 表示不包含组件A或者组件B
ecs.excludeOf(A, B);
ecs.excludeOf(A, B);
*/
export function excludeOf(...args: CompType<IComp>[]) {
return new ECSMatcher().excludeOf(...args);
@@ -308,7 +309,7 @@ export namespace ecs {
*/
export function getSingleton<T extends IComp>(ctor: CompCtor<T>) {
if (!ECSModel.tid2comp.has(ctor.tid)) {
let comp = createEntityWithComp(ctor) as T;
const comp = createEntityWithComp(ctor) as T;
ECSModel.tid2comp.set(ctor.tid, comp);
}
return ECSModel.tid2comp.get(ctor.tid) as T;
@@ -316,14 +317,14 @@ export namespace ecs {
/**
* 注册单例组件 - 主要用于那些不能手动创建对象的组件
* @param obj
* @param obj
*/
export function addSingleton(obj: IComp) {
let tid = (obj.constructor as CompCtor<IComp>).tid;
const tid = (obj.constructor as CompCtor<IComp>).tid;
if (!ECSModel.tid2comp.has(tid)) {
ECSModel.tid2comp.set(tid, obj);
}
}
//#endregion
}
}

View File

@@ -4,16 +4,16 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-05 14:03:54
*/
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import type { ecs } from './ECS';
import type { ECSEntity } from './ECSEntity';
/**
/**
* 组件抽象类
* 注:建议组件里面只放数据可能在实际写代码会碰到一些比较麻烦的问题,如果是单纯对组件内的数据操作可以在组件里面写方法
*/
export abstract class ECSComp implements ecs.IComp {
/** 组件的类型编号,-1表示未给该组件分配编号 */
static tid: number = -1;
static tid = -1;
/** 组件名 */
static compName: string;
@@ -21,15 +21,15 @@ export abstract class ECSComp implements ecs.IComp {
* 是否可回收组件对象,默认情况下都是可回收的
* 注如果该组件对象是由ecs系统外部创建的则不可回收需要用户自己手动进行回收
*/
canRecycle: boolean = true;
canRecycle = true;
/** 拥有该组件的实体 */
ent!: ECSEntity;
/** 组件的类型编号 */
tid: number = -1;
tid = -1;
/**
* 组件被回收时会调用这个接口。可以在这里重置数据,或者解除引用
* 注:不要偷懒,除非你能确定并保证组件在复用时,里面的数据是先赋值然后再使用
*/
abstract reset(): void;
}
}

View File

@@ -1,6 +1,7 @@
import { ecs } from "./ECS";
import { ECSMask } from "./ECSMask";
import { CompCtor, CompType, ECSModel } from "./ECSModel";
import type { ecs } from './ECS';
import { ECSMask } from './ECSMask';
import type { CompCtor, CompType } from './ECSModel';
import { ECSModel } from './ECSModel';
//#region 辅助方法
@@ -10,7 +11,7 @@ import { CompCtor, CompType, ECSModel } from "./ECSModel";
* @param componentTypeId 组件类型id
*/
function broadcastCompAddOrRemove(entity: ECSEntity, componentTypeId: number) {
let events = ECSModel.compAddOrRemove.get(componentTypeId);
const events = ECSModel.compAddOrRemove.get(componentTypeId);
for (let i = events!.length - 1; i >= 0; i--) {
events![i](entity);
}
@@ -29,16 +30,16 @@ function createComp<T extends ecs.IComp>(ctor: CompCtor<T>): T {
if (!cct) {
throw Error(`没有找到该组件的构造函数,检查${ctor.compName}是否为不可构造的组件`);
}
let comps = ECSModel.compPools.get(ctor.tid)!;
let component = comps.pop() || new (cct as CompCtor<T>);
const comps = ECSModel.compPools.get(ctor.tid)!;
const component = comps.pop() || new (cct as CompCtor<T>);
return component as T;
}
/**
* 销毁实体
*
*
* 缓存销毁的实体,下次新建实体时会优先从缓存中拿
* @param entity
* @param entity
*/
function destroyEntity(entity: ECSEntity) {
if (ECSModel.eid2Entity.has(entity.eid)) {
@@ -60,11 +61,11 @@ function destroyEntity(entity: ECSEntity) {
/** ECS实体对象 */
export class ECSEntity {
/** 实体唯一标识,不要手动修改 */
eid: number = -1;
eid = -1;
/** 实体对象名 */
name: string = "";
name = '';
/** 实体是否有效 */
isValid: boolean = true;
isValid = true;
/** 组件过滤数据 */
private mask = new ECSMask();
/** 当前实体身上附加的组件构造函数 */
@@ -111,7 +112,7 @@ export class ECSEntity {
* 移除子实体
* @param entity 被移除的实体对象
* @param isDestroy 被移除的实体是否释放,默认为释放
* @returns
* @returns
*/
removeChild(entity: ECSEntity, isDestroy = true) {
if (this.childs == null) return;
@@ -123,20 +124,20 @@ export class ECSEntity {
/**
* 根据组件类动态创建组件,并通知关心的系统。如果实体存在了这个组件,那么会先删除之前的组件然后添加新的
*
*
* 注意不要直接new Componentnew来的Component不会从Component的缓存池拿缓存的数据
* @param componentTypeId 组件类
* @param isReAdd true-表示用户指定这个实体可能已经存在了该组件那么再次add组件的时候会先移除该组件然后再添加一遍。false-表示不重复添加组件
*/
add<T extends ecs.IComp>(obj: T): ECSEntity;
add<T extends ecs.IComp>(ctor: CompType<T>, isReAdd?: boolean): T;
add<T extends ecs.IComp>(ctor: CompType<T> | T, isReAdd: boolean = false): T | ECSEntity {
add<T extends ecs.IComp>(ctor: CompType<T> | T, isReAdd = false): T | ECSEntity {
if (typeof ctor === 'function') {
let compTid = ctor.tid;
const compTid = ctor.tid;
if (ctor.tid === -1) {
throw Error(`${this.name}】实体【${ctor.compName}】组件未注册`);
}
if (this.compTid2Ctor.has(compTid)) { // 判断是否有该组件,如果有则先移除
if (this.compTid2Ctor.has(compTid)) { // 判断是否有该组件,如果有则先移除
if (isReAdd) {
this.remove(ctor);
}
@@ -170,8 +171,8 @@ export class ECSEntity {
return comp;
}
else {
let tmpCtor = (ctor.constructor as CompCtor<T>);
let compTid = tmpCtor.tid;
const tmpCtor = (ctor.constructor as CompCtor<T>);
const compTid = tmpCtor.tid;
// console.assert(compTid !== -1 || !compTid, '组件未注册!');
// console.assert(this.compTid2Ctor.has(compTid), '已存在该组件!');
if (compTid === -1 || compTid == null) throw Error(`${this.name}】实体【${tmpCtor.name}】组件未注册`);
@@ -196,10 +197,10 @@ export class ECSEntity {
/**
* 批量添加组件
* @param ctors 组件类
* @returns
* @returns
*/
addComponents<T extends ecs.IComp>(...ctors: CompType<T>[]) {
for (let ctor of ctors) {
for (const ctor of ctors) {
this.add(ctor);
}
return this;
@@ -221,7 +222,7 @@ export class ECSEntity {
* @param ctor 组件类
*/
has(ctor: CompType<ecs.IComp>): boolean {
if (typeof ctor == "number") {
if (typeof ctor === 'number') {
return this.mask.has(ctor);
}
else {
@@ -236,16 +237,16 @@ export class ECSEntity {
* 设置该参数为false这样该组件对象会缓存在实体身上下次重新添加组件时会将该组件对象添加回来不会重新从组件缓存
* 池中拿一个组件来用。
*/
remove(ctor: CompType<ecs.IComp>, isRecycle: boolean = true) {
remove(ctor: CompType<ecs.IComp>, isRecycle = true) {
let hasComp = false;
//@ts-ignore
let componentTypeId = ctor.tid;
const componentTypeId = ctor.tid;
//@ts-ignore
let compName = ctor.compName;
const compName = ctor.compName;
if (this.mask.has(componentTypeId)) {
hasComp = true;
//@ts-ignore
let comp = this[ctor.compName];
const comp = this[ctor.compName];
//@ts-ignore
comp.ent = null;
if (isRecycle) {
@@ -258,7 +259,7 @@ export class ECSEntity {
}
}
else {
this.compTid2Obj.set(componentTypeId, comp); // 用于缓存显示对象组件
this.compTid2Obj.set(componentTypeId, comp); // 用于缓存显示对象组件
}
}
@@ -284,7 +285,7 @@ export class ECSEntity {
// 移除模块上所有子模块
if (this.childs) {
this.childs.forEach(e => {
this.childs.forEach((e) => {
this.removeChild(e);
});
this.childs = null!;
@@ -299,4 +300,4 @@ export class ECSEntity {
private _remove(comp: CompType<ecs.IComp>) {
this.remove(comp, true);
}
}
}

View File

@@ -4,8 +4,8 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-05 14:21:54
*/
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import type { ecs } from './ECS';
import type { ECSEntity } from './ECSEntity';
export class ECSGroup<E extends ECSEntity = ECSEntity> {
/** 实体筛选规则 */
@@ -27,7 +27,7 @@ export class ECSGroup<E extends ECSEntity = ECSEntity> {
/**
* 当前group中实体的数量
*
*
* 注:不要手动修改这个属性值。
* 注其实可以通过this._matchEntities.size获得实体数量但是需要封装get方法。为了减少一次方法的调用所以才直接创建一个count属性
*/
@@ -46,7 +46,7 @@ export class ECSGroup<E extends ECSEntity = ECSEntity> {
}
onComponentAddOrRemove(entity: E) {
if (this.matcher.isMatch(entity)) { // Group只关心指定组件在实体身上的添加和删除动作。
if (this.matcher.isMatch(entity)) { // Group只关心指定组件在实体身上的添加和删除动作。
this._matchEntities.set(entity.eid, entity);
this._entitiesCache = null;
this.count++;
@@ -56,7 +56,7 @@ export class ECSGroup<E extends ECSEntity = ECSEntity> {
this._removedEntities!.delete(entity.eid);
}
}
else if (this._matchEntities.has(entity.eid)) { // 如果Group中有这个实体但是这个实体已经不满足匹配规则则从Group中移除该实体
else if (this._matchEntities.has(entity.eid)) { // 如果Group中有这个实体但是这个实体已经不满足匹配规则则从Group中移除该实体
this._matchEntities.delete(entity.eid);
this._entitiesCache = null;
this.count--;
@@ -80,4 +80,4 @@ export class ECSGroup<E extends ECSEntity = ECSEntity> {
this._enteredEntities?.clear();
this._removedEntities?.clear();
}
}
}

View File

@@ -4,14 +4,14 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-05-24 11:09:49
*/
import { ECSModel } from "./ECSModel";
import { ECSModel } from './ECSModel';
export class ECSMask {
private mask: Uint32Array;
private size: number = 0;
private size = 0;
constructor() {
let length = Math.ceil(ECSModel.compTid / 31);
const length = Math.ceil(ECSModel.compTid / 31);
this.mask = new Uint32Array(length);
this.size = length;
}
@@ -54,4 +54,4 @@ export class ECSMask {
this.mask[i] = 0;
}
}
}
}

View File

@@ -1,9 +1,10 @@
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSMask } from "./ECSMask";
import { CompCtor, CompType, ECSModel } from "./ECSModel";
import type { ecs } from './ECS';
import type { ECSEntity } from './ECSEntity';
import { ECSMask } from './ECSMask';
import type { CompCtor, CompType } from './ECSModel';
import { ECSModel } from './ECSModel';
let macherId: number = 1;
let macherId = 1;
/**
* 筛选规则间是“与”的关系
@@ -12,17 +13,17 @@ let macherId: number = 1;
export class ECSMatcher implements ecs.IMatcher {
protected rules: BaseOf[] = [];
protected _indices: number[] | null = null;
public isMatch!: (entity: ECSEntity) => boolean;
public mid: number = -1;
isMatch!: (entity: ECSEntity) => boolean;
mid = -1;
private _key: string | null = null;
public get key(): string {
get key(): string {
if (!this._key) {
let s = '';
for (let i = 0; i < this.rules.length; i++) {
s += this.rules[i].getKey()
s += this.rules[i].getKey();
if (i < this.rules.length - 1) {
s += ' && '
s += ' && ';
}
}
this._key = s;
@@ -69,15 +70,15 @@ export class ECSMatcher implements ecs.IMatcher {
/**
* 表示关注只拥有这些组件的实体
*
*
* 注意:
* 不是特殊情况不建议使用onlyOf。因为onlyOf会监听所有组件的添加和删除事件。
* @param args 组件索引
*/
onlyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
this.rules.push(new AllOf(...args));
let otherTids: CompType<ecs.IComp>[] = [];
for (let ctor of ECSModel.compCtors) {
const otherTids: CompType<ecs.IComp>[] = [];
for (const ctor of ECSModel.compCtors) {
if (args.indexOf(ctor) < 0) {
otherTids.push(ctor);
}
@@ -89,7 +90,7 @@ export class ECSMatcher implements ecs.IMatcher {
/**
* 不包含指定的任意一个组件
* @param args
* @param args
*/
excludeOf(...args: CompType<ecs.IComp>[]) {
this.rules.push(new ExcludeOf(...args));
@@ -118,7 +119,7 @@ export class ECSMatcher implements ecs.IMatcher {
}
private isMatchMore(entity: ECSEntity): boolean {
for (let rule of this.rules) {
for (const rule of this.rules) {
if (!rule.isMatch(entity)) {
return false;
}
@@ -127,9 +128,9 @@ export class ECSMatcher implements ecs.IMatcher {
}
clone(): ECSMatcher {
let newMatcher = new ECSMatcher();
const newMatcher = new ECSMatcher();
newMatcher.mid = macherId++;
this.rules.forEach(rule => newMatcher.rules.push(rule));
this.rules.forEach((rule) => newMatcher.rules.push(rule));
return newMatcher;
}
}
@@ -141,9 +142,9 @@ abstract class BaseOf {
constructor(...args: CompType<ecs.IComp>[]) {
let componentTypeId = -1;
let len = args.length;
const len = args.length;
for (let i = 0; i < len; i++) {
if (typeof (args[i]) === "number") {
if (typeof (args[i]) === 'number') {
componentTypeId = args[i] as number;
}
else {
@@ -159,7 +160,9 @@ abstract class BaseOf {
}
}
if (len > 1) {
this.indices.sort((a, b) => { return a - b; }); // 对组件类型id进行排序这样关注相同组件的系统就能共用同一个group
this.indices.sort((a, b) => {
return a - b;
}); // 对组件类型id进行排序这样关注相同组件的系统就能共用同一个group
}
}
@@ -176,7 +179,7 @@ abstract class BaseOf {
* 用于描述包含任意一个这些组件的实体
*/
class AnyOf extends BaseOf {
public isMatch(entity: ECSEntity): boolean {
isMatch(entity: ECSEntity): boolean {
// @ts-ignore
return this.mask.or(entity.mask);
}
@@ -190,7 +193,7 @@ class AnyOf extends BaseOf {
* 用于描述包含了“这些”组件的实体,这个实体除了包含这些组件还可以包含其他组件
*/
class AllOf extends BaseOf {
public isMatch(entity: ECSEntity): boolean {
isMatch(entity: ECSEntity): boolean {
// @ts-ignore
return this.mask.and(entity.mask);
}
@@ -204,12 +207,12 @@ class AllOf extends BaseOf {
* 不包含指定的任意一个组件
*/
class ExcludeOf extends BaseOf {
public getKey(): string {
getKey(): string {
return 'excludeOf:' + this.toString();
}
public isMatch(entity: ECSEntity): boolean {
isMatch(entity: ECSEntity): boolean {
// @ts-ignore
return !this.mask.or(entity.mask);
}
}
}

View File

@@ -4,9 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2022-09-05 16:37:10
*/
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSGroup } from "./ECSGroup";
import type { ecs } from './ECS';
import type { ECSEntity } from './ECSEntity';
import { ECSGroup } from './ECSGroup';
type CompAddOrRemove = (entity: ecs.Entity) => void;
@@ -55,7 +55,7 @@ export class ECSModel {
/**
* 缓存的group
*
*
* key是组件的筛选规则一个筛选规则对应一个group
*/
static groups: Map<number, ECSGroup> = new Map();
@@ -69,7 +69,7 @@ export class ECSModel {
if (!group) {
group = new ECSGroup(matcher);
ECSModel.groups.set(matcher.mid, group);
let careComponentTypeIds = matcher.indices;
const careComponentTypeIds = matcher.indices;
for (let i = 0; i < careComponentTypeIds.length; i++) {
ECSModel.compAddOrRemove.get(careComponentTypeIds[i])!.push(group.onComponentAddOrRemove.bind(group));
}
@@ -79,4 +79,4 @@ export class ECSModel {
/** 系统组件 */
static systems: Map<string, ecs.System> = new Map<string, ecs.System>();
}
}

View File

@@ -1,33 +1,33 @@
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSGroup } from "./ECSGroup";
import { ECSModel } from "./ECSModel";
import type { ecs } from './ECS';
import type { ECSEntity } from './ECSEntity';
import type { ECSGroup } from './ECSGroup';
import { ECSModel } from './ECSModel';
/** 继承此类实现具体业务逻辑的系统 */
export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
static s: boolean = true;
static s = true;
protected group: ECSGroup<E>;
protected dt: number = 0;
protected dt = 0;
private enteredEntities: Map<number, E> = null!;
private removedEntities: Map<number, E> = null!;
private hasEntityEnter: boolean = false;
private hasEntityRemove: boolean = false;
private hasUpdate: boolean = false;
private hasEntityEnter = false;
private hasEntityRemove = false;
private hasUpdate = false;
private tmpExecute: ((dt: number) => void) | null = null;
private execute!: (dt: number) => void;
/** 构造函数 */
constructor() {
let hasOwnProperty = Object.hasOwnProperty;
let prototype = Object.getPrototypeOf(this);
let hasEntityEnter = hasOwnProperty.call(prototype, 'entityEnter');
let hasEntityRemove = hasOwnProperty.call(prototype, 'entityRemove');
let hasFirstUpdate = hasOwnProperty.call(prototype, 'firstUpdate');
let hasUpdate = hasOwnProperty.call(prototype, 'update');
const hasOwnProperty = Object.hasOwnProperty;
const prototype = Object.getPrototypeOf(this);
const hasEntityEnter = hasOwnProperty.call(prototype, 'entityEnter');
const hasEntityRemove = hasOwnProperty.call(prototype, 'entityRemove');
const hasFirstUpdate = hasOwnProperty.call(prototype, 'firstUpdate');
const hasUpdate = hasOwnProperty.call(prototype, 'update');
this.hasEntityEnter = hasEntityEnter;
this.hasEntityRemove = hasEntityRemove;
@@ -69,8 +69,8 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
/**
* 先执行entityEnter最后执行firstUpdate
* @param dt
* @returns
* @param dt
* @returns
*/
private updateOnce(dt: number) {
if (this.group.count === 0) {
@@ -81,15 +81,15 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
// 处理刚进来的实体
if (this.enteredEntities.size > 0) {
var entities = this.enteredEntities.values();
for (let entity of entities) {
const entities = this.enteredEntities.values();
for (const entity of entities) {
(this as unknown as ecs.IEntityEnterSystem).entityEnter(entity);
}
this.enteredEntities.clear();
}
// 只执行firstUpdate
for (let entity of this.group.matchEntities) {
for (const entity of this.group.matchEntities) {
(this as unknown as ecs.ISystemFirstUpdate).firstUpdate(entity);
}
@@ -100,8 +100,8 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
/**
* 只执行update
* @param dt
* @returns
* @param dt
* @returns
*/
private execute0(dt: number): void {
if (this.group.count === 0) return;
@@ -110,7 +110,7 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
// 执行update
if (this.hasUpdate) {
for (let entity of this.group.matchEntities) {
for (const entity of this.group.matchEntities) {
(this as unknown as ecs.ISystemUpdate).update(entity);
}
}
@@ -118,15 +118,15 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
/**
* 先执行entityRemove再执行entityEnter最后执行update
* @param dt
* @returns
* @param dt
* @returns
*/
private execute1(dt: number): void {
let entities;
if (this.removedEntities.size > 0) {
if (this.hasEntityRemove) {
entities = this.removedEntities.values();
for (let entity of entities) {
for (const entity of entities) {
(this as unknown as ecs.IEntityRemoveSystem).entityRemove(entity);
}
}
@@ -141,7 +141,7 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
if (this.enteredEntities!.size > 0) {
if (this.hasEntityEnter) {
entities = this.enteredEntities!.values();
for (let entity of entities) {
for (const entity of entities) {
(this as unknown as ecs.IEntityEnterSystem).entityEnter(entity);
}
}
@@ -150,7 +150,7 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
// 执行update
if (this.hasUpdate) {
for (let entity of this.group.matchEntities) {
for (const entity of this.group.matchEntities) {
(this as unknown as ecs.ISystemUpdate).update(entity);
}
}
@@ -158,7 +158,7 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
/**
* 实体过滤规则
*
*
* 根据提供的组件过滤实体。
*/
abstract filter(): ecs.IMatcher;
@@ -167,7 +167,7 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
/** 根System对游戏中的System遍历从这里开始一个System组合中只能有一个RootSystem可以有多个并行的RootSystem */
export class ECSRootSystem {
private executeSystemFlows: ECSComblockSystem[] = [];
private systemCnt: number = 0;
private systemCnt = 0;
add(system: ECSSystem | ECSComblockSystem) {
if (system instanceof ECSSystem) {
@@ -183,10 +183,10 @@ export class ECSRootSystem {
init() {
// 自动注册系统组件
ECSModel.systems.forEach(sys => this.add(sys));
ECSModel.systems.forEach((sys) => this.add(sys));
// 初始化组件
this.executeSystemFlows.forEach(sys => sys.init());
this.executeSystemFlows.forEach((sys) => sys.init());
}
execute(dt: number) {
@@ -197,7 +197,7 @@ export class ECSRootSystem {
}
clear() {
this.executeSystemFlows.forEach(sys => sys.onDestroy());
this.executeSystemFlows.forEach((sys) => sys.onDestroy());
}
}
@@ -218,4 +218,4 @@ export class ECSSystem {
}
return this;
}
}
}

View File

@@ -80,7 +80,7 @@ declare global {
!Array.prototype.__cc_extended && Object.defineProperties(Array.prototype, {
remove: {
value: function (filter: any) {
if (typeof (filter) == 'function') {
if (typeof (filter) === 'function') {
for (let i = this.length - 1; i > -1; --i) {
filter(this[i], i, this) && this.splice(i, 1);
}
@@ -95,7 +95,7 @@ declare global {
},
removeOne: {
value: function (filter: any) {
if (typeof (filter) == 'function') {
if (typeof (filter) === 'function') {
for (let i = 0; i < this.length; ++i) {
if (filter(this[i], i, this)) {
this.splice(i, 1);
@@ -116,7 +116,7 @@ declare global {
},
random: {
value: function () {
let element = this[Math.floor(Math.random() * this.length)];
const element = this[Math.floor(Math.random() * this.length)];
return element;
}
},
@@ -126,7 +126,7 @@ declare global {
if (index < 0 || index >= length) {
return null;
}
let res = this[index];
const res = this[index];
this[index] = this[length - 1];
this.length = length - 1;
return res;
@@ -161,16 +161,18 @@ declare global {
function _max(a: number, b: number) {
return a > b ? a : b;
}
if (typeof (mapper) == 'function') {
if (typeof (mapper) === 'function') {
let max = mapper(this[0], 0, this);
for (let i = 1; i < this.length; ++i) {
let temp = mapper(this[i], i, this);
const temp = mapper(this[i], i, this);
max = temp > max ? temp : max;
}
return max;
}
else {
return this.reduce(function (prev: any, cur: any) { return _max(prev, cur); });
return this.reduce((prev: any, cur: any) => {
return _max(prev, cur);
});
}
}
},
@@ -182,27 +184,31 @@ declare global {
function _min(a: number, b: number) {
return a < b ? a : b;
}
if (typeof (mapper) == 'function') {
if (typeof (mapper) === 'function') {
let min = mapper(this[0], 0, this);
for (let i = 1; i < this.length; ++i) {
let temp = mapper(this[i], i, this);
const temp = mapper(this[i], i, this);
min = temp < min ? temp : min;
}
return min;
}
else {
return this.reduce(function (prev: any, cur: any) { return _min(prev, cur); });
return this.reduce((prev: any, cur: any) => {
return _min(prev, cur);
});
}
}
},
distinct: {
value: function () {
return this.filter(function (v: any, i: number, arr: any[]) { return arr.indexOf(v) === i; });
return this.filter((v: any, i: number, arr: any[]) => {
return arr.indexOf(v) === i;
});
}
},
filterIndex: {
value: function (filter: any) {
let output = [];
const output = [];
for (let i = 0; i < this.length; ++i) {
if (filter(this[i], i, this)) {
output.push(i);
@@ -238,14 +244,14 @@ declare global {
},
orderBy: {
value: function () {
let mappers = [];
const mappers = [];
for (let _i = 0; _i < arguments.length; _i++) {
mappers[_i] = arguments[_i];
}
return this.slice().sort(function (a: any, b: any) {
return this.slice().sort((a: any, b: any) => {
for (let i = 0; i < mappers.length; ++i) {
let va = mappers[i](a);
let vb = mappers[i](b);
const va = mappers[i](a);
const vb = mappers[i](b);
if (va > vb) {
return 1;
}
@@ -259,14 +265,14 @@ declare global {
},
orderByDesc: {
value: function () {
let mappers = [];
const mappers = [];
for (let _i = 0; _i < arguments.length; _i++) {
mappers[_i] = arguments[_i];
}
return this.slice().sort(function (a: any, b: any) {
return this.slice().sort((a: any, b: any) => {
for (let i = 0; i < mappers.length; ++i) {
let va = mappers[i](a);
let vb = mappers[i](b);
const va = mappers[i](a);
const vb = mappers[i](b);
if (va > vb) {
return -1;
}
@@ -282,8 +288,8 @@ declare global {
value: function (value: any, keyMapper: any) {
let low = 0, high = this.length - 1;
while (low <= high) {
let mid = ((high + low) / 2) | 0;
let midValue = keyMapper ? keyMapper(this[mid]) : this[mid];
const mid = ((high + low) / 2) | 0;
const midValue = keyMapper ? keyMapper(this[mid]) : this[mid];
if (value === midValue) {
return mid;
}
@@ -299,16 +305,16 @@ declare global {
},
binaryInsert: {
value: function (item: any, keyMapper: any, unique: any) {
if (typeof (keyMapper) == 'boolean') {
if (typeof (keyMapper) === 'boolean') {
unique = keyMapper;
keyMapper = undefined;
}
let low = 0, high = this.length - 1;
let mid = NaN;
let itemValue = keyMapper ? keyMapper(item) : item;
const itemValue = keyMapper ? keyMapper(item) : item;
while (low <= high) {
mid = ((high + low) / 2) | 0;
let midValue = keyMapper ? keyMapper(this[mid]) : this[mid];
const midValue = keyMapper ? keyMapper(this[mid]) : this[mid];
if (itemValue === midValue) {
if (unique) {
return mid;
@@ -324,14 +330,16 @@ declare global {
high = mid - 1;
}
}
let index = low > mid ? mid + 1 : mid;
const index = low > mid ? mid + 1 : mid;
this.splice(index, 0, item);
return index;
}
},
binaryDistinct: {
value: function (keyMapper: any) {
return this.filter(function (v: any, i: number, arr: any[]) { return arr.binarySearch(v, keyMapper) === i; });
return this.filter((v: any, i: number, arr: any[]) => {
return arr.binarySearch(v, keyMapper) === i;
});
}
},
findLast: {
@@ -356,16 +364,16 @@ declare global {
},
groupBy: {
value: function (grouper: any) {
let group = this.reduce(function (prev: any, next: any) {
let groupKey = grouper(next);
const group = this.reduce((prev: any, next: any) => {
const groupKey = grouper(next);
if (!prev[groupKey]) {
prev[groupKey] = [];
}
prev[groupKey].push(next);
return prev;
}, {});
return Object.keys(group).map(function (key) {
let arr = group[key];
return Object.keys(group).map((key) => {
const arr = group[key];
arr.key = key;
return arr;
});

View File

@@ -53,11 +53,11 @@ Date.prototype.format = function (format: string): string {
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;
let t1 = -1;
let t2 = -1;
if (d1 instanceof Date)
t1 = d1.getTime();
else
@@ -67,11 +67,11 @@ Date.prototype.range = function (d1: number | Date, d2: number | Date): boolean
else
t2 = d2;
let now = this.getTime();
const now = this.getTime();
if (now >= t1 && now < t2) {
return true;
}
return false;
}
};
export { };
export { };

Some files were not shown because too many files have changed in this diff Show More