Unity 从0开始编写一个技能编辑器_03_Buff系统的Handler

BuffHandler可以是用于处理角色身上buff的Mono类,任何具备跟Buff交互的角色,都要携带这个BuffHandler脚本。如果你的Buff有额外的处理机制,比如互斥Buff(如:免疫负面效果的霸体),需要在AddBuff方法中额外处理。当然 也可以不作为mono转为BaseFightObj的一个引用的实例,在BaseFightObj这一类中的生命周期进行调用

    /// <summary>/// Buff处理器的接口/// </summary>public interface BuffSystem_IBuffHandler{/// <summary>/// 添加Buff /// </summary>/// <param name="buffId">施加Buff的ID</param>/// <param name="caster">施加Buff者</param>public void AddBuff(int buffId, GameObject caster);/// <summary>/// 移除Buff/// </summary>/// <param name="buffId">要移除的Buff id</param>/// <param name="removeAll">如果对象同时存在多个同id的buff,是否将所有一并移除</param>public void RemoveBuff(int buffId, bool removeAll = true);/// <summary>/// 移除Buff(不执行OnBuffRemove)/// </summary>/// <param name="buffId">要移除的Buff id</param>/// <param name="removeAll">如果对象同时存在多个同id的buff,是否将所有一并移除</param>public void InterruptBuff(int buffId, bool interuptAll = true);/// <summary>/// 注册事件:添加Buff时/// </summary>/// <param name="act">注册的行为</param>public void RegisterOnAddBuff(Action act);/// <summary>/// 删除事件:添加Buff时/// </summary>/// <param name="act">注册的行为</param>public void RemoveOnAddBuff(Action act);/// <summary>/// 注册事件:删除Buff时/// </summary>/// <param name="act">注册的行为</param>public void RegisterOnRemoveBuff(Action act);/// <summary>/// 删除事件:删除Buff时/// </summary>/// <param name="act">注册的行为</param>public void RemoveOnRemoveBuff(Action act);}

接口实现如上所示,可以看到实现了一些 “trigger” 可以在特定需求下减轻一些主线程的压力。
依照接口,我们可以实现具体的BuffHandler类
1.AddBuff 方法如下 可以看到 对上文的 重复添加同一种Buff时的行为 做了处理。这是按照策划的需求给出的,不必要求在初次编写时考虑所有情况 便于扩展即可

