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 = 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(); } }