UI框架添加自动释放窗口内存功能

显示对象GameComponent添加自动释放的资源API
This commit is contained in:
dgflash
2022-06-21 15:33:40 +08:00
parent 46a21fc9b6
commit bdfa76cae1
9 changed files with 115 additions and 213 deletions

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "d7a109d3-8659-4487-a915-2c38b3d88f58",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -2,12 +2,11 @@
* @Author: dgflash
* @Date: 2021-11-11 19:05:32
* @LastEditors: dgflash
* @LastEditTime: 2022-06-14 19:53:02
* @LastEditTime: 2022-06-21 12:17:24
*/
import { Component, Node, _decorator } from 'cc';
import { EventDispatcher } from '../../../../../extensions/oops-framework/assets/core/common/event/EventDispatcher';
import { ViewUtil } from '../../../../../extensions/oops-framework/assets/core/utils/ViewUtil';
import { _decorator } from 'cc';
import { GameComponent } from '../../../../../extensions/oops-framework/assets/core/game/GameComponent';
import { ecs } from '../../../../../extensions/oops-framework/assets/libs/ecs/ECS';
const { ccclass, property } = _decorator;
@@ -21,7 +20,7 @@ const { ccclass, property } = _decorator;
* 4、对象管理的所有节点摊平直接通过节点名获取cc.Node对象节点名不能有重名
*/
@ccclass('CCComp')
export abstract class CCComp extends Component implements ecs.IComp {
export abstract class CCComp extends GameComponent implements ecs.IComp {
static tid: number = -1;
static compName: string;
@@ -29,94 +28,4 @@ export abstract class CCComp extends Component implements ecs.IComp {
ent!: ecs.Entity;
abstract reset(): void;
private nodes: Map<string, Node> = new Map();
/** 通过节点名获取预制上的节点,整个预制不能有重名节点 */
get(name: string): Node | undefined {
return this.nodes.get(name);
}
onLoad() {
ViewUtil.nodeTreeInfoLite(this.node, this.nodes);
}
//#region 全局事件管理
private _eventDispatcher: EventDispatcher | null = null;
public get eventDispatcher(): EventDispatcher {
if (!this._eventDispatcher) {
this._eventDispatcher = new EventDispatcher();
}
return this._eventDispatcher;
}
// 事件是否绑定node的active
private _isBindMessageActive: boolean = false;
/** 绑定node active属性即只有active为true才会响应事件 */
public bindMessageActive() {
this._isBindMessageActive = true;
}
/** 解绑node active属性无论node是否可见都会响应事件 */
public unbindMessageActive() {
this._isBindMessageActive = false;
}
/**
* 注册全局事件
* @param event(string) 事件名
* @param listener(function) 处理事件的侦听器函数
* @param thisObj(object) 侦听函数绑定的this对象
*/
public on(event: string, listener: Function, thisObj: any) {
this.eventDispatcher.on(event, (event, args) => {
if (!this.isValid) {
if (this._eventDispatcher) {
this._eventDispatcher.destroy();
this._eventDispatcher = null;
}
return;
}
if (this._isBindMessageActive) {
if (this.node.active) {
listener.call(thisObj, event, args);
}
}
else {
listener.call(thisObj, event, args);
}
}, thisObj);
}
/**
* 移除全局事件
* @param event(string) 事件名
*/
public off(event: string) {
if (this._eventDispatcher) {
this._eventDispatcher.off(event);
}
}
/**
* 触发全局事件
* @param event(string) 事件名
* @param arg(Array) 事件参数
*/
public dispatchEvent(event: string, arg: any = null) {
this.eventDispatcher.dispatchEvent(event, arg);
}
onDestroy() {
if (this._eventDispatcher) {
this._eventDispatcher.destroy();
this._eventDispatcher = null;
}
this.nodes.clear();
}
//#endregion
}

View File

@@ -2,12 +2,10 @@
* @Author: dgflash
* @Date: 2021-11-11 19:05:32
* @LastEditors: dgflash
* @LastEditTime: 2022-06-14 19:53:11
* @LastEditTime: 2022-06-21 12:17:51
*/
import { Node, _decorator } from 'cc';
import { EventDispatcher } from '../../../../../extensions/oops-framework/assets/core/common/event/EventDispatcher';
import { ViewUtil } from '../../../../../extensions/oops-framework/assets/core/utils/ViewUtil';
import { _decorator } from 'cc';
import { ecs } from '../../../../../extensions/oops-framework/assets/libs/ecs/ECS';
import VMParent from '../../../../../extensions/oops-framework/assets/libs/model-view/VMParent';
@@ -30,95 +28,4 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp {
ent!: ecs.Entity;
abstract reset(): void;
private nodes: Map<string, Node> = new Map();
/** 通过节点名获取预制上的节点,整个预制不能有重名节点 */
get(name: string): Node | undefined {
return this.nodes.get(name);
}
onLoad() {
ViewUtil.nodeTreeInfoLite(this.node, this.nodes);
super.onLoad();
}
//#region 全局事件管理
private _eventDispatcher: EventDispatcher | null = null;
public get eventDispatcher(): EventDispatcher {
if (!this._eventDispatcher) {
this._eventDispatcher = new EventDispatcher();
}
return this._eventDispatcher;
}
// 事件是否绑定node的active
private _isBindMessageActive: boolean = false;
/** 绑定node active属性即只有active为true才会响应事件 */
public bindMessageActive() {
this._isBindMessageActive = true;
}
/** 解绑node active属性无论node是否可见都会响应事件 */
public unbindMessageActive() {
this._isBindMessageActive = false;
}
/**
* 注册全局事件
* @param event(string) 事件名
* @param listener(function) 处理事件的侦听器函数
* @param thisObj(object) 侦听函数绑定的this对象
*/
public on(event: string, listener: Function, thisObj: any) {
this.eventDispatcher.on(event, (event, args) => {
if (!this.isValid) {
if (this._eventDispatcher) {
this._eventDispatcher.destroy();
this._eventDispatcher = null;
}
return;
}
if (this._isBindMessageActive) {
if (this.node.active) {
listener.call(thisObj, event, args);
}
}
else {
listener.call(thisObj, event, args);
}
}, thisObj);
}
/**
* 移除全局事件
* @param event(string) 事件名
*/
public off(event: string) {
if (this._eventDispatcher) {
this._eventDispatcher.off(event);
}
}
/**
* 触发全局事件
* @param event(string) 事件名
* @param arg(Array) 事件参数
*/
public dispatchEvent(event: string, arg: any = null) {
this.eventDispatcher.dispatchEvent(event, arg);
}
onDestroy() {
if (this._eventDispatcher) {
this._eventDispatcher.destroy();
this._eventDispatcher = null;
}
this.nodes.clear();
}
//#endregion
}

View File

@@ -2,7 +2,7 @@
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2022-06-17 16:32:26
* @LastEditTime: 2022-06-21 15:31:05
*/
import { Component, dynamicAtlasManager, EventTouch, _decorator } from "cc";
import { tips } from "../common/prompt/TipsManager";
@@ -10,6 +10,7 @@ import { oops } from "../../../../extensions/oops-framework/assets/core/Oops";
import { UIID } from "../common/config/GameUIConfig";
import { SingletonModuleComp } from "../common/ecs/SingletonModuleComp";
import { ecs } from "../../../../extensions/oops-framework/assets/libs/ecs/ECS";
import { resLoader } from "../../../../extensions/oops-framework/assets/core/common/loader/ResLoader";
const { ccclass, property } = _decorator;
// 视图层实体是空的
@@ -26,6 +27,10 @@ export class Demo extends Component {
}
start() {
// 释放加载界面资源
console.log("内存中现有资源");
resLoader.dump();
console.log("当前图集数量", dynamicAtlasManager.atlasCount);
console.log("可以创建的最大图集数量", dynamicAtlasManager.maxAtlasCount);
console.log("创建的图集的宽高", dynamicAtlasManager.textureSize);

View File

@@ -2,7 +2,7 @@
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2022-06-14 19:55:31
* @LastEditTime: 2022-06-21 15:30:55
*/
import { _decorator } from "cc";
import { resLoader } from "../../../../../extensions/oops-framework/assets/core/common/loader/ResLoader";
@@ -44,16 +44,13 @@ export class LoadingViewComp extends CCVMParentComp {
// 关闭加载界面
oops.gui.remove(UIID.Loading);
// 释放加载界面资源
resLoader.releaseDir("loading");
// 打开游戏主界面(自定义逻辑)
oops.gui.open(UIID.Demo);
}
start() {
// if (!sys.isNative) {
this.enter();
this.enter();
// }
}

View File

@@ -1,4 +1,4 @@
import { Asset, AssetManager, assetManager, Constructor, error, js, resources, __private } from "cc";
import { Asset, AssetManager, assetManager, Constructor, error, js, Prefab, resources, __private } from "cc";
export type ProgressCallback = __private._cocos_core_asset_manager_shared__ProgressCallback;
export type CompleteCallback<T = any> = __private._cocos_core_asset_manager_shared__CompleteCallbackWithData;
@@ -165,17 +165,23 @@ export default class ResLoader {
assetManager.loadRemote<T>(url, options, onComplete);
}
/** 通过资源相对路径释放资源 */
public release(path: string, bundleName: string = "resources") {
var bundle = assetManager.getBundle(bundleName);
bundle?.release(path);
if (bundle) {
var asset = bundle.get(path);
if (asset) {
this.releasePrefabtDepsRecursively(asset._uuid);
}
}
}
/** 通过相对文件夹路径删除所有文件夹中资源 */
public releaseDir(path: string, bundleName: string = "resources") {
var bundle: AssetManager.Bundle | null = assetManager.getBundle(bundleName);
var infos = bundle?.getDirWithPath(path);
infos?.map(function (info) {
var asset = assetManager.assets.get(info.uuid)!;
assetManager.releaseAsset(asset);
infos?.map((info) => {
this.releasePrefabtDepsRecursively(info.uuid);
});
if (path == "" && bundleName != "resources" && bundle) {
@@ -183,6 +189,19 @@ export default class ResLoader {
}
}
/** 释放预制依赖资源 */
private releasePrefabtDepsRecursively(uuid: string) {
var asset = assetManager.assets.get(uuid)!;
if (asset instanceof Prefab) {
var uuids: string[] = assetManager.dependUtil.getDepsRecursively(uuid)!;
uuids.forEach(uuid => {
assetManager.assets.get(uuid)!.decRef();
});
}
assetManager.releaseAsset(asset);
}
/** 获取资源 */
public get<T extends Asset>(path: string, type?: __private._cocos_core_asset_manager_shared__AssetType<T> | null, bundleName: string = "resources"): T | null {
var bundle: AssetManager.Bundle | null = assetManager.getBundle(bundleName);
return bundle!.get(path, type);
@@ -190,7 +209,7 @@ export default class ResLoader {
public dump() {
assetManager.assets.forEach((value: Asset, key: string) => {
console.log(key);
console.log(assetManager.assets.get(key));
})
console.log(`当前资源总数:${assetManager.assets.count}`);
}

View File

@@ -2,13 +2,15 @@
* @Author: dgflash
* @Date: 2022-04-14 17:08:01
* @LastEditors: dgflash
* @LastEditTime: 2022-04-14 19:07:39
* @LastEditTime: 2022-06-21 15:30:04
*/
import { Component, _decorator } from "cc";
import { Asset, Component, isValid, Node, _decorator } from "cc";
import { EventDispatcher } from "../common/event/EventDispatcher";
import { ViewUtil } from "../utils/ViewUtil";
const { ccclass } = _decorator;
/** 游戏显示对象组件模板 */
@ccclass("GameComponent")
export class GameComponent extends Component {
private _eventDispatcher: EventDispatcher | null = null;
@@ -33,13 +35,42 @@ export class GameComponent extends Component {
this._isBindMessageActive = false;
}
/** 自动释放资源 */
private dynamicsAssets: Asset[] = [];
/** 摊平的节点集合(不能重名) */
private nodes: Map<string, Node> = new Map();
/** 通过节点名获取预制上的节点,整个预制不能有重名节点 */
get(name: string): Node | undefined {
return this.nodes.get(name);
}
onLoad() {
ViewUtil.nodeTreeInfoLite(this.node, this.nodes);
}
/** 添加自动释放的资源 */
addAutoReleaseAsset(asset: Asset) {
if (isValid(asset)) {
asset.addRef();
this.dynamicsAssets.push(asset);
}
}
/** 添加自动释放的资源数组 */
addAutoReleaseAssets(assets: Asset[]) {
assets.forEach(asset => {
this.addAutoReleaseAsset(asset);
});
}
/**
* 注册全局事件
* @param event(string) 事件名
* @param listener(function) 处理事件的侦听器函数
* @param thisObj(object) 侦听函数绑定的this对象
*/
public on(event: string, listener: Function, thisObj: any) {
on(event: string, listener: Function, thisObj: any) {
this.eventDispatcher.on(event, (event, args) => {
if (!this.isValid) {
if (this._eventDispatcher) {
@@ -64,7 +95,7 @@ export class GameComponent extends Component {
* 移除全局事件
* @param event(string) 事件名
*/
public off(event: string) {
off(event: string) {
if (this._eventDispatcher) {
this._eventDispatcher.off(event);
}
@@ -75,14 +106,24 @@ export class GameComponent extends Component {
* @param event(string) 事件名
* @param arg(Array) 事件参数
*/
public dispatchEvent(event: string, arg = null) {
dispatchEvent(event: string, arg = null) {
this.eventDispatcher.dispatchEvent(event, arg);
}
onDestroy() {
protected onDestroy() {
// 释放消息对象
if (this._eventDispatcher) {
this._eventDispatcher.destroy();
this._eventDispatcher = null;
}
// 节点引用数据清除
this.nodes.clear();
// 自动释放资源
this.dynamicsAssets.forEach(asset => {
asset.decRef();
});
this.dynamicsAssets.splice(0, this.dynamicsAssets.length);
}
}

View File

@@ -1,4 +1,5 @@
import { Component, Node, _decorator } from "cc";
import { resLoader } from "../../common/loader/ResLoader";
import { ViewParams } from "./Defines";
const { ccclass } = _decorator;
@@ -48,10 +49,15 @@ export class DelegateComponent extends Component {
viewParams.callbacks!.onRemoved(this.node, viewParams.params);
}
if (isDestroy)
if (isDestroy) {
this.node.destroy();
else
// 释放界面相关资源
resLoader.release(viewParams.prefabPath);
}
else {
this.node.removeFromParent();
}
}
onDestroy() {

View File

@@ -1,4 +1,5 @@
import { Component, _decorator } from 'cc';
import { GameComponent } from '../../core/game/GameComponent';
import { VM } from './ViewModel';
const { ccclass, help, executionOrder } = _decorator;
@@ -13,7 +14,7 @@ const { ccclass, help, executionOrder } = _decorator;
@ccclass
@executionOrder(-1)
@help('https://github.com/wsssheep/cocos_creator_mvvm_tools/blob/master/docs/VMParent.md')
export default class VMParent extends Component {
export default class VMParent extends GameComponent {
/** 绑定的标签可以通过这个tag 获取 当前的 vm 实例 */
protected tag: string = '_temp';
@@ -33,7 +34,7 @@ export default class VMParent extends Component {
* ```
*
*/
protected onLoad() {
onLoad() {
if (this.data == null) return;
this.tag = '_temp' + '<' + this.node.uuid.replace('.', '') + '>';
VM.add(this.data, this.tag);
@@ -48,6 +49,8 @@ export default class VMParent extends Component {
// console.groupEnd()
this.onBind();
super.onLoad();
}
/**在 onLoad 完成 和 start() 之前调用,你可以在这里进行初始化数据等操作 */
@@ -111,8 +114,11 @@ export default class VMParent extends Component {
*/
protected onDestroy() {
this.onUnBind();
//解除全部引用
// 解除全部引用
VM.remove(this.tag);
this.data = null;
super.onDestroy();
}
}