AddBuff的多种情况
public enum BuffMutilAddType
{resetTime,                     //重置Buff时间multipleLayer,                 //增加Buff层数multipleLayerAndResetTime,     //增加Buff层数且重置Buff时间multipleCount                  //同种Buff同时存在多个,互不影响
}
AddBuff方法的具体实现
private void AddBuff(IBuff buff, GameObject caster){if (!updated) Update();Buff bf = (Buff)buff;if (bf.IsEmpty()){Debug.LogError("尝试加入空Buff");return;}//无论是否可以添加都执行初始化和BuffAwakebf.Initialize(this, caster);bf.OnBuffAwake();//确定能添加Buff时onAddBuff?.Invoke();//检查是否已有同样的BuffBuff previous = buffs.Find(p => p.Equals(bf));//没有则直接添加if (previous == null){//结算Tag效果if (bf.BuffTag != BuffTag.none){//首先:如果有已有buff能抵消新buff,则直接抵消if (buffs.Any(b => BuffManager.GetInstance().TagManager.IsTagCanAddWhenHaveOther(bf.BuffTag, b.BuffTag))){bf.SetEffective(false);bf.OnBuffDestroy();return;}for (int i = buffs.Count - 1; i >= 0; i--){//之后:如果新buff没有被抵消,则新buff抵消已有的buff//Debug.Log("Running:" + bf.BuffTag + ":" + buffs[i].BuffTag);if (BuffManager.GetInstance().TagManager.IsTagRemoveOther(bf.BuffTag, buffs[i].BuffTag)){RemoveBuff(buffs[i]);}}}buffs.Add(bf);forOnBuffStart += bf.OnBuffStart;return;}//有则根据重复添加的类型处理。//一个Buff对象的Start不会重复执行//只有mutilCount类型会同时存在多个同id Buffswitch (previous.MutilAddType){case BuffMutilAddType.resetTime:previous.ResetTimer();//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleLayer:previous.ModifyLayer(1);//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleLayerAndResetTime:previous.ResetTimer();previous.ModifyLayer(1);//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleCount:buffs.Add(bf);forOnBuffStart += bf.OnBuffStart;break;default:break;}}

然后是RemoveBuff的两种情况

 /// <summary>/// 移除一个Buff,移除后执行OnBuffRemove/// </summary>/// <param name="buff">要移除的Buff</param>private void RemoveBuff(IBuff buff){Buff bf = (Buff)buff;bf.SetEffective(false);}/// <summary>/// 移除一个Buff,移除后不执行OnBuffRemove/// </summary>/// <param name="buff">要移除的Buff</param>private void InteruptBuff(IBuff buff){Buff bf = (Buff)buff;bf.SetEffective(false);buffs.Remove(bf);forOnBuffDestroy += ((Buff)buff).OnBuffDestroy;}

之所以这么设计是因为 有些负面Buff效果在onRemoveBuff执行 然而 互斥buff或者说实际的净化buff 不希望onRemoveBuff执行,这会导致一些预期之外的后果 可能不便于实现一些需求,所以编写这两种本质上均为RemoveBuff的方法,为了方便理解 命名为InteruptBuff 打断buff

上述的私有方法AddBuff(IBuff buff, GameObject caster),RemoveBuff(IBuff buff),和InteruptBuff(IBuff buff)封装了实际的Buff处理逻辑。这些方法实现了添加、移除和打断Buff的具体细节。
将复杂的逻辑封装在私有方法中,可以更容易地进行维护和修改。任何更改都只需要在私有方法内部进行,而不影响公有接口

  public void AddBuff(int buffId, GameObject caster){var b = BuffManager.GetInstance().GetBuff(buffId);AddBuff(b, caster);}public void RemoveBuff(int buffId, bool removeAll = true){var b = buffs.FirstOrDefault(b => b.ID == buffId);if (b == null){Debug.Log("尝试从" + this.name + "移除没有添加的Buff。 id:" + buffId);return;}else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll){var bs = buffs.Where(b => b.ID == buffId);foreach (var bf in bs){RemoveBuff(bf);}}else RemoveBuff(b);}public void InterruptBuff(int buffId, bool removeAll = true){var b = buffs.FirstOrDefault(b => b.ID == buffId);if (b == null){Debug.Log("尝试从" + this.name + "打断没有添加的Buff。 id:" + buffId);return;}else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll){var bs = buffs.Where(b => b.ID == buffId);foreach (var bf in bs){InteruptBuff(bf);}}else InteruptBuff(b);}

然后我们用公有方法将内部复杂的逻辑封装起来,外部只需简单调用。例如,外部调用者只需提供Buff ID和施法者(caster),而不需要关心具体的Buff对象和其处理细节。
完整代码如下

