如何将组件与游戏系统数据绑定?

比如UI上的组件cc.Label 组件如何和游戏里的数据绑定
比如
cc.Label.string = My.money
这个只是赋值,UI上是变化了1次
但在我脚本里
My.money += 100;
如何使得UI上的 Label也相应变化呢?
有什么好办法吗?

你是想要 mvvm 模式么,论坛搜下有插件的呀

纯手写的话可以这样。

@property(cc.Label)
moneyLabel: cc.Label = null;

_money: number = 0
get money() {
   return this._money;
}
set money(val: number) {
   this._money = val;
   this._moneyLabel.string = `${val}`;
}

这属于静态绑定吧
就是说 组件,数据 同时纯在,
实际的情况 往往是,游戏数据是全局的,而UI是某个场景的!
那,,这个办法似乎不行吧!
而且,一个数据可能在多个场景的多个UI组件上使用啊!

发送一个消息嘛,所有用到这个数据的UI响应这个消息,自己去读取数据来更新。

额我想你是想类似vue的吧,这样是需要你自己去注入变量去拦截修改,也就是对一个变量的属性重写get set方法,在js中你可以

 // 使用 Object.defineProperty
        Object.defineProperty(obj, attr, {
            get: function () {
                return val;
            },
            set: function (newValue) {
          // 修改通知
            }
        });

你可以遍历对象所有属性进行拦截监听,进行封装一下就可以实现你想要的了,这些都是框架级的了,一般你就写get set 然后发游戏通知就可以了,如果要透明这种在代码里面看的干净,那就是我上面说的了,我自己实现了一个http://puremvc.org/框架,就是直接的对model监听指定属性变化就好,不用实现发通知的步骤,框架已经实现了

或者用set get 或者用事件监听,看你习惯哪种了

1.只更新当前ui 直接赋值 省事
2.同时更新当前ui或其他ui 事件派发 无疑
使用set get感觉有些冗余吧
mvvm不知道是否对任意ui生效?需要配置什么 麻烦不?
对我而言 更关心是赋值给哪个ui 而不是数值…

1.用 set get方法就是 如果游戏变量很多 就比较麻烦,而且游戏变量随时增加。。。
2.游戏变量 与 ui 都不是同步出现的,策划随时改变ui,程序也随时增加,或者减少变量,这样的绑定就比较麻烦
3.消息通知,当前我就是这么做的,,想看看是否有更好的机制。。

我的游戏是 MMORPG类

对全局变量,我都是使用自定义消息机制,当变量更新后触发更新消息,需要使用这个变量的地方监听消息即可

我严重怀疑 cc的消息通知机制,似乎 监听多了就有收不到的情况,所以我都不敢用!你确定消息通知机制没问题吗?还是我使用的方式有问题,,我不确定,也就不敢用了,之前收不到消息或者不能100%收到消息,填了很多坑啊!

另外,如果使用自定义消息,那要为 每一个 全局变量 都给出一个 消息名 吧!
如果 游戏系统里有 100个这样的变量,那就要有100个 自定义消息名,这样才好区分 哪个变量变化了!

我这MMORPG 变量不只100个, 估计得几百个

1赞

你用的是cc.Node的自定义消息?
试试我这个方案,看是否满足你的需求

/**

  • 全局消息管理类(自己实现)

*/

export class MsgManager {

public static on(msgName, callback, thisobj) {

    //实现省略

}

public static off(msgName, callback, thisobj) {

    //实现省略

}

public static emit(...arg) {

    //实现省略

}

}

/**

  • 游戏数据管理类

*/

export class GameData {

private static atts = {};

public static setAtt(attName, attValue) {

    this.atts[attName] = attValue;

    MsgManager.emit(attName, attValue);

}

}

/**

  • 要版定属性的lebel节点挂上该脚本

*/

export default class AttBinding extends cc.Component {

onEnable() {

    MsgManager.on(this.node.name, this.updateAtt, this);

}

onDisable() {

    MsgManager.off(this.node.name, this.updateAtt, this);

}

updateAtt(attName, attValue) {

    if (attName === this.node.name) {

        this.node.getComponent(cc.Label).string = attValue + ``;

    }

}

}

this.node.name 重名会有问题吗?

你的属性的名字肯定是唯一的,所以在属性绑定上肯定不会有冲突,如果你担心属性的Label节点有可能会和非属性的Label节点发生冲突,你可以定个属性节点的命名规则,比如加个前缀att_att;att_blood;att_xxx等,然后在触发的时候,在MsgManager.emit(att_+attName, attValue);
这样既不会和其他消息冲突,也不会让节点的名字和非属性节点的名字冲突,怎么灵活怎么来,要会变通嘛,我上面的代码只是提供一种思路!

再说,你的非属性节点不挂这个绑定脚本也不会影响非属性节点啊,我都被你带偏了。。。。。。。