1.规范化框架业务模板的提示信息

2.废弃GameCollision.ts
This commit is contained in:
dgflash
2026-04-05 11:05:58 +08:00
parent 9a4fd82dcf
commit b32c550b15
5 changed files with 88 additions and 129 deletions

View File

@@ -11,7 +11,26 @@ import type { CCEntity } from './CCEntity';
/** 业务逻辑 */
export class CCBusiness<T extends CCEntity> {
ent!: T;
private _destroyed: boolean = false;
/** 当前业务逻辑是否有效(未销毁) */
get isValid(): boolean {
return !this._destroyed;
}
private _ent: T | null = null;
/** 所属实体引用 */
get ent(): T {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试访问已销毁的业务逻辑的实体引用');
}
return this._ent!;
}
set ent(value: T) {
this._ent = value;
}
/** 业务逻辑初始化(由 CCEntity.addBusiness 自动调用) */
protected init() {
@@ -19,6 +38,13 @@ export class CCBusiness<T extends CCEntity> {
}
destroy() {
if (this._destroyed) {
console.warn('[OopsFramework]', '业务逻辑已销毁,无需重复销毁');
return;
}
this._destroyed = true;
// 释放消息对象
if (this._event) {
this._event.clear();
@@ -26,7 +52,7 @@ export class CCBusiness<T extends CCEntity> {
}
// 清空实体引用,避免循环引用导致的内存泄漏
this.ent = null!;
this._ent = null;
}
//#region 全局事件管理
@@ -34,6 +60,9 @@ export class CCBusiness<T extends CCEntity> {
private _event: EventDispatcher | null = null;
/** 全局事件管理器 */
private get event(): EventDispatcher {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试访问已销毁的业务逻辑的事件管理器');
}
if (this._event == null) this._event = new EventDispatcher();
return this._event;
}
@@ -47,6 +76,10 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象
*/
watch<K extends keyof OopsFramework.TypedEventMap>(event: K, listener: ListenerFuncTyped<K, OopsFramework.TypedEventMap[K]>, object: any): void {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上注册事件');
return;
}
this.event.on(event as string, listener as ListenerFunc, object);
}
@@ -57,6 +90,10 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象
*/
watchOnce<K extends keyof OopsFramework.TypedEventMap>(event: K, listener: ListenerFuncTyped<K, OopsFramework.TypedEventMap[K]>, object: any): void {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上注册一次性事件');
return;
}
this.event.once(event as string, listener as ListenerFunc, object);
}
@@ -67,6 +104,7 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象可选
*/
unwatch<K extends keyof OopsFramework.TypedEventMap>(event: K, listener?: ListenerFuncTyped<K, OopsFramework.TypedEventMap[K]>, object?: any): void {
if (this._destroyed) return;
this.event.off(event as string, listener as ListenerFunc, object);
}
@@ -76,6 +114,10 @@ export class CCBusiness<T extends CCEntity> {
* @param data 事件数据
*/
emit<K extends keyof OopsFramework.TypedEventMap>(event: K, data: OopsFramework.TypedEventMap[K]): void {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上触发事件');
return;
}
this.event.emit(event, data);
}
@@ -85,6 +127,10 @@ export class CCBusiness<T extends CCEntity> {
* @param data 事件数据(必须完全匹配类型定义)
*/
emitAsync<K extends keyof OopsFramework.TypedEventMap>(event: K, data: OopsFramework.TypedEventMap[K]): Promise<void> {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上触发异步事件');
return Promise.resolve();
}
return this.event.emitAsync(event, data);
}
@@ -99,6 +145,10 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象
*/
on(event: string, listener: ListenerFunc, object: object) {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上注册事件');
return;
}
this.event.on(event, listener, object);
}
@@ -109,6 +159,10 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象
*/
once(event: string, listener: ListenerFunc, object: object) {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上注册一次性事件');
return;
}
this.event.once(event, listener, object);
}
@@ -119,6 +173,7 @@ export class CCBusiness<T extends CCEntity> {
* @param object 侦听函数绑定的this对象可选
*/
off(event: string, listener?: ListenerFunc, object?: object) {
if (this._destroyed) return;
this.event.off(event, listener, object);
}
@@ -128,6 +183,10 @@ export class CCBusiness<T extends CCEntity> {
* @param args 事件参数
*/
dispatchEvent(event: string, ...args: unknown[]) {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上触发事件');
return;
}
this.event.dispatchEvent(event, ...args);
}
@@ -137,6 +196,10 @@ export class CCBusiness<T extends CCEntity> {
* @param args 事件参数
*/
dispatchEventAsync(event: string, ...args: unknown[]): Promise<void> {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上触发异步事件');
return Promise.resolve();
}
return this.event.dispatchEventAsync(event, ...args);
}
@@ -149,13 +212,17 @@ export class CCBusiness<T extends CCEntity> {
* onGlobal(event: string, args: unknown) { console.log(args) };
*/
protected setEvent(...args: string[]) {
if (this._destroyed) {
console.warn('[OopsFramework]', '尝试在已销毁的业务逻辑上批量设置事件');
return;
}
for (const name of args) {
const func = (this as Record<string, unknown>)[name];
if (typeof func === 'function') {
this.on(name, func as ListenerFunc, this);
}
else {
console.error(`名为【${name}】的全局事方法不存在`);
console.error('[OopsFramework]', `名为【${name}】的全局事方法不存在`);
}
}
}

View File

@@ -35,7 +35,7 @@ export abstract class CCEntity extends ecs.Entity {
addChildSingleton<T extends CCEntity>(cls: OopsFramework.EntityCtor<T>): T {
if (this.singletons == null) this.singletons = new Map();
if (this.singletons.has(cls)) {
console.error(`${cls.name} 单例子实体已存在`);
console.error('[OopsFramework]', `${cls.name} 单例子实体已存在`);
return null!;
}
const entity = ecs.getEntity<T>(cls);
@@ -105,7 +105,7 @@ export abstract class CCEntity extends ecs.Entity {
// 检查实体是否已销毁
if (!this.isValid) {
console.warn(`实体已销毁,取消添加预制体组件: ${(ctor as any).name}`);
console.warn('[OopsFramework]', `实体已销毁,取消添加预制体组件: ${(ctor as any).name}`);
node.destroy();
return null;
}
@@ -120,7 +120,7 @@ export abstract class CCEntity extends ecs.Entity {
// 检查实体是否已销毁
if (!this.isValid) {
console.warn(`实体已销毁,取消添加预制体组件: ${(ctor as any).name}`);
console.warn('[OopsFramework]', `实体已销毁,取消添加预制体组件: ${(ctor as any).name}`);
node.destroy();
return null;
}
@@ -166,7 +166,7 @@ export abstract class CCEntity extends ecs.Entity {
}
if (oops.gui.has(key)) {
console.warn(`${key} 界面已存在`);
console.warn('[OopsFramework]', `${key} 界面已存在`);
return oops.gui.get(key);
}
@@ -174,7 +174,7 @@ export abstract class CCEntity extends ecs.Entity {
// 检查实体是否已销毁
if (!this.isValid) {
console.warn(`实体已销毁,取消添加界面组件: ${key}`);
console.warn('[OopsFramework]', `实体已销毁,取消添加界面组件: ${key}`);
oops.gui.remove(key);
return null;
}
@@ -196,7 +196,7 @@ export abstract class CCEntity extends ecs.Entity {
if (key) {
const node = oops.gui.get(key);
if (node == null) {
console.warn(`${key} 界面不存在或已关闭`);
console.warn('[OopsFramework]', `${key} 界面不存在或已关闭`);
return;
}
@@ -209,7 +209,7 @@ export abstract class CCEntity extends ecs.Entity {
if (view) this.remove(ctor as unknown as CompType<ecs.IComp>);
}
catch (error) {
console.error(`移除界面组件失败: ${key}`, error);
console.error('[OopsFramework]', `移除界面组件失败: ${key}`, error);
}
};
oops.gui.remove(key);
@@ -248,7 +248,7 @@ export abstract class CCEntity extends ecs.Entity {
addBusiness<T extends CCBusiness<CCEntity>>(cls: OopsFramework.BusinessCtor<T>): T {
if (this.businesss == null) this.businesss = new Map();
if (this.businesss.has(cls)) {
console.error(`${cls.name} 业务逻辑组件已存在`);
console.error('[OopsFramework]', `${cls.name} 业务逻辑组件已存在`);
return null!;
}
const business = new cls();

View File

@@ -5,13 +5,11 @@
* @LastEditTime: 2022-09-06 17:20:51
*/
import type { Component } from 'cc';
import type { ecs } from '../../libs/ecs/ECS';
import { ECSModel } from '../../libs/ecs/ECSModel';
import { VM } from '../../libs/model-view/ViewModel';
import { VMBase } from '../../libs/model-view/VMBase';
import type { CCEntity } from './CCEntity';
import type { UICtor } from '../../types/Module';
import { GameComponent } from './GameComponent';
/**
@@ -90,15 +88,13 @@ export abstract class CCView<T extends CCEntity> extends GameComponent implement
* 注意:如果子类需要覆盖此方法,必须调用 super.onLoad()
*/
onLoad() {
// 提前返回,避免不必要的检查
if (!this.mvvm) return;
// onBind 语义为"绑定初始化",与 data 是否存在解耦,始终调用
this.onBind();
const data = this.data;
if (data === undefined || data === null) {
console.warn(`[CCView] ${this.constructor.name}: mvvm=true 但 data 未定义VM 绑定已跳过`);
console.warn('[OopsFramework]', `${this.constructor.name}: mvvm=true 但 data 未定义VM 绑定已跳过`);
return;
}
@@ -110,7 +106,6 @@ export abstract class CCView<T extends CCEntity> extends GameComponent implement
* @private
*/
private initializeVM() {
// 使用正则替换所有的点,避免 VM.add 内部校验失败
const uuid = this.node.uuid.replace(/\./g, '');
this.tag = `_temp<${uuid}>`;
VM.add(this.data!, this.tag);
@@ -161,35 +156,30 @@ export abstract class CCView<T extends CCEntity> extends GameComponent implement
private getVMComponents(): VMBase[] {
const result: VMBase[] = [];
const myUuid = this.uuid;
// 深度优先遍历,遇到嵌套的 MVVM CCView 时剪枝
const traverse = (node: any) => {
// 检查当前节点的组件
const vmComps = node.getComponents(VMBase);
const vmLen = vmComps.length;
for (let i = 0; i < vmLen; i++) {
result.push(vmComps[i]);
}
// 检查是否有嵌套的 MVVM CCView排除自己
const ccViews = node.getComponents(CCView);
const ccLen = ccViews.length;
for (let i = 0; i < ccLen; i++) {
const view = ccViews[i];
if (view.uuid !== myUuid && view.mvvm) {
// 遇到嵌套的 MVVM CCView剪枝不再遍历其子节点
return;
}
}
// 递归遍历子节点
const children = node.children;
const childLen = children.length;
for (let i = 0; i < childLen; i++) {
traverse(children[i]);
}
};
traverse(this.node);
return result;
}
@@ -199,24 +189,24 @@ export abstract class CCView<T extends CCEntity> extends GameComponent implement
remove() {
const ent = this.ent;
if (!ent) {
console.error(`组件 ${this.name} 移除失败,实体不存在`);
console.error('[OopsFramework]', `组件 ${this.name} 移除失败,实体不存在`);
return;
}
const tid = this.tid;
if (tid < 0) {
console.error(`组件 ${this.name} 移除失败,组件未注册 (tid=${tid})`);
console.error('[OopsFramework]', `组件 ${this.name} 移除失败,组件未注册 (tid=${tid})`);
return;
}
const cct = ECSModel.compCtors[tid];
if (!cct) {
console.error(`组件 ${this.name} 移除失败,组件构造函数不存在 (tid=${tid})`);
console.error('[OopsFramework]', `组件 ${this.name} 移除失败,组件构造函数不存在 (tid=${tid})`);
return;
}
ent.removeUi(cct as unknown as UICtor);
this.ent = null!; // 清空引用,避免内存泄漏
ent.removeUi(cct as unknown as OopsFramework.UICtor);
this.ent = null!;
}
/**
@@ -224,11 +214,9 @@ export abstract class CCView<T extends CCEntity> extends GameComponent implement
* 注意:如果子类需要覆盖此方法,必须调用 super.onDestroy()
*/
protected onDestroy() {
// 只有启用了 MVVM 时才执行清理
if (this.mvvm) {
this.onUnBind();
// 解除全部引用
const tag = this.tag;
if (tag) {
VM.remove(tag);

View File

@@ -1,87 +0,0 @@
/*
* @Author: dgflash
* @Date: 2022-03-29 17:08:08
* @LastEditors: dgflash
* @LastEditTime: 2022-09-02 09:45:41
*/
import type { ICollisionEvent, ITriggerEvent } from 'cc';
import { _decorator, ccenum, Collider, Component } from 'cc';
const { ccclass, property } = _decorator;
/** 碰撞物体类型 */
export enum CollisionType {
/** 角色类 */
Role,
/** 飞弹类体*/
Ballistic,
/** 墙体类 */
Wall
}
ccenum(CollisionType);
const Event_TriggerEnter = 'onTriggerEnter';
const Event_TriggerStay = 'onTriggerStay';
const Event_TriggerExit = 'onTriggerExit';
const Event_CollisionEnter = 'onCollisionEnter';
const Event_CollisionStay = 'onCollisionStay';
const Event_CollisionExit = 'onCollisionExit';
/** 碰撞器与触发器 */
@ccclass('GameCollision')
export class GameCollision extends Component {
protected collider: Collider = null!;
@property({ type: CollisionType, tooltip: '碰撞物体类型' })
type: CollisionType = CollisionType.Ballistic;
onLoad() {
this.collider = this.getComponent(Collider)!;
if (this.collider.isTrigger) {
this.collider.on(Event_TriggerEnter, this.onTrigger, this);
this.collider.on(Event_TriggerStay, this.onTrigger, this);
this.collider.on(Event_TriggerExit, this.onTrigger, this);
}
else {
this.collider.on(Event_CollisionEnter, this.onCollision, this);
this.collider.on(Event_CollisionStay, this.onCollision, this);
this.collider.on(Event_CollisionExit, this.onCollision, this);
}
}
private onTrigger(event: ITriggerEvent) {
switch (event.type) {
case Event_TriggerEnter:
this.onTriggerEnter(event);
break;
case Event_TriggerStay:
this.onTriggerStay(event);
break;
case Event_TriggerExit:
this.onTriggerExit(event);
break;
}
}
protected onTriggerEnter(event: ITriggerEvent) { }
protected onTriggerStay(event: ITriggerEvent) { }
protected onTriggerExit(event: ITriggerEvent) { }
private onCollision(event: ICollisionEvent) {
switch (event.type) {
case Event_CollisionEnter:
this.onCollisionEnter(event);
break;
case Event_CollisionStay:
this.onCollisionStay(event);
break;
case Event_CollisionExit:
this.onCollisionExit(event);
break;
}
}
protected onCollisionEnter(event: ICollisionEvent) { }
protected onCollisionStay(event: ICollisionEvent) { }
protected onCollisionExit(event: ICollisionEvent) { }
}

View File

@@ -1,9 +0,0 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "7fa3eab3-0e4a-4152-af0e-50daf4e55261",
"files": [],
"subMetas": {},
"userData": {}
}