15.事件中心:实现

23、以用户为中心的设计与事件风暴实践 本文探讨了以用户为中心的设计基础与事件风暴实践,介绍了如何通过同理心地图、影响映射等方法深入了解用户需求,并全面解析了事件风暴的准备、操作步骤与实际应用案例。事件风暴作为一种协作性强、可视化程度高的实践方法,能够帮助团队打破知识壁垒,发现潜在问题并优化业务流程。通过案例分析和mermaid流程图,文章为读者提供了可操作的指导和价值体现过程,旨在提升产品设计和开发效率。 阅读详情

一、实现目标

敌人死亡时,需要通知其他系统执行对应逻辑:

敌人死亡
├── Level:游戏成功通关
└── Player:人物升级

Enemy 不直接引用 Level 和 Player,而是通过 EventMgr 发送死亡事件,从而降低对象之间的耦合度。

二、事件中心的数据结构

Dictionary<string, UnityAction> eventDic;
  • string:事件的唯一标识名。
  • UnityAction:事件触发时需要执行的方法。
  • Dictionary:根据事件名称找到对应的所有监听方法。
    敌人死亡事件使用常量保存:
public const string EnemyDieEvent = "EnemyDieEvent";

使用常量可以统一事件名称,避免手写字符串时出现拼写错误。

三、添加事件监听

Level 和 Player 在 Awake() 中监听敌人死亡事件:

EventMgr.Instance.AddEventListener
(
    EventMgr.EnemyDieEvent,
    ClearLevel
);

如果字典中已经存在该事件,就使用 += 添加监听方法;否则创建新的事件记录。

四、触发事件

敌人血量归零后触发死亡事件:

EventMgr.Instance.EventTrigger(EventMgr.EnemyDieEvent);

事件中心找到 EnemyDieEvent 对应的委托,并执行其中保存的全部方法。

按下 J
  ↓
敌人扣除一点生命值
  ↓
Hp <= 0
  ↓
触发 EnemyDieEvent
  ↓
Level.ClearLevel()
Player.UpGrade()

五、防止重复死亡

private bool isDead;

敌人死亡后把 isDead 设置为 true:

isDead = true;

检测按键时判断敌人是否存活:

if (Input.GetKeyDown(KeyCode.J) && !isDead)

这样可以防止生命值归零后重复触发死亡事件。

六、移除事件监听

监听者销毁时,需要移除自己注册的方法:

private void OnDestroy()
{
    EventMgr.Instance.RemoveEventListener(
        EventMgr.EnemyDieEvent,
        ClearLevel
    );
}
Awake     → 添加监听
OnDestroy → 移除监听

如果一个事件已经没有任何监听者,就从字典中删除该事件记录。

七、完整代码

1. EventMgr.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class EventMgr : Singleton2<EventMgr>
{
    // Key:事件名称
    // Value:事件触发时需要执行的所有方法
    private readonly Dictionary<string, UnityAction> eventDic = new();

    // 敌人死亡事件的唯一标识
    public const string EnemyDieEvent = "EnemyDieEvent";

    private EventMgr()
    {
    }

    /// <summary>
    /// 触发事件。
    /// </summary>
    /// <param name="eventName">需要触发的事件名称。</param>
    public void EventTrigger(string eventName)
    {
        if (eventDic.TryGetValue(eventName, out UnityAction unityAction))
        {
            unityAction?.Invoke();
        }
    }

    /// <summary>
    /// 添加事件监听。
    /// </summary>
    /// <param name="eventName">需要监听的事件名称。</param>
    /// <param name="unityAction">事件触发时执行的方法。</param>
    public void AddEventListener(
        string eventName,
        UnityAction unityAction)
    {
        if (string.IsNullOrEmpty(eventName) || unityAction == null)
        {
            Debug.LogError("输入的事件名称或者函数不合法");
            return;
        }

        if (eventDic.ContainsKey(eventName))
        {
            eventDic[eventName] += unityAction;
        }
        else
        {
            eventDic.Add(eventName, unityAction);
        }
    }

    /// <summary>
    /// 移除指定的事件监听。
    /// </summary>
    /// <param name="eventName">事件名称。</param>
    /// <param name="unityAction">需要移除的方法。</param>
    public void RemoveEventListener(
        string eventName,
        UnityAction unityAction)
    {
        if (string.IsNullOrEmpty(eventName) || unityAction == null)
        {
            Debug.LogError("输入的事件名称或者函数不合法");
            return;
        }

        if (!eventDic.ContainsKey(eventName))
            return;

        eventDic[eventName] -= unityAction;

        // 没有监听者后删除该事件
        if (eventDic[eventName] == null)
        {
            eventDic.Remove(eventName);
        }
    }

    /// <summary>
    /// 清空所有事件监听。
    /// </summary>
    public void Clear()
    {
        eventDic.Clear();
    }

    /// <summary>
    /// 清空指定事件的所有监听。
    /// </summary>
    public void Clear(string eventName)
    {
        if (eventDic.ContainsKey(eventName))
        {
            eventDic.Remove(eventName);
        }
    }
}

