构建复杂游戏的又一神器

news/2024/7/19 13:53:34 标签: 游戏, java, js, html, dart
htmledit_views">
html" title=js>js_content">

前言

事件机制,相信很多人都知道,了解,也经常用到。

在设计模式中,它叫 「观察者模式」(又叫发布-订阅模式)。

它无处不在:

在Java中,它是「Java」的核心库html" title=java>java.utils.Observable」

在C#中,为它提供了语法糖支持:「event关键字」

在web浏览器的Javascript中,有内置的事件机制:window.addEventListener,Event

在Nodehtml" title=js>js中,也有内置库events

html" title=游戏>游戏引擎中也都是内置的存在

  1. CocosCreator的「cc.EventTarget」

  2. Laya的「Laya.EventDispatcher」

  3. 其他引擎都有

使用这种模式可以让我们「更好地解耦」html" title=游戏>游戏业务逻辑。

「但是」

这些事件机制的在 JS 和 TS 中的实现没能让我觉得满意(我都是使用过),总觉得缺了点什么。

  1. 携带数据没类型提示

    1. 消息发送者,没法获得要发送消息携带的数据类型提示

    2. 消息接收者,没法获得发送过来的数据类型提示

  2. 面对复杂的通信情况,没内置支持

    1. 想在消息发送点,接收到,消息接收器返回的数据(如果自己实现,将回调包在数据中传给消息接收者,让它执行这个回调)

    2. 事件发出去了,但消息接收者还没注册,错过了

  3. 不内置支持状态管理

    1. 很多地方需要监听角色等级变化事件然后去角色信息接口取角色等级状态做业务处理

    2. 也就是我们需要在多个地方监听同一个状态变化,然后去某个接口取出当前状态做业务处理。

    3. 很多时候,我们会遇到类似这种需求:

    4. 这样的处理重复而不优雅。

突然有一天逛「掘金」,看到这么一个文章分享:

构建复杂应用的神器,FBroadcast[1]

演示

demo测试展示

看完后,脑子里只有一个字: 这就是我想要的神器

  • 虽然它是用 Dart 写给 Flutter

  • 但没关系,借鉴一下,用 TypeScript 重写一下

  • (ps:部分说明也是复制过来的)

我喜欢逛掘金,虽然他们大多是分享 Web 前端相关的知识,但也有很多可以借鉴用到html" title=游戏>游戏前端的地方,受益匪浅。

介绍

一个基于TypeScript的一套「高效灵活」的广播系统,可以帮助开发者「轻松」「有序」的构建具有「极具复杂性的关联交互」「状态变化」html" title=游戏>游戏和应用。

特性

  • 基础事件机制的支持

  • 消息支持携带任意类型的数据(并有类型提示)

  • 支持函数this绑定或任意类型作为环境,一行代码就可以移除环境内所有的接收者

  • 易于构建局部/全局的状态管理

  • 支持双向通信

  • 支持不可思议的粘性广播

  • 基于TypeScript并提供极度舒适的类型提示

安装/获取

  • 源码获取

    git clone https://github.com/AILHC/EasyGameFrameworkOpen
    //文件路径:EasyGameFrameworkOpen/packages/broadcast
    
  • npm 安装

    npm i @ailhc/broadcast
    
  • 注意⚠️

    • 则需要到dist文件夹下,取出可以使用的模块规范类型的文件

    • 比如CocosCreator3D,支持systemhtml" title=js>js规范

    • 则可以拿systemhtml" title=js>js文件夹下的文件,复制到项目中,设置为插件就可以引入使用了

    • 如果所在项目不支持直接使用npm包

使用

  • 通过 broadcast 来注册,发送广播非常简便

//注册接收器
this._broadcast.on("testA", (str) => {
    //do something
})
//发送消息
this._broadcast.broadcast("testA", "string")
  • broadcast允许在注册/发送消息时,携带任意类型数据,并支持类型提示

  • broadcast允许在注册消息时,给自己透传数据(而非通过闭包取闭包外数据的方式)

    灵感来自Laya的EventDispatcher

    闭包使用不当容易出问题。

  • 开发者可以选择将特定类型的消息进行持久化,这样就能轻易实现广播式的全局状态管理。

    ⚠️注意,一个消息类型一旦持久化就只能通过 brocast.offAll(key) 来从广播系统中移除该类型的消息。

    broadcast.broadcast(
                //消息类型key
                "objTypeTest",
                //数据
                {a:1,b:"",c:false},
                //回调
                undefined,
                //持久化
                true
                )
    
  • 粘性广播

    broadcast.stickyBroadcast(
        //消息类型key
        "stringTypeTest",
        //数据
        "");
    

当广播系统中没有对应类型的接收器时,「粘性广播」 将会暂时滞留在系统中,直到有该类型的接收器被注册,则会立即发出广播(当广播系统中有对应类型的接收器时,就和普通广播具有相同的表现)。

  • 双向通信

    双向沟通,双倍效率

broadcast支持在广播发送点接收接收器返回的消息。

//发送消息
broadcast.broadcast(
    //消息类型key
    "numberTypeTest",
    //数据
    1,
    接收器返回的消息
    (data) => {
        // do something
    })

