数据管理

      介绍

      在 react/vue 中,我们经常使用 redux/vuex 来进行数据管理,维护一套统一的数据,在 Eva.js 体系下,我们设计了一套数据管理系统,叫做 EVAX,通过 EVAX 我们可以维护一份共有数据,多个不同的对象上的组件可能会使用同一份数据进行逻辑运行。

      比如游戏中的生命值,不仅在人的头顶上会显示,游戏中的人物也会根据生命值的多少来展示不同的形态,我们将 EVAX 组件绑定到游戏对象上,可对某个数据进行监听,如果数据发生变化,可以操作当前游戏对象上其他组件上的数据或者事件。

      Eva.js 开发游戏不是强依赖 EVAX 的,可以按照需要使用。

      安装

      使用 NPM

      1. npm i @eva/plugin-evax

      在浏览器中

      1. <script src=https://unpkg.com/@eva/plugin-evax@1.2.x/dist/EVA.plugin.EVAX.min.js></script>

      创建 store

      所有数据需要事先定义好,如果没有定义好,将不会被监听

      1. // 创建 Store
      2. const store = {
      3. user: {
      4. name: ‘Mingfei’,
      5. age: 18
      6. },
      7. items: [
      8. {
      9. id: 1,
      10. name: ‘20191111’
      11. }
      12. ]
      13. }

      初始化 EVAX

      1. // 引入 evax 插件
      2. import { EvaXSystem, EvaX } from ‘@eva/plugin-evax’
      3. // 创建游戏,传入store
      4. const game = new Game({
      5. autoStart: true, // 可选
      6. frameRate: 60
      7. })
      8. const store = { a: 1 }
      9. const evaxSystem = new EvaXSystem({
      10. store // 这里将定义的 store 传入
      11. })
      12. game.addSystem(evaxSystem)
      13. const evaxManager = new GameObject(‘evaxManager’)
      14. evaxManager.addComponent(
      15. new EvaX({
      16. events: {
      17. ‘store.a’: () => {}
      18. }
      19. })
      20. )
      21. game.scene.addChild(evaxMangager)

      监听数据变化

      1. // 添加evax组件
      2. go.addComponent(
      3. new EvaX({
      4. events: {
      5. ‘store.user’: {
      6. deep: true, // store.user 下的属性变化也会触发
      7. handler(store, oldStore) {
      8. console.log(this) // 当前组件
      9. }
      10. },
      11. ‘store.user.age’(store, oldStore) {},
      12. ‘store.items.0’(store, oldStore) {
      13. // 0 下的属性变化不会触发,如需监听需设置deep
      14. },
      15. ‘store.items.0.name’(store, oldStore) {
      16. // name 变化会触发
      17. },
      18. popUp(arg1, arg2) {
      19. // 这是一个事件,参考后面事件触发
      20. }
      21. }
      22. })
      23. )

      更新数据

      更新单个值

      直接修改对象上面的值,如果值与之前相同也会触发监听此值改变的事件

      1. store.user.name = ‘Cailun’
      2. // 或者
      3. evaxSystem.store.user.name = ‘Cailun’

      evax.updateStore 更新所有值

      Tip: updateStore 和 forceUpdateStore 只会触发最后一层属性的变化。

      全覆盖模式更新,对比内容变化,变化的内容才会触发更新,

      1. const newStore = {
      2. user: {
      3. name: ‘Cailun’,
      4. age: 18
      5. }
      6. }
      7. evaxSystem.emit(‘evax.updateStore’, newStore)

      以上操作会触发 store.user.name 更新,因为 age 没有变化

      evax.forceUpdateStore 强制更新所有值

      全覆盖模式更新,所有值都会被更新一次,触发所有属性的监听事件

      1. const newStore = {
      2. user: {
      3. name: ‘Cailun’,
      4. age: 18
      5. }
      6. }
      7. evaxSystem.emit(‘evax.forceUpdateStore’, newStore)

      以上操作会触发 store.user.namestore.user.age 数据变化事件,即便没有变化

      事件触发

      使用 emit 方法触发约定事件,事件 不要 使用 evax. 开头

      1. evaxSystem.emit(‘popUp’, arg1, arg2, //…) // 事件约定,事件不要使用 evax. 开头

      监听方法:

      1. // 添加evax组件
      2. go.addComponent(
      3. new EvaX({
      4. events: {
      5. popUp(arg1, arg2) {}
      6. }
      7. })
      8. )

      使用案例

      创建一个文字

      这个案例介绍,如果 Store 上面的文字发生变化,我们修改对应组件上面文字的内容

      1. // 创建对象,文字组件使用store里面的名字
      2. const go = new GameObject(‘go’)
      3. const txt = go.addComponent(new Text({ text: ‘’ }))

      1、一般来讲,我们的业务逻辑写在脚本组件中,在 EVAX 组件接收到时间或者数据更改的时候,调用脚本组件上面的方法。 2、将一些需要修改的组件,比如 Text 挂在到脚本组件的属性上,以便后续操作。

      1. // 创建一个自定义组件,将方法放到自定义组件中
      2. class AScriptComponent extends Component{
      3. static componentName: ‘AScriptComponent’,
      4. start() {
      5. this.txt = this.gameObject.getComponent(‘Text’)
      6. // 在组件中使用evax可先绑定evax组件,在evax组件上拿到evax对象,进行事件触发和修改
      7. const evax = this.gameObject.getComponent(‘EvaX’)
      8. this.evax = evax.evax
      9. },
      10. setName(store, oldStore) {
      11. txt.text = store.user.name // 设置新的text内容
      12. setTimeout(()=>{
      13. this.evax.emit(‘animationDown’) // 通知修改完毕,由其他的组件来承接变化,不在此案例中
      14. this.evax.store.age += 1 // 由其他的组件来承接变化,不在此案例中
      15. }, 1000)
      16. },
      17. popUp(store) {
      18. // 做事件对应操作
      19. }
      20. })
      21. // 添加自定义组件
      22. const aScript = go.addComponent(new AScriptComponent)

      创建 evax 组件,将需要绑定的事件写入,并且调用自定义组件上的事件

      1. // 添加evax组件
      2. go.addComponent(
      3. new EvaX({
      4. events: {
      5. ‘store.user.name’(store, oldStore) {
      6. // 建议把触发的方法放在其他自定义组件内部,以便与后续场景编辑器使用
      7. go.getComponent(AScriptComponent).setName(store, oldStore)
      8. },
      9. ‘store.user.age’(store, oldStore) {
      10. // …
      11. },
      12. popUp(…args) {
      13. go.getComponent(AScriptComponent).popUp(…args)
      14. }
      15. }
      16. })
      17. )
      ,