2. Enemy.cs

using UnityEngine;

public class Enemy : MonoBehaviour
{
    public int Hp = 5;

    // 记录敌人是否已经死亡
    private bool isDead;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.J) && !isDead)
        {
            Hp--;
            Debug.Log($"敌人扣血,剩余生命值:{Hp}");

            if (Hp <= 0)
            {
                Die();
            }
        }
    }

    private void Die()
    {
        isDead = true;
        Debug.Log("怪兽死亡");

        EventMgr.Instance.EventTrigger(
            EventMgr.EnemyDieEvent
        );
    }
}

3. Level.cs

using UnityEngine;

public class Level : MonoBehaviour
{
    private void Awake()
    {
        EventMgr.Instance.AddEventListener(
            EventMgr.EnemyDieEvent,
            ClearLevel
        );
    }

    private void ClearLevel()
    {
        Debug.Log("游戏成功通关");
    }

    private void OnDestroy()
    {
        EventMgr.Instance.RemoveEventListener(
            EventMgr.EnemyDieEvent,
            ClearLevel
        );
    }
}

4. Player.cs

using UnityEngine;

public class Player : MonoBehaviour
{
    private void Awake()
    {
        EventMgr.Instance.AddEventListener(
            EventMgr.EnemyDieEvent,
            UpGrade
        );
    }

    private void UpGrade()
    {
        Debug.Log("人物升级");
    }

    private void OnDestroy()
    {
        EventMgr.Instance.RemoveEventListener(
            EventMgr.EnemyDieEvent,
            UpGrade
        );
    }
}

运行游戏后连续按下 J:

敌人扣血,剩余生命值:4
敌人扣血,剩余生命值:3
敌人扣血,剩余生命值:2
敌人扣血,剩余生命值:1
敌人扣血,剩余生命值:0
怪兽死亡
游戏成功通关
人物升级
CapNet:无线网络实现数据中心功耗封顶 本文提出CapNet,一种基于低功耗无线传感器网络(IEEE 802.15.4)的数据中心管理架构,用于实现高效的功率封顶控制。通过实证评估机架内无线链路质量,设计事件驱动的实时协议,减少轮询开销,并在真实部署中验证其满足功率封顶的时延要求,兼具高可靠性与低成本优势。 阅读详情

相关推荐

利用运放设计简单有源滤波器(低通、高通、带通)

本文旨在帮助刚接触模电的同学快速设计一个实用可靠的运放,故我将不会说一些晦涩难懂的原理,只给出仿真电路图。

WeiTong0527的博客 3万+

业务事件中心设计思想

这里看原文 本文只是提供一个简单的思考方向,实现方案只是举例说明,如果读者也需要一个类似的功能,可以根据以下思路去完善。 背景 在订单系统的业务中通常会碰到类似这样的功能 订单5分钟未支付自动取消订单 订单支付30分钟后自动接单 订单15天后自动确认收货 或者在逆交易中有类似这样的需求 优惠券相关的商品金额退款完成后退还优惠券 通常实现方案 延时消息,消息队列对于存储时间过长的数据可能无法支持像RocketMQ默认配置最大保存2天,大多不支持取消 数据库加索引扫描出合适订单,造成业务库索引过多影响

Kaifan&Blog 2951

【AI绘图进阶指南】Latent Diffusion Model核心组件解析——从理论到实践

本文深入解析Latent Diffusion Model(LDM)的核心组件,包括Autoencoder、Denoiser和Conditioning Encoder的工作原理及实践应用。通过理论结合代码示例,揭示LDM如何高效处理图像生成任务,并优化AI绘图流程,为开发者提供从理论到实践的进阶指南。

weixin_42628941的博客 384

C++每日训练 Day 15:构建线程池支持的事件中心 SignalHub

通过接入线程池和事件标识,我们实现一个真正可以落地于大型应用(如服务端、UI 框架、游戏引擎)的异步事件调度系统。篇末提供问题与答案帮助巩固理解。

Interview_TC的博客 597

告别手动标注!PDMS NakiToolkit插件安装与初体验:以Pipeline工具为例

本文详细介绍了PDMS NakiToolkit插件的安装与使用,特别是其Pipeline工具如何通过自动化标注和材料统计功能大幅提升三维工厂设计效率。从环境准备到实战演示,帮助工程师告别繁琐的手动标注工作,实现项目交付周期的大幅缩短。