public class BuffHandler : MonoBehaviour, BuffSystem_IBuffHandler{private List<Buff> buffs = new List<Buff>();private Action onAddBuff;private Action onRemoveBuff;public List<Buff> GetBuffs => new List<Buff>(buffs);public void RegisterOnAddBuff(Action act) { onAddBuff += act; }public void RemoveOnAddBuff(Action act) { onRemoveBuff -= act; }public void RegisterOnRemoveBuff(Action act) { onRemoveBuff += act; }public void RemoveOnRemoveBuff(Action act) { onRemoveBuff -= act; }#region 私有方法private void AddBuff(IBuff buff, GameObject caster){if (!updated) Update();Buff bf = (Buff)buff;if (bf.IsEmpty()){Debug.LogError("尝试加入空Buff");return;}//无论是否可以添加都执行初始化和BuffAwakebf.Initialize(this, caster);bf.OnBuffAwake();//确定能添加Buff时onAddBuff?.Invoke();//检查是否已有同样的BuffBuff previous = buffs.Find(p => p.Equals(bf));//没有则直接添加if (previous == null){//结算Tag效果if (bf.BuffTag != BuffTag.none){//首先:如果有已有buff能抵消新buff,则直接抵消if (buffs.Any(b => BuffManager.GetInstance().TagManager.IsTagCanAddWhenHaveOther(bf.BuffTag, b.BuffTag))){bf.SetEffective(false);bf.OnBuffDestroy();return;}for (int i = buffs.Count - 1; i >= 0; i--){//之后:如果新buff没有被抵消,则新buff抵消已有的buff//Debug.Log("Running:" + bf.BuffTag + ":" + buffs[i].BuffTag);if (BuffManager.GetInstance().TagManager.IsTagRemoveOther(bf.BuffTag, buffs[i].BuffTag)){RemoveBuff(buffs[i]);}}}buffs.Add(bf);forOnBuffStart += bf.OnBuffStart;return;}//有则根据重复添加的类型处理。//一个Buff对象的Start不会重复执行//只有mutilCount类型会同时存在多个同id Buffswitch (previous.MutilAddType){case BuffMutilAddType.resetTime:previous.ResetTimer();//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleLayer:previous.ModifyLayer(1);//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleLayerAndResetTime:previous.ResetTimer();previous.ModifyLayer(1);//forOnBuffStart += previous.OnBuffStart;break;case BuffMutilAddType.multipleCount:buffs.Add(bf);forOnBuffStart += bf.OnBuffStart;break;default:break;}}/// <summary>/// 移除一个Buff,移除后执行OnBuffRemove/// </summary>/// <param name="buff">要移除的Buff</param>private void RemoveBuff(IBuff buff){Buff bf = (Buff)buff;bf.SetEffective(false);}/// <summary>/// 移除一个Buff,移除后不执行OnBuffRemove/// </summary>/// <param name="buff">要移除的Buff</param>private void InteruptBuff(IBuff buff){Buff bf = (Buff)buff;bf.SetEffective(false);buffs.Remove(bf);forOnBuffDestroy += ((Buff)buff).OnBuffDestroy;}#endregionpublic void AddBuff(int buffId, GameObject caster){var b = BuffManager.GetInstance().GetBuff(buffId);AddBuff(b, caster);}public void RemoveBuff(int buffId, bool removeAll = true){var b = buffs.FirstOrDefault(b => b.ID == buffId);if (b == null){Debug.Log("尝试从" + this.name + "移除没有添加的Buff。 id:" + buffId);return;}else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll){var bs = buffs.Where(b => b.ID == buffId);foreach (var bf in bs){RemoveBuff(bf);}}else RemoveBuff(b);}public void InterruptBuff(int buffId, bool removeAll = true){var b = buffs.FirstOrDefault(b => b.ID == buffId);if (b == null){Debug.Log("尝试从" + this.name + "打断没有添加的Buff。 id:" + buffId);return;}else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll){var bs = buffs.Where(b => b.ID == buffId);foreach (var bf in bs){InteruptBuff(bf);}}else InteruptBuff(b);}private bool updated = false;private Action forOnBuffDestroy;    //用于在下一帧执行onBuffDestoryprivate Action forOnBuffStart;private void Update(){if (updated) return;updated = true;forOnBuffDestroy?.Invoke();forOnBuffStart?.Invoke();forOnBuffDestroy = null;forOnBuffStart = null;}private void LateUpdate(){updated = false;Buff bf;bool buffRemoved = false;for (int i = buffs.Count - 1; i >= 0; i--){bf = buffs[i];//Debug.Log(bf);bf.OnBuffUpdate();if (!bf.IsEffective){bf.OnBuffRemove();buffRemoved = true;buffs.Remove(bf);forOnBuffDestroy += bf.OnBuffDestroy;}}if (buffRemoved) onRemoveBuff?.Invoke();}}
}