//注册接收器
broadcast.on("numberTypeTest", (data, callback) => {
            

    /// do something
    var result = logic();

    // 返回消息
    callback(result);
})
  • 支持函数this绑定或任意类型作为 环境绑定

    在CocosCreator中注册事件可以这样

    this.node.on(cc.Node.EventType.TOUCH_START, this.showAnimView, this)
    

    这个this可以用来调用showAnimView这个方法,不至于调用的方法里使用this时丢失this

    而在broadcast中也支持,还支持在环境解构时,开发者可以方便的一次性移除所有在该环境中注册的接收器。

    broadcast.offAllByContext(this)
    
  • 支持批量注册接收者

    broadcast.on([
        {
            //消息类型
            key: "numberTypeTest",
            //接收器
            listener: this.onNumberTypeTest,
            //环境
            context: this
        },
        {
            //消息类型
            key: "stringTypeTest",
            //接收器
            listener: this.onStringTypeTest,
            //环境
            context: this
        }
        //
    ])
    

    基本的使用就这些了

    具体的使用例子可以克隆仓库:EasyGameFramework[2]

    看基于CocosCreator2.4.2的demo examples/egf-ccc-full/assets/tests/broadcastTest

    打开这个场景:broadcastTest.fire

    看demo之前,需要安装环境哦,

    安装 npm ,然后到egf-ccc-full 根目录

    npm install
    

极度舒适的类型提示演示

//需要消息定义者,定义时添加如下类型声明
declare global {
    interface ITestKey extends broadcast.IMsgKey {
        testA: "testA",
        testB: "testB",
        testC: "testC",
        testD: "testD",
        //消息类型key提示
        objTypeTest: "objTypeTest"
    }
    interface ITestValueType extends broadcast.IMsgValueType {
        testA: string,
        testB: string,
        testC: string,
        testD: string,
        //对应消息类型的发消息和收消息的类型声明
        objTypeTest: { a: number, b: string, c: boolean }

    }
    interface ITestResultType extends broadcast.IResultType {
        testC: string,
        //双向通信返回数据类型声明
        objTypeTest: { callbackDataA: { hahah: string } }
    }
}
//然后在实例化broadcast时,注入类型
export default class TestBroadcast extends cc.Component {
    private _broadcast: Broadcast<ITestKey, ITestValueType, ITestResultType>
    start() {
        this._broadcast = new Broadcast<ITestKey, ITestValueType, ITestResultType>();
    }
}

最后

关注作者公众号,更多实用干货等着你

QQ 群: 1103157878
博客主页: https://ailhc.github.io/
掘金: https://juejin.cn/user/3069492195769469
github: https://github.com/AILHC

Reference

[1]

构建复杂应用的神器,FBroadcast: https://zhuanlan.zhihu.com/p/181668358

[2]

EasyGameFramework: https://github.com/AILHC/EasyGameFrameworkOpen


http://www.niftyadmin.cn/n/805499.html

相关文章

hashtable的用法

C#中哈希表(HashTable)的用法详解 1. 哈希表(HashTable)简述 在.NET Framework中&#xff0c;Hashtable是System.Collections命名空间提供的一个容器&#xff0c;用于处理和表现类似keyvalue的键值 对&#xff0c;其中key通常可用来快速查找&#xff0c;同时key是区分大小写&a…

nginx安装 yum install zlib 等 报错:Could not retrieve mirrorlist http://mirrorlist.centos.org

在安装nginx时&#xff0c;使用 yum install 给 nginx 安装所需要的环境的时候报错&#xff1a; 看到这个报错的时候我的第一反应和大多人一样&#xff0c;根据 “Network is unreachable” 以为是网络不通畅。我反复检查 ip&#xff0c;网关&#xff0c;DNS 以及各种 ping 后…

ajenti key word

os.chmod os.chmodos.chmod转载于:https://www.cnblogs.com/Jghost/p/af598a4493c414395ce735bc9e5da5bd.html

设计一个简易的引导任务框架(2) | 4.23粉丝赠书

今天是4.23世界读书日&#xff0c;公众号向支持的小伙伴们送出下面3本技术图书&#xff08;三选一&#xff09;&#xff01;参与方式&#xff1a;本文点赞留言&#xff0c;必须超过20字&#xff0c;以及你想要的图书名字参与活动积赞最多的前3名读者&#xff0c;将会获得赠书&a…

Spring Boot bootstrap.yml外置

有时候我们是需要将bootstrap.yml文件的外置的,也即是说&#xff0c;在spring boot应用启动后&#xff0c;不直接使用jar包里面的bootstrap.yml文件&#xff0c;而是读取某个目录下的bootstrap.yml文件,然后进行覆盖。注意在spring boot 2.0之前的版本&#xff0c;得使用如下参…

腾讯来做客了!我除了说牛啤,还能说什么?

“Cocos 和 Native 交互好复杂&#xff0c;能不能简单一些&#xff1f;我们尝试着使用注解来解决这个问题。”背景ABCBinding 的结构设计具体实现通过 tag 找到 Native 方法约束 Native 方法优雅的回调其他 feature抹平系统差异无需关心线程切换支持超时彩蛋&#xff1a;在热更…

Quick Finder!就是香,还要看怎么尝

在此感谢『陈皮皮』对社区做的贡献&#xff0c;将自己辛勤开发的插件三件套赠送给了Cocos官方旗舰店&#xff0c;做为五一活动的礼品&#xff01;今天&#xff0c;皮皮还发来了Quick Finder的插件使用教程&#xff0c;真的是太感动了温馨提示&#xff1a;明天4月30号&#xff0…

福利,送书!架构师是怎样炼成的?

文末参与抽奖&#xff0c;送出3本《架构师的自我修练》成为架构师是很多程序员的梦想&#xff1a;规划复杂系统的架构设计并决定系统的技术发展方向&#xff1b;设计开发框架让开发工程师根据自己设定的规范和接口编程&#xff1b;在公司内部的会议上发表意见一言九鼎&#xff…