weixin_30047059的博客 349

华为[ENSP]OSPF的配置实例(单区域+多区域)

华为[ENSP]OSPF的配置实例(单区域+多区域)

weixin_62594100的博客 2万+

Android自定义view实现个人中心设置界面带点击事件

前一篇博客写了《Android实现个人中心设置界面》,发现许多朋友询问怎么实现点击事件,其实实现点击事件又两种方式实现,一种是自带的setOnClickListener实现onclicklister接口就可以实现整个item的点击事件。另外一种是在自定义view中暴漏一个接口给外界调用。效果图1:原生点击事件效果图2:对外暴漏接口点击事件效果图3:代码设置每个item的左侧图标,标题文字,右侧文字...

红酒配电影 2万+

K-GAS解读(08)

大众kgas标准,大众及其供应商kgas

m0_51113317的博客 598

如何对系统日志中事件 ID 9、事件 ID 11 和事件 ID 15 错误消息进行故障排除

如何对事件 ID 9、事件 ID 11 和事件 ID 15 错误消息进行故障排除 http://support.microsoft.com/kb/154690/zh-cn 文章编号: 154690 -查看本文应用于的产品 系统提示注意:本篇文章的内容适用于其他版本的 Windows (不包括您正在使用的版本) 。本篇文章的内容可能不适用您的电脑。浏览 Windo...

weixin_34001430的博客 6396

PowerShell 升级到 v7 并设置为默认版本(详细操作指南)

本文详细介绍了如何将PowerShell升级到v7并设为默认版本。PowerShell 7基于.NET Core构建,具有跨平台支持、性能优化和新语法特性等优势。文章提供了多种安装方法(MSI安装包、包管理器)和设置默认版本的方案(修改PATH、创建符号链接、配置编辑器等),同时涵盖企业批量部署解决方案和常见问题处理。通过升级到PowerShell 7,用户可以获得更强大的命令行体验,适用于开发、运维和自动化场景。

huluang的专栏 4290

【TRAE调教指南之MCP篇】构建高效AI编程的七大MCP服务配置实战

【TRAE调教指南之MCP篇】构建高效AI编程的七大MCP服务配置实战

funfan的博客 2774

C++每日训练 Day 15:构建线程池支持的事件中心 SignalHub(易学版)

);📌 说明:这个类负责让协程挂起,并在合适的时候 resume。关键组件作用ThreadPool处理异步任务的线程池Dispatcher 接口控制协程 resume 到哪个线程协程挂起点,封装 resume 动作事件中心,支持事件挂起 + resume。

Interview_TC的博客 445

uniapp - 解决控制台提示“同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示”,uniApp安卓/苹果App真机运行调试显示同步资源失败,无任何授权提示且无法连接

uni-app,报错,安卓Android,苹果ios,安卓app端,苹果App端,uniapp苹果安卓app,提示错误解决,HbuilderX,uniapp同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示同步失败,安卓基座调试,没有反应,真机没有提示怎么办,如何解决这个问题,苹果ios手机,电脑模拟器运行,adb连接,连接失败,报错出错,uniapp真机运行的时候显示同步资源失败,未得到同步资源的授权,plugins里面没有tools,找不到tools,还是不行,重新打基座

🏆 前端领域优质创作者 1万+

盘点全球最美的15座数据中心

1Mare Nostrum位于巴塞罗那,位于一座经过改建的教堂内,是世界上最美的数据中心之一,也是离“上帝”最近的数据中心。2Salem Chapel in English Leeds不...

数据中心运维管理 1165

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

UnityVR--EventManager--事件中心1

C#中的一些概念:委托、事件、观察者模式,及它们的应用和重要性。

唐小墨同学的博客 1210

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

微信小程序 15 个人中心页

:触摸开始事件 :触摸滑动事件 :触摸结束事件手机上,其实 这三个 事件 挺重要的。本来 也没有多少事件呀。。 可以让一块区域的所有东西 在 y 轴上 移动到指定位置。 可以让一块区域的所有东西 在 y 轴上 移动到指定位置。:动画的 过渡需要时间。......

小哞^同^学的技术博客 5111

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Android 15 控制中心:快速设置面板如何切换回旧版布局?

Android15系统更新后,控制中心界面焕然一新,但部分用户可能更习惯旧版布局。本文详细介绍了如何将Android15的控制中心切换回Android14风格,包括原生安卓手机和国产手机的具体操作步骤。切换方法主要通过在设置中寻找"布局样式"选项或启用开发者模式实现,同时提供了针对老旧机型的替代方案。文章还提醒用户切换前备份当前布局,并解答了切换后可能出现的常见问题。无论是想体验新版还是保留旧版,用户都可以通过简单设置自由切换控制中心样式。