Update 每帧更新Buff状态,执行所有记录的销毁和开始方法。
LateUpdate检查并更新每个Buff的状态,如果Buff无效,则移除并记录其销毁方法。
BuffHandler类通过管理游戏对象上的所有Buff,实现了Buff的添加、移除、打断和更新等功能。其核心逻辑包括Buff的初始化、处理相同Buff的多种添加类型、管理Buff的生命周期以及调用相关回调方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/36998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新AIGC系统源码-ChatGPT商业版系统源码,自定义ChatGPT指令Promp提示词,AI绘画系统,AI换脸、多模态识图理解文档分析

目录 一、前言 系统文档 二、系统演示 核心AI能力 系统快速体验 三、系统功能模块 3.1 AI全模型支持/插件系统 AI模型提问 文档分析 ​识图理解能力 3.2 GPts应用 3.2.1 GPTs应用 3.2.2 GPTs工作台 3.2.3 自定义创建Promp指令预设应用 3.3 AI专业绘画 3.3.1 文…

【51单片机入门】数码管原理

文章目录 前言共阴极与共阳极数码管多个数码管显示原理 总结 前言 在我们的日常生活中&#xff0c;数码管被广泛应用于各种电子设备中&#xff0c;如电子表、计时器、电子钟等。数码管的主要功能是显示数字和一些特殊字符。在这篇文章中&#xff0c;我们将探讨数码管的工作原理…

SpringMVC启动流程

文章目录 引文HandlerHandlerMapperHandlerAdapterRequestMapping方法参数解析RequestMapping方法返回值解析文件上传流程拦截器解析 SpringMVC启动流程如下 引文 我们在使用SpringMVC时&#xff0c;传统的方式是在webapp目录下定义一个web.xml文件&#xff0c;比如&#xff1a…

PerplexityAI与《连线》杂志纠纷事件深度分析

引言 最近&#xff0c;PerplexityAI&#xff0c;这家人工智能搜索领域的新秀公司&#xff0c;因被《连线》杂志指控剽窃内容和捏造事实而陷入困境。这起事件引发了广泛关注&#xff0c;也揭示了AI技术在信息检索和内容生成领域面临的一系列挑战。本文将对该事件进行详细分析&a…

Android Lint

文章目录 Android Lint概述工作流程Lint 问题问题种类警告严重性检查规则 用命令运行 LintAndroidStudio 使用 Lint忽略 Lint 警告gradle 配置 Lint查找无用资源文件 Android Lint 概述 Lint 是 Android 提供的 代码扫描分析工具&#xff0c;它可以帮助我们发现代码结构/质量…

CONSTRAINT关键字

CREATE TABLE accounts(acctNo CHAR(20) PRIMARY KEY,balance FLOAT,CONSTRAINT c1 CHECK(balance > 0) ); 1、CONSTRAINT C1部分定义了一个新的约束&#xff0c;这里命名为C1 2、CHECK(BALANCE>0)是约束的具体内容&#xff0c;它规定了balance列的值必须大于等于0。这…

最小生成树拓展应用

