TH1/Book/3.4事件机制EventSystem.md
2025-07-17 18:26:28 +08:00

135 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 事件机制EventSystem
ECS最重要的特性一是数据跟逻辑分离二是数据驱动逻辑。什么是数据驱动逻辑呢不太好理解我们举个例子
一个moba游戏英雄都有血条血条会在人物头上显示也会在左上方头像UI上显示。这时候服务端发来一个扣血消息。我们怎么处理这个消息第一种方法在消息处理函数中修改英雄的血数值修改头像上血条显示同时修改头像UI的血条。这种方式很明显造成了模块间的耦合。第二种方法扣血消息处理函数中只是改变血值血值的改变抛出一个hpchange的事件人物头像模块跟UI模块都订阅血值改变事件在订阅的方法中分别处理自己的逻辑这样各个模块负责自己的逻辑没有耦合。
ET提供了多种事件事件都是可以多次订阅的:
1. AwakeSystem组件工厂创建组件后抛出只抛出一次可以带参数
```csharp
Player player = ComponentFactory.Create<Player>();
// 订阅Player的Awake事件
public class PlayerAwakeSystem: AwakeSystem<Player>
{
public override void Awake(Player self)
{
}
}
```
2. StartSystem组件UpdateSystem调用前抛出
```csharp
// 订阅Player的Start事件
public class PlayerStartSystem: StartSystem<Player>
{
public override void Start(Player self)
{
}
}
```
3. UpdateSystem组件每帧抛出
```csharp
// 订阅Player的Update事件
public class PlayerUpdateSystem: UpdateSystem<Player>
{
public override void Update(Player self)
{
}
}
```
4. DestroySystem组件删除时抛出
```csharp
// 订阅Player的Destroy事件
public class PlayerDestroySystem: DestroySystem<Player>
{
public override void Destroy(Player self)
{
}
}
Player player = ComponentFactory.Create<Player>();
// 这里会触发Destroy事件
player.Dispose();
```
5. ChangeSystem组件内容改变时抛出需要开发者手动触发
```csharp
// 订阅Player的Destroy事件
public class PlayerChangeSystem: ChangeSystem<Player>
{
public override void Change(Player self)
{
}
}
Player player = ComponentFactory.Create<Player>();
// 需要手动触发ChangeSystem
Game.EventSystem.Change(player);
```
6. DeserializeSystem组件反序列化之后抛出
```csharp
// 订阅Player的Deserialize事件
public class PlayerDeserializeSystem: DeserializeSystem<Player>
{
public override void Deserialize(Player self)
{
}
}
// 这里player2会触发Deserialize事件
Player player2 = MongoHelper.FromBson<Player>(player.ToBson());
```
7. LoadSystemEventSystem加载dll时抛出用于服务端热更新重新加载dll做一些处理比如重新注册handler
```csharp
// 订阅Player的Load事件
public class PlayerLoadSystem: LoadSystem<Player>
{
public override void Load(Player self)
{
}
}
```
8. 普通的Event由开发者自己抛出可以最多带三个参数。另外客户端热更层也可以订阅mono层的Event事件
```csharp
int oldhp = 10;
int newhp = 5;
// 抛出hp改变事件
Game.EventSystem.Run("HpChange", oldhp, newhp);
// UI订阅hp改变事件
[Event("HpChange")]
public class HpChange_ShowUI: AEvent<int, int>
{
public override void Run(int a, int b)
{
throw new NotImplementedException();
}
}
// 模型头顶血条模块也订阅hp改变事件
[Event("HpChange")]
public class HpChange_ModelHeadChange: AEvent<int, int>
{
public override void Run(int a, int b)
{
throw new NotImplementedException();
}
}
```
9. 除此之外还有很多事件例如消息事件。消息事件使用MessageHandler来声明可以带参数指定哪种服务器需要订阅。
```csharp
[MessageHandler(AppType.Gate)]
public class C2G_LoginGateHandler : AMRpcHandler<C2G_LoginGate, G2C_LoginGate>
{
protected override void Run(Session session, C2G_LoginGate message, Action<G2C_LoginGate> reply)
{
G2C_LoginGate response = new G2C_LoginGate();
reply(response);
}
}
```
更具体的消息事件等到讲消息的时候再细细讲解了
10. 数值事件,数值模块再讲解
......, 更多的事件由自己去开发。
ET框架的逻辑就是由以上各种事件来驱动的。