Files
oops-plugin-framework/assets/libs/model-view/VMState.ts
dgflash f2fe9d47b6 1. 存储模块全面优化,修复跨平台兼容性问题,完美支持所有Unicode字符
2. 存储模块性能提升,添加LRU缓存、批量操作支持,优化内存使用
3. 多语言模块性能与内存管理优化,组件查询性能提升
4. 时间模块类型安全与性能优化,使用泛型替代any,对象池机制减少内存分配
5. 事件系统修复双重注册、重复注册等严重问题,实现EventData对象池减少GC压力
6. RandomManager修复4个逻辑BUG,包括边界问题和越界问题
7. 音频模块内存与性能优化,避免重复加载,优化数据结构,添加完整清理机制
8. CCView与CCViewVM合并,支持按需启用MVVM
9. Collection模块优化,AsyncQueue添加队列容量限制,Collection查询性能提升
10. ECS系统全面优化,对象池复用减少内存分配,循环性能提升
11. 优化MVVM组件性能
2026-01-09 21:54:05 +08:00

320 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Color } from 'cc';
import { Button, CCInteger, Enum, Node, Sprite, UIOpacity, UIRenderer, _decorator, color } from 'cc';
import { VMBase } from './VMBase';
import { VM } from './ViewModel';
const { ccclass, property, menu, help } = _decorator;
/** 比较条件 */
enum CONDITION {
'==', // 正常计算,比较 等于
'!=', // 正常计算,比较 不等于
'>', // 正常计算,比较>
'>=', // 正常计算,比较>=
'<', // 正常计算,比较<
'<=', // 正常计算,比较>=
'range' // 计算在范围内
}
enum ACTION {
NODE_ACTIVE, // 满足条件的节点激活不满足的不激活只对子节点的激活有效果当前节点active = false时组件就失去效果了如果设置当前节点可用NODE_VISIBLE代替
NODE_VISIBLE, // 满足条件的节点显示,不满足的不显示
NODE_OPACITY, // 满足条件的节点改变不透明度不满足的还原255
NODE_COLOR, // 满足条件的节点改变颜色,不满足的恢复白色
COMPONENT_CUSTOM, // 自定义控制组件模式
SPRITE_GRAYSCALE, // 满足条件的节点cc.Sprite组件纹理变黑白
BUTTON_INTERACTABLE, // 满足条件的节点cc.BUTTON组件,
}
enum CHILD_MODE_TYPE {
NODE_INDEX,
NODE_NAME
}
/**
* [VM-State]
* 监听数值状态,根据数值条件设置节点是否激活
*/
@ccclass
@menu('OopsFramework/Mvvm/VM-State (状态控制)')
@help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037846&doc_id=2873565')
export default class VMState extends VMBase {
@property
watchPath = '';
@property({
tooltip: '遍历子节点,根据子节点的名字或名字转换为值,判断值满足条件 来激活'
})
foreachChildMode = false;
@property({
type: Enum(CONDITION),
})
condition: CONDITION = CONDITION['=='];
@property({
type: Enum(CHILD_MODE_TYPE),
tooltip: '遍历子节点,根据子节点的名字转换为值,判断值满足条件 来激活',
visible: function () {
// @ts-ignore
return this.foreachChildMode === true;
}
})
foreachChildType: CHILD_MODE_TYPE = CHILD_MODE_TYPE.NODE_INDEX;
@property({
displayName: 'Value: a',
visible: function () {
// @ts-ignore
return this.foreachChildMode === false;
}
})
valueA = 0;
@property({
displayName: 'Value: b',
visible: function () {
// @ts-ignore
return this.foreachChildMode === false && this.condition === CONDITION.range;
}
})
valueB = 0;
@property({
type: Enum(ACTION),
tooltip: '一旦满足条件就对节点执行操作'
})
valueAction: ACTION = ACTION.NODE_ACTIVE;
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.NODE_OPACITY;
},
range: [0, 255],
type: CCInteger,
displayName: 'Action Opacity'
})
valueActionOpacity = 0;
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.NODE_COLOR;
},
displayName: 'Action Color'
})
valueActionColor: Color = color(155, 155, 155);
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.COMPONENT_CUSTOM;
},
displayName: 'Component Name'
})
valueComponentName = '';
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.COMPONENT_CUSTOM;
},
displayName: 'Component Property'
})
valueComponentProperty = '';
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.COMPONENT_CUSTOM;
},
displayName: 'Default Value'
})
valueComponentDefaultValue = '';
@property({
visible: function () {
// @ts-ignore
return this.valueAction === ACTION.COMPONENT_CUSTOM;
},
displayName: 'Action Value'
})
valueComponentActionValue = '';
@property({
type: [Node],
tooltip: '需要执行条件的节点,如果不填写则默认会执行本节点以及本节点的所有子节点 的状态'
})
watchNodes: Node[] = [];
// 缓存动态添加的组件,用于销毁时清理
private _addedComponents: Map<Node, UIOpacity> = new Map();
onLoad() {
super.onLoad();
// 如果数组里没有监听值,那么默认把所有子节点给监听了
if (this.watchNodes.length == 0) {
if (this.valueAction !== ACTION.NODE_ACTIVE && this.foreachChildMode === false) {
this.watchNodes.push(this.node);
}
this.watchNodes = this.watchNodes.concat(this.node.children);
}
}
start() {
if (this.enabled) {
this.onValueInit();
}
}
// 当值初始化时
protected onValueInit() {
const value = VM.getValue(this.watchPath);
this.checkNodeFromValue(value);
}
// 当值被改变时
protected onValueChanged(newVar: any, oldVar: any, pathArr: any[]) {
this.checkNodeFromValue(newVar);
}
// 检查节点值更新
private checkNodeFromValue(value: any) {
if (this.foreachChildMode) {
this.watchNodes.forEach((node, index) => {
const v = (this.foreachChildType === CHILD_MODE_TYPE.NODE_INDEX) ? index : node.name;
const check = this.conditionCheck(value, v);
// log('遍历模式', value, node.name, check);
this.setNodeState(node, check);
});
}
else {
const check = this.conditionCheck(value, this.valueA, this.valueB);
this.setNodesStates(check);
}
}
// 更新 多个节点 的 状态
private setNodesStates(checkState?: boolean) {
const nodes = this.watchNodes;
const check = checkState;
nodes.forEach((node) => {
this.setNodeState(node, check);
});
}
/** 更新单个节点的状态 */
private setNodeState(node: Node, checkState?: boolean) {
const n = this.valueAction;
const check = checkState;
switch (n) {
case ACTION.NODE_ACTIVE:
node.active = check ? true : false;
break;
case ACTION.NODE_VISIBLE: {
let opacity = node.getComponent(UIOpacity);
if (opacity == null) {
opacity = node.addComponent(UIOpacity);
// 缓存动态添加的组件
this._addedComponents.set(node, opacity);
}
if (opacity) {
opacity.opacity = check ? 255 : 0;
}
break;
}
case ACTION.NODE_OPACITY: {
let opacity = node.getComponent(UIOpacity);
if (opacity == null) {
opacity = node.addComponent(UIOpacity);
// 缓存动态添加的组件
this._addedComponents.set(node, opacity);
}
if (opacity) {
opacity.opacity = check ? this.valueActionOpacity : 255;
}
break;
}
case ACTION.NODE_COLOR: {
const uir = node.getComponent(UIRenderer);
if (uir) {
uir.color = check ? this.valueActionColor : color(255, 255, 255);
}
break;
}
case ACTION.COMPONENT_CUSTOM:
const comp: any = node.getComponent(this.valueComponentName);
if (comp == null) return;
if (this.valueComponentProperty in comp) {
comp[this.valueComponentProperty] = check ? this.valueComponentActionValue : this.valueComponentDefaultValue;
}
break;
case ACTION.SPRITE_GRAYSCALE: {
const sprite = node.getComponent(Sprite);
if (sprite) {
sprite.grayscale = check!;
}
break;
}
case ACTION.BUTTON_INTERACTABLE: {
const sprite = node.getComponent(Button);
if (sprite) {
sprite.interactable = check!;
}
break;
}
default:
break;
}
}
/** 条件检查 */
private conditionCheck(v: any, a: any, b?: any): boolean {
const cod = CONDITION;
switch (this.condition) {
case cod['==']:
if (v == a) return true;
break;
case cod['!=']:
if (v != a) return true;
break;
case cod['<']:
if (v < a) return true;
break;
case cod['>']:
if (v > a) return true;
break;
case cod['>=']:
if (v >= a) return true;
break;
case cod['<']:
if (v < a) return true;
break;
case cod['<=']:
if (v <= a) return true;
break;
case cod['range']:
if (v >= a && v <= b) return true;
break;
default:
break;
}
return false;
}
/**
* 组件销毁时清理内存引用
*/
onDestroy() {
// 清理节点引用数组
this.watchNodes.length = 0;
// 清理动态添加的组件缓存
this._addedComponents.clear();
}
}