文章目录 最小生成树拓展应用理论基础 题单1. [新的开始](https://www.acwing.com/problem/content/1148/)2. [北极通讯网络](https://www.acwing.com/problem/content/1147/)3. [走廊泼水节](https://www.acwing.com/problem/content/348/)4. [秘密的牛奶运输](https://www.ac…

用英文介绍芝加哥(1):Making Modern Chicago Part 1 Building a Boomtown

Making Modern Chicago | Part 1: Building a Boomtown Link: https://www.youtube.com/watch?vpNdX0Dm-J8Y&listPLmSQiOQJmbZ7TU39cyx7gizM9i8nOuZXy&index4 Summary Summary of Chicago’s History and Development Urban Planning and Growth Chicago, often r…

揭开油烟净化器行业的黑幕:材料以次充好,消费者权益何在?

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 油烟净化器&#xff0c;作为现代厨房环保的必需品&#xff0c;原本应是保护家庭和环境的利器。然而&#xff0c;近年来市场上…

无需向量量化的自回归图像生成

摘要 https://arxiv.org/pdf/2406.11838 传统观点认为&#xff0c;用于图像生成的自回归模型通常伴随着向量量化的标记。我们观察到&#xff0c;尽管离散值空间可以方便地表示分类分布&#xff0c;但它对于自回归建模来说并不是必需的。在这项工作中&#xff0c;我们提出使用扩…

战地战地风云最强的免费加速器 2024低延迟不卡顿加速器推荐

来喽来喽&#xff0c;steam夏季促销它又来喽&#xff0c;战地风云&#xff0c;第一人称射击游戏&#xff0c;而且这次迎来了史低&#xff0c;游戏背景设定为近未来&#xff08;公元2042年&#xff09;&#xff0c;会有动态的天气系统&#xff0c;以及改善后的破坏系统。该作为《…

c++字典

在C中&#xff0c;“字典”通常指的是std::map或std::unordered_map&#xff0c;它们是标准库中提供的关联容器&#xff0c;用于存储键值对。以下是一些常见的操作示例&#xff0c;包括插入、访问、删除和遍历元素。 使用 std::map std::map 是一种有序的关联容器&#xff0c;键…

开源模型应用落地-FastAPI-助力模型交互-WebSocket篇(三)

一、前言 使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。 FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,F…

【基础篇】第1章 Elasticsearch 引言

1.1 Elasticsearch简介 1.1.1 基本概念 Elasticsearch&#xff0c;一个开源的分布式搜索引擎&#xff0c;以其强大的搜索能力和实时数据分析能力&#xff0c;在大数据时代脱颖而出。它基于Apache Lucene库构建&#xff0c;旨在提供高效、可扩展且易于使用的全文检索解决方案。…

关于Mac mini 10G网口的问题

问题: 购入一个10G网口的Mac mini M2&#xff0c;将其和自己的2.5G交换机连接&#xff0c;使用共享屏幕进行远程操作的过程中出现了频率极高的卡顿&#xff0c;几乎是几秒钟卡一下&#xff0c;使用ping进行测试发现卡的时候就ping不通了。测试使用Mac mini的无线网和雷电转2.5G…

React Native 开发常见问题及注意事项

本文只是使用时积累的一些经验 开发环境 1、Android Studio 依赖项下载慢 如果发现依赖下载非常慢&#xff0c;动不动十几KB的 参考&#xff1a;加速 Android Studio 依赖项下载 也可以切换数据源 修改 android/build.gradle中的jcenter()和google() repositories {// goo…

人脑计算机技术与Neuroplatform:未来计算的革命性进展

引言 想象一下&#xff0c;你在某个清晨醒来&#xff0c;准备开始一天的工作&#xff0c;而实际上你的大脑正作为一台生物计算机的核心&#xff0c;处理着大量复杂的信息。这并非科幻电影的情节&#xff0c;而是人脑计算机技术即将带来的现实。本文将深入探讨FinalSpark公司的…

【BFS】【并查集】个人练习-Leetcode-815. Bus Routes

题目链接&#xff1a;https://leetcode.cn/problems/bus-routes/description/ 题目大意&#xff1a;给出一系列公交车路线routes[][]&#xff0c;每条路线上有一系列车站&#xff0c;可以搭乘同一班公交车经过这些车站。给出起点车站和终点车站&#xff0c;求最小的需要搭乘的…

选择适合你的8款原型设计工具

随着互联网的飞速发展&#xff0c;设计行业逐渐成为近年来的热门职业。设计师们需要的掌握的技能也越来越多&#xff0c;例如海报设计、名片设计、产品设计、网页设计等。产品原型设计就是产品设计中非常重要的一个阶段&#xff0c;主要目的是帮助用户更容易了解产品设计的思路…

深度学习 —— 1.单一神经元

深度学习初级课程 1.单一神经元2.深度神经网络3.随机梯度下降法4.过拟合和欠拟合5.剪枝、批量标准化6.二分类 前言 本套课程仍为 kaggle 课程《Intro to Deep Learning》&#xff0c;仍按之前《机器学习》系列课程模式进行。前一系列《Keras入门教程》内容&#xff0c;与本系列…