AirDroid_cn的博客 1056

深度解析tcc-g15:Dell G15开源散热控制中心实战指南

**tcc-g15**是一款专为Dell G15系列游戏本设计的开源散热控制中心,作为官方AWCC(Alienware Control Center)的轻量级替代方案,通过WMI硬件直连技术实现高效散热管理。这款Python开发的工具不仅解决了AWCC的资源占用和响应延迟问题,还为技术爱好者提供了完全可定制的散热控制方案,彻底释放硬件散热潜力。 ## 项目定位与技术背景 Dell G15游戏本

gitblog_00876的博客 416

戴尔G15散热控制中心(tcc-g15)使用教程

戴尔G15散热控制中心(tcc-g15)是一款开源的硬件监控与控制工具,专为戴尔G系列笔记本电脑设计,提供对风扇速度、温度监控等核心功能的轻量级解决方案。作为Alienware Control Center(AWCC)的替代工具,它解决了原厂软件体积庞大、功能冗余和隐私问题等痛点。 [![软件主界面](https://raw.gitcode.com/gh_mirrors/tc/tcc-g15/r...

gitblog_00892的博客 1967

去中心化聊天软件_在15分钟内建立去中心化的网络聊天

去中心化聊天软件In this 15 minute tutorial we're going to build a simple decentralized chat application which runs entirely in a web browser. 在这个15分钟的教程中,我们将构建一个简单的分散式聊天应用程序,该应用程序完全在Web浏览器中运行。 All you will ...

culuo8053的博客 1592

Android 15 单指操作:单指下滑调出控制中心后如何切换通知面板?

Android15优化单手操作体验,将控制中心与通知面板分离管理。用户可通过三种通用手势快速切换:1.单指左右滑动控制面板;2.下拉到底再上滑;3.点击顶部状态栏。不同品牌手机还提供特色功能,如华为分区域下滑、小米双指捏合等。若遇切换问题,可检查手势设置、模式选择或重启设备。这一设计使大屏手机操作更高效便捷。

AirDroid_cn的博客 385

去中心化聊天软件_在15分钟内建立去中心化网络聊天

在15分钟内建立去中心化网络聊天 在这个15分钟的教程中,我们将构建一个简单的分散式聊天应用程序,该应用程序完全在Web浏览器中运行。 您只需要一个文本编辑器 ,一个Web浏览器 ,以及有关如何保存HTML文件并在浏览器中打开它们的基本知识 。 我们将使用Bugout ,这是一个JavaScript库,用于处理对等网络和加密。 如果只需要这些文件,请在此仓库中下载index...

Web 开发&软件开发 6406

Nacos源码服务端系列第15篇事件中心之共享发布者

目录 DefaultSharePublisher uml 类图 实现方式更优的发布者(NamingEventPublisher) 总结 学习目标: 了解什么是共享发布者,跟DefaultPublisher有什么区别,它有哪些实现类。 DefaultSharePublisher 从代码中可以看出DefaultSharePublisher 的逻辑跟上一节的DefaultPublisher 的区别和联系 区别: 1、DefaultPublisher 是针对Event类型 而...

wuchsh123的专栏 438

8.15开源服务注册中心如何选型

title date comments categories tags permalink 开源服务注册中心如何选型 2020/5/20 true 微服务 微服务 8.15 当下主流的服务注册与发现的解决方案,主要有两种: 应...

libing的专栏 479

从乌克兰机场到武汉地震中心:网络攻击事件分析

近年来,网络安全领域经历了一系列重大事件,这些事件不仅暴露了现有系统的脆弱性,也推动了安全技术和策略的发展。以下是我对一些关键事件的概述,以及它们所揭示的漏洞和原理。2016年1月,乌克兰首都基辅的鲍里斯波尔国际机场遭遇了一起网络攻击,其电脑网络被确认感染了恶意软件。这一事件揭示了关键基础设施面临的网络安全风险,以及恶意软件攻击的潜在威胁。攻击分析: 攻击者利用了网络中的漏洞,通过植入恶意软件来控制机场的关键系统。虽然初步报告显示没有造成明显损害,但恶意软件的潜在能力足以对机场运营造成重大干扰。该恶意软件与

聚焦网络安全,以多元语言优势汲取知识,分享生动有趣的学习与技术心得。 1500

全球最美的15座数据中心

1Mare Nostrum位于巴塞罗那,位于一座经过改建的教堂内,是世界上最美的数据中心之一,也是离“上帝”最近的数据中心。2Salem Chapel in Englis...

数据中心运维管理 679
上一篇: 14.事件中心:主要作用和原理
下一篇: 16.事件中心优化:添加参数
Unity黑马王子
博客等级 码龄4年 1846粉丝 181原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值