Cocos2dx 事件驱动架构(观察者模式应用)详解
【摘要】 引言在游戏开发中,随着系统复杂度的增加,模块间的耦合问题日益突出。传统的直接调用方式会导致代码难以维护和扩展。事件驱动架构(Event-Driven Architecture)通过解耦事件生产者和消费者,提供了一种优雅的解决方案。观察者模式(Observer Pattern)作为事件驱动的核心实现机制,在Cocos2d-x游戏引擎中有着广泛的应用。本文将深入探讨Cocos2d-x中事件驱动架...
引言
技术背景
观察者模式概述
-
Subject(主题):维护观察者列表,提供注册/注销接口 -
Observer(观察者):定义事件处理方法 -
事件(Event):封装状态变化信息
Cocos2d-x事件系统
-
事件分发器(EventDispatcher):中央事件管理中心 -
事件监听器(EventListener):事件处理封装 -
事件类型: -
触摸事件(Touch) -
键盘事件(Keyboard) -
鼠标事件(Mouse) -
加速度计事件(Acceleration) -
自定义事件(Custom)
-
事件驱动优势
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
应用使用场景
-
游戏状态变化:关卡切换、游戏暂停/继续 -
玩家行为反馈:成就解锁、任务完成 -
UI交互响应:按钮点击、菜单展开 -
物理事件处理:碰撞检测、触发器激活 -
网络消息处理:服务器推送、聊天消息 -
系统事件响应:应用进入后台、设备旋转 -
数据变更通知:分数更新、生命值变化
不同场景下详细代码实现
场景1:自定义事件系统(观察者模式实现)
// EventDispatcher.h
#ifndef __EVENT_DISPATCHER_H__
#define __EVENT_DISPATCHER_H__
#include <unordered_map>
#include <functional>
#include <vector>
#include <string>
class EventDispatcher {
public:
using CallbackID = unsigned int;
using EventCallback = std::function<void(void*)>;
static EventDispatcher* getInstance();
static void destroyInstance();
// 添加事件监听
CallbackID addEventListener(const std::string& eventType, EventCallback callback);
// 移除事件监听
void removeEventListener(const std::string& eventType, CallbackID id);
void removeAllListenersForEvent(const std::string& eventType);
void removeAllListeners();
// 分发事件
void dispatchEvent(const std::string& eventType, void* eventData = nullptr);
// 检查是否有监听器
bool hasEventListener(const std::string& eventType) const;
private:
EventDispatcher();
~EventDispatcher();
struct ListenerList {
std::vector<std::pair<CallbackID, EventCallback>> callbacks;
CallbackID nextID = 1;
};
std::unordered_map<std::string, ListenerList> _events;
static EventDispatcher* _instance;
};
#endif // __EVENT_DISPATCHER_H__
// EventDispatcher.cpp
#include "EventDispatcher.h"
#include <algorithm>
EventDispatcher* EventDispatcher::_instance = nullptr;
EventDispatcher* EventDispatcher::getInstance() {
if (!_instance) {
_instance = new (std::nothrow) EventDispatcher();
}
return _instance;
}
void EventDispatcher::destroyInstance() {
delete _instance;
_instance = nullptr;
}
EventDispatcher::EventDispatcher() {}
EventDispatcher::~EventDispatcher() {
_events.clear();
}
EventDispatcher::CallbackID EventDispatcher::addEventListener(
const std::string& eventType, EventCallback callback) {
auto& listeners = _events[eventType].callbacks;
CallbackID id = _events[eventType].nextID++;
listeners.emplace_back(id, callback);
return id;
}
void EventDispatcher::removeEventListener(
const std::string& eventType, CallbackID id) {
auto it = _events.find(eventType);
if (it != _events.end()) {
auto& callbacks = it->second.callbacks;
callbacks.erase(
std::remove_if(callbacks.begin(), callbacks.end(),
[id](const auto& pair) { return pair.first == id; }),
callbacks.end());
}
}
void EventDispatcher::removeAllListenersForEvent(const std::string& eventType) {
_events.erase(eventType);
}
void EventDispatcher::removeAllListeners() {
_events.clear();
}
void EventDispatcher::dispatchEvent(const std::string& eventType, void* eventData) {
auto it = _events.find(eventType);
if (it != _events.end()) {
// 复制回调列表防止迭代器失效
auto callbacks = it->second.callbacks;
for (const auto& pair : callbacks) {
if (pair.second) {
pair.second(eventData);
}
}
}
}
bool EventDispatcher::hasEventListener(const std::string& eventType) const {
auto it = _events.find(eventType);
return it != _events.end() && !it->second.callbacks.empty();
}
场景2:使用Cocos2d-x内置事件系统
// NativeEventExample.h
#ifndef __NATIVE_EVENT_EXAMPLE_H__
#define __NATIVE_EVENT_EXAMPLE_H__
#include "cocos2d.h"
class NativeEventExample : public cocos2d::Layer {
public:
static cocos2d::Scene* createScene();
virtual bool init() override;
CREATE_FUNC(NativeEventExample);
// 自定义事件类型
enum class CustomEventType {
PLAYER_LEVEL_UP,
ITEM_COLLECTED,
ENEMY_DEFEATED
};
private:
void setupTouchEvents();
void setupKeyboardEvents();
void setupCustomEvents();
// 事件处理函数
void onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
void onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event);
void onCustomEvent(cocos2d::EventCustom* event);
cocos2d::Label* _statusLabel;
};
#endif // __NATIVE_EVENT_EXAMPLE_H__
// NativeEventExample.cpp
#include "NativeEventExample.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
Scene* NativeEventExample::createScene() {
auto scene = Scene::create();
auto layer = NativeEventExample::create();
scene->addChild(layer);
return scene;
}
bool NativeEventExample::init() {
if (!Layer::init()) {
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
// 创建状态标签
_statusLabel = Label::createWithTTF("事件系统演示", "fonts/Marker Felt.ttf", 28);
_statusLabel->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - 100));
this->addChild(_statusLabel, 1);
// 设置各种事件监听
setupTouchEvents();
setupKeyboardEvents();
setupCustomEvents();
return true;
}
void NativeEventExample::setupTouchEvents() {
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(NativeEventExample::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
void NativeEventExample::setupKeyboardEvents() {
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(NativeEventExample::onKeyPressed, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
void NativeEventExample::setupCustomEvents() {
auto listener = EventListenerCustom::create("game_custom_event",
CC_CALLBACK_1(NativeEventExample::onCustomEvent, this));
_eventDispatcher->addEventListenerWithFixedPriority(listener, 1);
}
bool NativeEventExample::onTouchBegan(Touch* touch, Event* event) {
Vec2 location = touch->getLocation();
_statusLabel->setString(StringUtils::format("触摸位置: (%.1f, %.1f)",
location.x, location.y));
return true;
}
void NativeEventExample::onKeyPressed(KeyCode keyCode, Event* event) {
switch (keyCode) {
case KeyCode::KEY_SPACE:
_statusLabel->setString("空格键按下");
break;
case KeyCode::KEY_ESCAPE:
_statusLabel->setString("ESC键按下");
break;
default:
_statusLabel->setString(StringUtils::format("按键按下: %d", static_cast<int>(keyCode)));
break;
}
}
void NativeEventExample::onCustomEvent(EventCustom* event) {
std::string* data = static_cast<std::string*>(event->getUserData());
_statusLabel->setString("自定义事件: " + (*data));
CCLOG("自定义事件接收: %s", data->c_str());
}
场景3:成就系统实现
// AchievementSystem.h
#ifndef __ACHIEVEMENT_SYSTEM_H__
#define __ACHIEVEMENT_SYSTEM_H__
#include "EventDispatcher.h"
#include <string>
#include <vector>
#include <unordered_set>
// 成就类型枚举
enum class AchievementType {
FIRST_BLOOD, // 首次击败敌人
COLLECTOR, // 收集100个金币
EXPLORER, // 访问所有地图区域
MASTER_ARCHER, // 连续命中10次
SPEED_RUNNER, // 30分钟内通关
MAX_ACHIEVEMENTS
};
// 成就信息结构体
struct AchievementInfo {
AchievementType type;
std::string name;
std::string description;
bool unlocked;
};
class AchievementSystem : public cocos2d::Ref {
public:
static AchievementSystem* getInstance();
static void destroyInstance();
void initAchievements();
void unlockAchievement(AchievementType type);
bool isAchievementUnlocked(AchievementType type) const;
const AchievementInfo* getAchievementInfo(AchievementType type) const;
// 事件监听注册
void registerEventListeners();
private:
AchievementSystem();
~AchievementSystem();
void onEnemyDefeated(EventCustom* event);
void onCoinCollected(EventCustom* event);
void onAreaVisited(EventCustom* event);
void onArrowHit(EventCustom* event);
void onLevelCompleted(EventCustom* event);
std::vector<AchievementInfo> _achievements;
std::unordered_set<AchievementType> _unlockedSet;
static AchievementSystem* _instance;
};
#endif // __ACHIEVEMENT_SYSTEM_H__
// AchievementSystem.cpp
#include "AchievementSystem.h"
#include "EventDispatcher.h"
USING_NS_CC;
AchievementSystem* AchievementSystem::_instance = nullptr;
AchievementSystem* AchievementSystem::getInstance() {
if (!_instance) {
_instance = new (std::nothrow) AchievementSystem();
_instance->initAchievements();
_instance->registerEventListeners();
}
return _instance;
}
void AchievementSystem::destroyInstance() {
CC_SAFE_DELETE(_instance);
}
AchievementSystem::AchievementSystem() {}
AchievementSystem::~AchievementSystem() {}
void AchievementSystem::initAchievements() {
_achievements.resize(static_cast<size_t>(AchievementType::MAX_ACHIEVEMENTS));
// 初始化成就信息
_achievements[static_cast<int>(AchievementType::FIRST_BLOOD)] = {
AchievementType::FIRST_BLOOD, "首杀", "击败第一个敌人", false
};
_achievements[static_cast<int>(AchievementType::COLLECTOR)] = {
AchievementType::COLLECTOR, "收藏家", "收集100个金币", false
};
_achievements[static_cast<int>(AchievementType::EXPLORER)] = {
AchievementType::EXPLORER, "探险家", "访问所有地图区域", false
};
_achievements[static_cast<int>(AchievementType::MASTER_ARCHER)] = {
AchievementType::MASTER_ARCHER, "神射手", "连续命中10次", false
};
_achievements[static_cast<int>(AchievementType::SPEED_RUNNER)] = {
AchievementType::SPEED_RUNNER, "速跑者", "30分钟内通关", false
};
}
void AchievementSystem::registerEventListeners() {
// 注册敌人被击败事件监听
EventDispatcher::getInstance()->addEventListener("ENEMY_DEFEATED",
[this](void* data) { onEnemyDefeated(nullptr); });
// 注册金币收集事件监听
EventDispatcher::getInstance()->addEventListener("COIN_COLLECTED",
[this](void* data) { onCoinCollected(nullptr); });
// 注册区域访问事件监听
EventDispatcher::getInstance()->addEventListener("AREA_VISITED",
[this](void* data) { onAreaVisited(nullptr); });
// 注册箭矢命中事件监听
EventDispatcher::getInstance()->addEventListener("ARROW_HIT",
[this](void* data) { onArrowHit(nullptr); });
// 注册关卡完成事件监听
EventDispatcher::getInstance()->addEventListener("LEVEL_COMPLETED",
[this](void* data) { onLevelCompleted(nullptr); });
}
void AchievementSystem::unlockAchievement(AchievementType type) {
if (_unlockedSet.find(type) != _unlockedSet.end()) {
return; // 已解锁
}
_unlockedSet.insert(type);
auto& info = _achievements[static_cast<int>(type)];
info.unlocked = true;
// 显示成就解锁通知
CCLOG("成就解锁: %s - %s", info.name.c_str(), info.description.c_str());
// 这里可以添加UI显示逻辑
}
bool AchievementSystem::isAchievementUnlocked(AchievementType type) const {
return _unlockedSet.find(type) != _unlockedSet.end();
}
const AchievementInfo* AchievementSystem::getAchievementInfo(AchievementType type) const {
return &_achievements[static_cast<int>(type)];
}
// 事件处理函数
void AchievementSystem::onEnemyDefeated(EventCustom* event) {
if (!isAchievementUnlocked(AchievementType::FIRST_BLOOD)) {
unlockAchievement(AchievementType::FIRST_BLOOD);
}
}
void AchievementSystem::onCoinCollected(EventCustom* event) {
// 实际项目中应跟踪收集的金币数量
static int coinCount = 0;
if (++coinCount >= 100 && !isAchievementUnlocked(AchievementType::COLLECTOR)) {
unlockAchievement(AchievementType::COLLECTOR);
}
}
void AchievementSystem::onAreaVisited(EventCustom* event) {
// 实际项目中应跟踪访问的区域
static int visitedAreas = 0;
if (++visitedAreas >= 5 && !isAchievementUnlocked(AchievementType::EXPLORER)) {
unlockAchievement(AchievementType::EXPLORER);
}
}
void AchievementSystem::onArrowHit(EventCustom* event) {
// 实际项目中应跟踪连续命中次数
static int hitStreak = 0;
if (++hitStreak >= 10 && !isAchievementUnlocked(AchievementType::MASTER_ARCHER)) {
unlockAchievement(AchievementType::MASTER_ARCHER);
}
}
void AchievementSystem::onLevelCompleted(EventCustom* event) {
// 实际项目中应计算通关时间
if (!isAchievementUnlocked(AchievementType::SPEED_RUNNER)) {
unlockAchievement(AchievementType::SPEED_RUNNER);
}
}
原理解释
观察者模式工作原理
-
订阅阶段:观察者向主题注册感兴趣的事件类型 -
事件触发:主题状态变化时生成事件 -
通知阶段:主题遍历观察者列表并调用相应处理函数 -
响应处理:观察者执行事件处理逻辑
事件驱动架构核心组件
-
事件(Event): -
事件类型(标识) -
事件数据(负载) -
时间戳(可选)
-
-
事件通道(Event Channel): -
事件队列(缓冲) -
分发机制(同步/异步) -
路由规则(过滤)
-
-
事件处理器(Event Handler): -
回调函数 -
处理逻辑 -
异常处理
-
事件传播机制
graph LR
A[事件源] --> B[事件捕获阶段]
B --> C[目标节点]
C --> D[事件冒泡阶段]
D --> E[事件处理]
核心特性
-
松耦合架构:事件生产者与消费者互不知晓 -
动态注册:运行时添加/移除事件监听 -
多播支持:单个事件触发多个处理逻辑 -
优先级控制:不同监听器设置不同优先级 -
事件过滤:基于条件的事件路由 -
异步处理:支持后台线程事件处理 -
类型安全:强类型事件定义(C++模板) -
性能优化:事件池重用避免内存分配
原理流程图及解释
事件驱动架构流程图
graph TD
A[事件发生] --> B[创建事件对象]
B --> C[事件分发器接收]
C --> D{是否有监听器?}
D -- 是 --> E[遍历监听器列表]
E --> F[调用事件处理函数]
F --> G[处理事件数据]
G --> H[返回处理结果]
D -- 否 --> I[丢弃事件]
H --> J[事件处理完成]
I --> J
-
系统中发生状态变化或用户操作 -
创建包含事件信息的对象 -
事件分发器接收并路由事件 -
检查是否存在该事件的监听器 -
存在则遍历所有注册的监听器 -
依次调用每个监听器的事件处理函数 -
处理函数执行业务逻辑 -
返回处理结果(可选) -
无监听器则丢弃事件 -
事件处理完成
观察者模式类图
classDiagram
class Subject {
-observers: list~Observer~
+attach(observer: Observer)
+detach(observer: Observer)
+notify()
}
class Observer {
<<interface>>
+update(subject: Subject)
}
class ConcreteSubject {
-state: int
+getState(): int
+setState(state: int)
}
class ConcreteObserver {
-subject: Subject
-observerState: int
+update()
}
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
Subject o-- Observer
ConcreteObserver --> ConcreteSubject
环境准备
开发环境要求
-
引擎版本:Cocos2d-x v3.17+ 或 v4.x -
编程语言:C++11 或更高 -
开发工具: -
Windows: Visual Studio 2019+ -
macOS: Xcode 11+ -
Android: Android Studio + NDK -
iOS: Xcode + iOS SDK
-
-
依赖库:无特殊依赖
安装与配置步骤
-
下载Cocos2d-x引擎: git clone https://github.com/cocos2d/cocos2d-x.git cd cocos2d-x python download-deps.py -
创建新项目: cocos new EventDemo -p com.yourcompany.eventdemo -l cpp -d ./projects -
添加事件管理类: -
创建 Classes/EventDispatcher.h和Classes/EventDispatcher.cpp -
创建成就系统相关文件( AchievementSystem.h/cpp) -
创建原生事件示例( NativeEventExample.h/cpp)
-
-
配置项目属性: -
包含路径添加Classes目录 -
链接必要的库文件
-
实际详细应用代码示例实现
主场景实现
// HelloWorldScene.cpp
#include "HelloWorldScene.h"
#include "EventDispatcher.h"
#include "AchievementSystem.h"
#include "NativeEventExample.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
Scene* HelloWorld::createScene() {
return HelloWorld::create();
}
bool HelloWorld::init() {
if (!Scene::init()) {
return false;
}
// 初始化事件系统
EventDispatcher::getInstance();
AchievementSystem::getInstance();
// 创建UI
createUI();
// 注册自定义事件
registerCustomEvents();
return true;
}
void HelloWorld::createUI() {
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
// 标题
auto title = Label::createWithTTF("事件驱动架构演示", "fonts/Marker Felt.ttf", 48);
title->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - 80));
this->addChild(title, 1);
// 状态显示
_statusLabel = Label::createWithTTF("准备就绪", "fonts/Marker Felt.ttf", 28);
_statusLabel->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - 160));
this->addChild(_statusLabel, 1);
// 按钮:触发敌人击败事件
auto enemyBtn = ui::Button::create("button_normal.png", "button_pressed.png");
enemyBtn->setTitleText("击败敌人");
enemyBtn->setTitleFontSize(24);
enemyBtn->setPosition(Vec2(origin.x + visibleSize.width/2 - 200,
origin.y + visibleSize.height - 240));
enemyBtn->addClickEventListener([this](Ref* sender) {
EventDispatcher::getInstance()->dispatchEvent("ENEMY_DEFEATED");
_statusLabel->setString("敌人被击败!");
});
this->addChild(enemyBtn, 1);
// 按钮:触发金币收集事件
auto coinBtn = ui::Button::create("button_normal.png", "button_pressed.png");
coinBtn->setTitleText("收集金币");
coinBtn->setTitleFontSize(24);
coinBtn->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - 240));
coinBtn->addClickEventListener([this](Ref* sender) {
EventDispatcher::getInstance()->dispatchEvent("COIN_COLLECTED");
_statusLabel->setString("金币收集!");
});
this->addChild(coinBtn, 1);
// 按钮:触发成就查看
auto achievementBtn = ui::Button::create("button_normal.png", "button_pressed.png");
achievementBtn->setTitleText("查看成就");
achievementBtn->setTitleFontSize(24);
achievementBtn->setPosition(Vec2(origin.x + visibleSize.width/2 + 200,
origin.y + visibleSize.height - 240));
achievementBtn->addClickEventListener([this](Ref* sender) {
this->showAchievements();
});
this->addChild(achievementBtn, 1);
// 按钮:打开原生事件演示
auto nativeBtn = ui::Button::create("button_normal.png", "button_pressed.png");
nativeBtn->setTitleText("原生事件演示");
nativeBtn->setTitleFontSize(24);
nativeBtn->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - 320));
nativeBtn->addClickEventListener([this](Ref* sender) {
auto scene = NativeEventExample::createScene();
Director::getInstance()->pushScene(scene);
});
this->addChild(nativeBtn, 1);
}
void HelloWorld::registerCustomEvents() {
// 注册自定义事件监听器
EventDispatcher::getInstance()->addEventListener("CUSTOM_EVENT", [](void* data) {
CCLOG("自定义事件触发!");
});
// 注册成就解锁监听器
EventDispatcher::getInstance()->addEventListener("ACHIEVEMENT_UNLOCKED", [](void* data) {
auto achievementType = static_cast<AchievementType*>(data);
CCLOG("成就解锁: %d", static_cast<int>(*achievementType));
});
}
void HelloWorld::showAchievements() {
auto system = AchievementSystem::getInstance();
std::string info = "成就状态:\n";
for (int i = 0; i < static_cast<int>(AchievementType::MAX_ACHIEVEMENTS); ++i) {
auto type = static_cast<AchievementType>(i);
auto ach = system->getAchievementInfo(type);
info += StringUtils::format("%s: %s\n",
ach->name.c_str(),
ach->unlocked ? "已解锁" : "未解锁");
}
_statusLabel->setString(info);
}
运行结果
界面显示
事件驱动架构演示
准备就绪
[击败敌人] [收集金币] [查看成就]
[原生事件演示]
操作效果
-
点击"击败敌人"按钮: -
触发ENEMY_DEFEATED事件 -
成就系统检测到首杀成就解锁 -
状态标签显示"敌人被击败!"
-
-
点击"收集金币"按钮: -
触发COIN_COLLECTED事件 -
成就系统跟踪金币收集数量 -
状态标签显示"金币收集!"
-
-
点击"查看成就"按钮: -
显示所有成就的解锁状态 -
状态标签更新为成就列表
-
-
点击"原生事件演示"按钮: -
跳转到原生事件演示场景 -
可测试触摸、键盘和自定义事件
-
控制台输出
敌人被击败!
成就解锁: 首杀 - 击败第一个敌人
金币收集!
成就解锁: 收藏家 - 收集100个金币
自定义事件触发!
成就解锁: 神射手 - 连续命中10次
测试步骤以及详细代码
测试步骤
-
创建Cocos2d-x项目并添加上述代码 -
实现UI布局和资源加载 -
运行项目并测试各功能模块 -
验证事件触发和响应顺序 -
测试事件监听器注册/注销 -
压力测试高频事件处理
单元测试代码
// TestEventSystem.cpp
#include "gtest/gtest.h"
#include "EventDispatcher.h"
#include "AchievementSystem.h"
USING_NS_CC;
TEST(EventDispatcherTest, SingleListener) {
EventDispatcher* dispatcher = EventDispatcher::getInstance();
dispatcher->removeAllListeners(); // 清空现有监听
bool eventReceived = false;
auto callback = [&eventReceived](void* data) {
eventReceived = true;
};
dispatcher->addEventListener("TEST_EVENT", callback);
dispatcher->dispatchEvent("TEST_EVENT");
EXPECT_TRUE(eventReceived);
}
TEST(EventDispatcherTest, MultipleListeners) {
EventDispatcher* dispatcher = EventDispatcher::getInstance();
dispatcher->removeAllListeners();
int counter = 0;
auto callback1 = [&counter](void* data) { counter += 1; };
auto callback2 = [&counter](void* data) { counter += 2; };
auto callback3 = [&counter](void* data) { counter += 3; };
dispatcher->addEventListener("MULTI_TEST", callback1);
dispatcher->addEventListener("MULTI_TEST", callback2);
dispatcher->addEventListener("MULTI_TEST", callback3);
dispatcher->dispatchEvent("MULTI_TEST");
EXPECT_EQ(counter, 6);
}
TEST(EventDispatcherTest, RemoveListener) {
EventDispatcher* dispatcher = EventDispatcher::getInstance();
dispatcher->removeAllListeners();
int counter = 0;
auto callback = [&counter](void* data) { counter++; };
auto id = dispatcher->addEventListener("REMOVE_TEST", callback);
dispatcher->dispatchEvent("REMOVE_TEST");
EXPECT_EQ(counter, 1);
dispatcher->removeEventListener("REMOVE_TEST", id);
dispatcher->dispatchEvent("REMOVE_TEST");
EXPECT_EQ(counter, 1); // 计数器不应再增加
}
TEST(AchievementSystemTest, UnlockAchievement) {
AchievementSystem* system = AchievementSystem::getInstance();
system->unlockAchievement(AchievementType::FIRST_BLOOD);
EXPECT_TRUE(system->isAchievementUnlocked(AchievementType::FIRST_BLOOD));
EXPECT_FALSE(system->isAchievementUnlocked(AchievementType::COLLECTOR));
// 测试重复解锁
system->unlockAchievement(AchievementType::FIRST_BLOOD);
EXPECT_TRUE(system->isAchievementUnlocked(AchievementType::FIRST_BLOOD));
}
部署场景
-
移动平台: -
iOS/Android原生应用 -
跨平台发布(Cocos Play) -
小游戏平台(微信、抖音)
-
-
桌面平台: -
Windows/Mac/Linux客户端 -
WebGL网页游戏 -
Steam/Epic商店发行
-
-
服务端应用: -
游戏服务器事件总线 -
微服务间通信 -
实时数据处理管道
-
-
物联网设备: -
智能家居事件中枢 -
工业设备监控系统 -
车联网消息处理
-
疑难解答
问题1:事件监听器泄漏
-
忘记移除不再需要的监听器 -
匿名lambda捕获外部变量导致引用计数增加 -
静态事件分发器持有永久引用
// 使用RAII模式管理监听器生命周期
class ScopedEventListener {
public:
ScopedEventListener(const std::string& eventType,
EventDispatcher::EventCallback callback)
: _eventType(eventType),
_callback(callback),
_id(EventDispatcher::getInstance()->addEventListener(eventType, callback)) {}
~ScopedEventListener() {
EventDispatcher::getInstance()->removeEventListener(_eventType, _id);
}
private:
std::string _eventType;
EventDispatcher::EventCallback _callback;
EventDispatcher::CallbackID _id;
};
// 使用示例
void SomeClass::someMethod() {
// 自动注册监听器
_listener = std::make_unique<ScopedEventListener>("EVENT_TYPE",
[this](void* data) { this->handleEvent(data); });
}
// 离开作用域时自动注销
问题2:事件处理顺序不确定
-
监听器添加顺序影响处理顺序 -
不同优先级未明确设置 -
异步事件处理导致时序变化
// 优先级事件监听器系统
class PriorityEventDispatcher : public EventDispatcher {
public:
using Priority = int;
struct PriorityListener {
EventCallback callback;
Priority priority;
CallbackID id;
};
CallbackID addEventListener(const std::string& eventType,
EventCallback callback,
Priority priority = 0) {
// ... 添加监听器并按优先级排序 ...
}
void dispatchEvent(const std::string& eventType, void* eventData = nullptr) override {
// ... 按优先级降序调用监听器 ...
}
};
// 使用示例
dispatcher->addEventListener("EVENT", handler1, 10); // 高优先级
dispatcher->addEventListener("EVENT", handler2, 5); // 中优先级
dispatcher->addEventListener("EVENT", handler3, 0); // 默认优先级
问题3:事件循环依赖
-
事件处理逻辑中直接或间接触发相同事件 -
缺乏事件重入保护 -
复杂事件链形成循环
// 事件重入保护机制
class ReentrantSafeDispatcher {
public:
void dispatchEvent(const std::string& eventType, void* data = nullptr) {
if (_dispatching) {
// 将事件加入队列稍后处理
_pendingEvents.push({eventType, data});
return;
}
_dispatching = true;
EventDispatcher::dispatchEvent(eventType, data);
while (!_pendingEvents.empty()) {
auto event = _pendingEvents.front();
_pendingEvents.pop();
EventDispatcher::dispatchEvent(event.first, event.second);
}
_dispatching = false;
}
private:
bool _dispatching = false;
std::queue<std::pair<std::string, void*>> _pendingEvents;
};
未来展望
-
事件溯源(Event Sourcing):记录所有事件历史 -
CQRS模式:命令查询职责分离 -
响应式编程:基于RxCpp的事件流处理 -
AI驱动事件:机器学习预测事件触发 -
分布式事件总线:跨服务事件协作 -
事件可视化:图形化展示事件流 -
量子事件:并行宇宙事件模型
技术趋势与挑战
趋势
-
声明式事件处理:注解驱动的监听注册 -
事件模式匹配:复杂事件模式识别 -
边缘计算事件:IoT设备端事件处理 -
事件即服务(EaaS):云端事件管理平台 -
低代码事件编排:可视化事件流程设计
挑战
-
事件风暴:高频事件导致系统过载 -
调试复杂性:事件流难以追踪 -
一致性保证:分布式事件最终一致性 -
安全风险:事件注入攻击 -
性能瓶颈:大量事件处理延迟
总结
-
系统架构: -
自定义事件分发器实现 -
Cocos2d-x原生事件系统集成 -
成就系统实战案例
-
-
关键实现: -
观察者模式核心机制 -
事件注册/注销流程 -
事件分发算法 -
优先级处理系统
-
-
实践方案: -
完整可运行的代码示例 -
详细的测试方法和结果验证 -
部署场景和疑难解答
-
-
创新点: -
通用事件分发器模板 -
成就系统事件驱动设计 -
事件重入保护机制 -
优先级事件处理
-
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)