【unity实战】如何更加规范的创建各种Rogue-Lite(肉鸽)风格的物品和BUFF效果(附项目源码)

news2024/11/15 11:25:32

文章目录

  • 前言
  • 定义基类
  • 实现不同的BUFF效果
    • 一、回血BUFF
      • 1. 简单的回血效果实现
      • 2. BUFF层数控制回血量
    • 二、攻击附带火焰伤害
    • 三、治疗领域
      • 1. 简单的治疗领域实现
      • 2. 添加技能冷却时间
  • 通过拾取物品获取对应的BUFF
  • 参考
  • 源码
  • 完结

前言

当创建各种Rogue-Lite(肉鸽)风格的游戏时,物品和BUFF效果是非常重要的元素之一。为了更加规范地创建这些物品和BUFF效果,可以使用抽象类来定义不同的BUFF。

那么什么是抽象类呢?他的用法?为什么用它?好处是什么呢?

在Unity中,抽象类是一种特殊的类,它不能被实例化,只能被用作其他类的基类。抽象类通常用于定义一些通用的行为和属性,但并不提供具体的实现细节。其目的是让子类来实现这些抽象方法和属性,以便根据具体的需求进行定制化。

使用抽象类的主要原因是为了实现代码的重用和统一性。抽象类可以定义一些通用的方法和属性,从而避免在多个类中重复编写相似的代码。同时,它也可以作为约定,强制子类实现特定的方法和属性,确保了程序的一致性和可扩展性。

抽象类的主要好处包括:

  1. 提供了一种模板化的设计方式,使得代码更易维护和扩展。
  2. 强制了子类必须实现抽象方法和属性,从而减少了程序出错的可能性。
  3. 通过抽象类可以实现多态性,使得代码更加灵活和可复用。

在Unity中,经常会用到抽象类来定义一些通用的行为或者规范,例如定义一个抽象的游戏角色类,其中定义了移动、攻击等方法,然后具体的角色类(如玩家角色、敌对角色等)继承并实现这些方法。这样可以保持代码的一致性和可维护性。

总之,抽象类在Unity中的使用可以帮助我们更好地组织和管理代码,提高代码的复用性和可维护性。

定义基类

物品就是物品BUFF,下面我都会用物品作为注释

新增Item,定义一个名为 Item 的物品BUFF抽象类

[System.Serializable]

public abstract class Item
{
    // 定义BUFF名称
    public abstract string GiveName();

    // 定义一个虚方法 Update,其中 player 表示玩家对象,stacks 表示物品的叠加数量(及BUFF层数)
    public virtual void Update(Player player, int stacks){ }
}

新增ItemList,定义物品BUFF列表参数

[System.Serializable]
public class ItemList
{
    // 表示物品
    public Item item;

    // 表示名称
    public string name;

    // 表示叠加数量(及BUFF层数)
    public int stacks;

    // 构造函数,用于初始化 ItemList 对象
    public ItemList(Item newItem, string newName, int newStacks)
    {
        item = newItem;
        name = newName;
        stacks = newStacks;
    }
}

实现不同的BUFF效果

一、回血BUFF

1. 简单的回血效果实现

定义一个名为 HealingItem 的类,继承自 Item,定义回血BUFF

public class HealingItem : Item
{
    public override string GiveName()
    {
        return "回血BUFF";
    }

    public override void Update(Player player, int stacks)
    {
        // 将玩家的生命值增加 5
        player.health += 5;
    }
}

新增玩家脚本,调用BUFF

public class Player : MonoBehaviour
{
    // 表示玩家的生命值
    public int health;

    // 表示玩家的物品BUFF列表
    public List<ItemList> items = new List<ItemList>();

    void Start()
    {
        HealingItem item = new HealingItem();
        // 将回血BUFF对象添加到物品列表中
        items.Add(new ItemList(item, item.GiveName(), 1));

        StartCoroutine(CallItemUpdate());
    }

    IEnumerator CallItemUpdate()
    {
        // 遍历物品列表中的每个物品
        foreach (ItemList i in items)
        {
            // 调用物品的 Update 方法
            i.item.Update(this, i.stacks);
        }
        
        //暂停1秒继续执行
        yield return new WaitForSeconds(1);
        
        // 重新启动协程 CallItemUpdate
        StartCoroutine(CallItemUpdate());
    }
}

运行效果,角色每秒回5点血
在这里插入图片描述

2. BUFF层数控制回血量

修改HealingItem

public override void Update(Player player, int stacks)
{
    // 将玩家的生命值增加
    player.health += 3 + (2 * stacks);
}

效果,两层每秒加7血
在这里插入图片描述
在这里插入图片描述

二、攻击附带火焰伤害

新增敌人脚本,定义敌人生命值

public class Enemy : MonoBehaviour {
    public int health;
}

修改Item,定义攻击事件

public virtual void OnHit(Player player, Enemy enemy, int stacks){ }

新增FireDamageItem,实现火焰攻击效果

public class FireDamageItem : Item
{
    public override string GiveName()
    {
        return "火焰攻击";
    }

    public override void OnHit(Player player, Enemy enemy, int stacks)
    {
        enemy.health -= 10 * stacks;
    }    
}

修改Player,默认加2层火焰攻击效果

// 表示玩家的攻击力 
public int attackDamage;

void Start()
{
    FireDamageItem item = new FireDamageItem();
    items.Add(new ItemList(item, item.GiveName(), 2));
}

public void CallItemOnHit(Enemy enemy)
{
    foreach (ItemList i in items)
    {
        i.item.OnHit(this, enemy, i.stacks);
    }
}

新增PlayerHitbox,定义攻击判定,攻击附加额外火焰攻击BUFF伤害

public class PlayerHitbox : MonoBehaviour
{
    public Player player;

    //触发器检测
    private void OnTriggerEnter(Collider other)
    {
        // 判断进入碰撞体的对象是否为敌人
        if (other.tag == "Enemy")
        {
            Enemy enemy = other.GetComponent<Enemy>();

            // 减少敌人的生命值,减少的值为玩家的攻击力
            enemy.health -= player.attackDamage;

            // 调用玩家的 CallItemOnHit 方法,附加额外伤害
            player.CallItemOnHit(enemy);
        }
    }
}

效果,攻击附带额外伤害
在这里插入图片描述

三、治疗领域

实现治疗领域效果一般需要加载一些特性,而我们定义的BUFF是没办法挂载特效物品的,这时候就需要使用Resources加载指定的特效了

在这里插入图片描述

1. 简单的治疗领域实现

绘制预制体
在这里插入图片描述

修改Item,定义跳跃方法

public virtual void OnJump(Player player, int stacks) { }

新增HealingArea,实现跳跃方法生成治疗领域

public class HealingArea : Item
{
	//特效
    GameObject effect;
    
    public override string GiveName()
    {
        return "治疗领域";
    }
    
    public override void OnJump(Player player, int stacks)
    {
        if (effect == null) effect= (GameObject)Resources.Load("Item Effects/Healing Area", typeof(GameObject));
        GameObject healingArea = GameObject.Instantiate(effect, player.transform.position, Quaternion.Euler(Vector3.zero));
    }
}

修改Player,实现每次按Space,执行治疗领域OnJump方法

private void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        CallItemOnJump();
    }
}
    
public void CallItemOnJump()
{
    foreach (ItemList i in items)
    {
        i.item.OnJump(this, i.stacks);
    }
}

效果,每次跳跃生成一个治疗光环
在这里插入图片描述

2. 添加技能冷却时间

修改HealingArea

public class HealingArea : Item
{
    GameObject effect;
    float internalCoolDown;//技能冷却时间
    
    public override string GiveName()
    {
        return "Healing Area";
    }

    public override void Update(Player player, int stacks)
    {
        internalCoolDown -= 1;
    }

    public override void OnJump(Player player, int stacks)
    {
        if (internalCoolDown <= 0)
        {
            if (effect == null) effect = (GameObject)Resources.Load("Item Effects/Healing Area", typeof(GameObject));
            GameObject healingArea = GameObject.Instantiate(effect, player.transform.position, Quaternion.Euler(Vector3.zero));
            internalCoolDown = 10;//技能冷却时间默认定义10秒
        }
    }
}

效果,每10秒才能释放一次治疗光环
在这里插入图片描述

通过拾取物品获取对应的BUFF

新增ItemPickup ,物品拾取类

public class ItemPickup : MonoBehaviour
{
    // 掉落的物品对象
    public Item item;
    // 物品类型
    public Items itemDrop;

    void Start()
    {
        // 调用 AssignItem 方法,传入掉落的物品类型,并将返回值赋值给 item
        item = AssignItem(itemDrop);
    }

    // 触发器检测
    private void OnTriggerEnter(Collider other)
    {
        // 判断进入碰撞体的对象是否为玩家
        if (other.tag == "Player")
        {
            // 获取玩家对象
            Player player = other.GetComponent<Player>();

            // 调用 AddItem 方法,传入玩家对象
            AddItem(player);

            // 销毁 Pickup 对象
            Destroy(this.gameObject);
        }
    }
    
    public Item AssignItem(Items itemToAssign)
    {
        // 根据不同的物品类型返回不同的物品对象
        switch (itemToAssign)
        {
            case Items.HealingItem:
                return new HealingItem();
            case Items.FireDamageItem:
                return new FireDamageItem();
            case Items.HealingAreaItem:
                return new HealingArea();
            default:
                return new HealingItem();
        }
    }

    public void AddItem(Player player)
    {
        // 遍历玩家物品列表中的每个物品
        foreach (ItemList i in player.items)
        {
            // 如果该物品已经存在于列表中,则将该物品的叠加数量加 1,并直接返回
            if (i.name == item.GiveName())
            {
                i.stacks += 1;
                return;
            }
        }

        // 将新的物品添加到玩家物品列表中
        player.items.Add(new ItemList(item, item.GiveName(), 1));
    }
}

// 定义一个公共枚举类型 Items,表示所有可用的物品类型
public enum Items
{
    HealingItem,
    FireDamageItem,
    HealingAreaItem
}

修改Player,删除前面旧的BUFF添加

// HealingItem item = new HealingItem();
// items.Add(new ItemList(item, item.GiveName(), 1));

// FireDamageItem item = new FireDamageItem();
// items.Add(new ItemList(item, item.GiveName(), 2));

新增各种BUFF物品,配置预制体
在这里插入图片描述效果,拾取物品即可获取对应的BUFF效果
在这里插入图片描述
ps:后续要加入其他BUFF,直接就可以修改ItemPickup很方便的进行添加定义即可

参考

【视频】https://www.youtube.com/watch?v=iU6mKyQjOYI

源码

https://gitcode.net/unity1/unity-roguelitebuff
在这里插入图片描述

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

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

相关文章

VS2022使用Vim按键

VS2022使用Vim按键 在插件管理里面搜索VsVim 点击安装&#xff0c;重启VS 工具->选项->VsVim 配置按键由谁处理&#xff0c;建议Ctrl C之类常用的使用VS处理&#xff0c;其它使用Vim处理

shell编程系列(7)-使用wc进行文本统计

文章目录 前言wc命令的使用wc命令的参数说明&#xff1a;统计字数统计行数打印文本行号 结语 前言 统计功能也是我们在shell编程中经常碰到的一个需求&#xff0c;wc命令可以适用于任何需要统计的数据&#xff0c;不只是统计文本&#xff0c;配合ls命令我们可以统计文件的个数…

electron调用dll问题总汇

通过一天的调试安装&#xff0c;electron调用dll成功&#xff0c;先列出当前的环境&#xff1a;node版本: 18.12.0&#xff0c;32位的&#xff08;因为dll为32位的&#xff09; VS2019 python node-gyp 1、首先要查看报错原因&#xff0c;通常在某一行会有提示&#xff0c;常…

在Linux上安装KVM虚拟机

一、搭建KVM环境 KVM&#xff08;Kernel-based Virtual Machine&#xff09;是一个基于内核的系统虚拟化模块&#xff0c;从Linux内核版本2.6.20开始&#xff0c;各大Linux发行版就已经将其集成于发行版中。KVM与Xen等虚拟化相比&#xff0c;需要硬件支持的完全虚拟化。KVM由内…

vue3 router-view 使用keep-alive报错parentcomponent.ctx.deactivate is not a function

问题 如下图&#xff0c;在component组件上添加v-if判断&#xff0c;会报错: parentcomponent.ctx.deactivate is not a function 解决方法 去除v-if&#xff0c;将key直接添加上。由于有的公用页面&#xff0c;需要刷新&#xff0c;不希望缓存&#xff0c;所以需要添加key…

2023/11/30JAVAweb学习

数组json形式 想切换实现类,只需要只在你需要的类上添加 Component 如果在同一层,可以更改扫描范围,但是不推荐这种方法 注入时存在多个同类型bean解决方式

C 中的结构 - 存储、指针、函数和自引用结构

0. 结构体的内存分配 当声明某种类型的结构变量时&#xff0c;结构成员被分配连续&#xff08;相邻&#xff09;的内存位置。 struct student{char name[20];int roll;char gender;int marks[5];} stu1; 此处&#xff0c;内存将分配给name[20]、roll、gender和marks[5]。st1这…

Redis学习文档

目录 一、概念1、特征2、关系型数据库和非关系型数据库的区别3、键的结构4、Redis的Java客户端5、缓存更新策略5.1、概念5.2、代码 6、缓存穿透6.1、含义6.2、解决办法6.3、缓存空值代码举例6.4、布隆过滤器代码举例 7、缓存击穿7.1、概念7.2、解决办法7.3、互斥锁代码举例7.4、…

卡码网语言基础课 | 17. 判断集合成员

目录 一、 set 集合 二、 创建集合 2.1 引入头文件 2.2 创建 2.3 插入元素 2.4 删除元素 三、 find的用法 四、 实现基本解题 五、 延伸拓展 题目&#xff1a;编写一个程序&#xff0c;判断给定的整数 n 是否存在于给定的集合中。 输入描述&#xff1a; 有多组测试…

Pycharm中使用matplotlib绘制动态图形

Pycharm中使用matplotlib绘制动态图形 最终效果 最近用pycharm学习D2L时发现官方在jupyter notebook交互式环境中能动态绘制图形&#xff0c;但是在pycharm脚本环境中只会在最终 plt.show() 后输出一张静态图像。于是有了下面这段自己折腾了一下午的代码&#xff0c;用来在pych…

jetson nano SSH远程连接(使用MobaXterm)

文章目录 SSH远程连接1.SSH介绍2.准备工作3.连接步骤3.1 IP查询3.2 新建会话和连接 SSH远程连接 本节课的实现&#xff0c;需要将Jetson Nano和电脑保持在同一个局域网内&#xff0c;也就是连接同一个路 由器&#xff0c;通过SSH的方式来实现远程登陆。 1.SSH介绍 SSH是一种网…

一文讲透Python机器学习特征选择之互信息法

1.互信息法的基本思想 互信息&#xff08;Mutual Information&#xff0c;MI&#xff09;的基本思想是计算每个特征变量与目标变量之间的互信息统计量&#xff0c;互信息统计量衡量变量之间的依赖关系。两个随机变量之间的互信息统计量肯定是非负值&#xff0c;当且仅当两个随…

带键扫的LED专用驱动方案

一、基本概述 TM1650 是一种带键盘扫描接口的LED&#xff08;发光二极管显示器&#xff09;驱动控制专用电路。内部集成有MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强&#xff0c;可适用于24 小时长期…

【强迫症患者必备】SpringBoot项目中Mybatis使用mybatis-redis开启三级缓存必须创建redis.properties优化方案

springboot项目中mybatis使用mybatis-redis开启三级缓存需要创建redis.properties优化方案 前言下载mybatis-redis源码分析RedisCache 代码RedisConfigurationBuilder的parseConfiguration方法 优化改造1.创建JedisConfig类2.复制RedisCache代码创建自定义的MyRedisCache3.指定…

分享超实用的软文撰写步骤!建议收藏

一想到写软文就头大&#xff0c;根本不知道从哪里下手&#xff0c;这是很多写手在创作过程中会遇到的问题。 一篇软文写得好不好&#xff0c;关键就要看你的创作步骤到不到位&#xff0c;软文创作是有一套可执行的具体方式的&#xff0c;跟着步骤来&#xff0c;你也能轻轻松松…

【java扫盲贴】final修饰变量

引用类型&#xff1a;地址不可变 //Java中的引用类型分为类&#xff08;class&#xff09;、接口&#xff08;interface&#xff09;、数组&#xff08;array&#xff09;和枚举&#xff08;enum&#xff09;。//string是特殊的引用类型&#xff0c;他的底层是被final修饰的字…

麒麟操作系统网桥配置

网桥概念&#xff1a; Bridge 是 Linux 上用来做 TCP/IP 二层协议交换的设备&#xff0c;其功能可 以简单的理解为是一个二层交换机或者 Hub&#xff1b;多个网络设备可以连接 到同一个 Bridge&#xff0c;当某个设备收到数据包时&#xff0c;Bridge 会将数据转发 给其他设备。…

osgFX扩展库-刻线特效、立方图镜面高光特效(2)

刻线特效 刻线特效(osgFX::Scribe)是一个双通道的特效&#xff0c;第一个通道以通常的方式渲染图形&#xff0c;第二个通道使用线框模式。用户设置好光照和材质之后&#xff0c;即可使用指定的颜色进行渲染。这个特效使用了PolygonOffset渲染属性类来避免多边形斑驳(Z-fighting…

【C++ Primer Plus学习记录】嵌套循环和二维数组

for循环是一种处理数组的工具。下面进一步讨论如何使用嵌套for循环中来处理二维数组。 C没有提供二维数组类型&#xff0c;但是用户可以创建每个元素本身都是数组的数组。例如&#xff0c;假设要存储5个城市在4年间的最高温度&#xff0c;可以这样声明数组&#xff1a; int m…

机器学习入门(第四天)——朴素贝叶斯

知识树 Knowledge tree P(y|x)&#xff0c;P给定x的条件下&#xff0c;y的概率。如&#xff1a;P(y我招女孩子喜欢的概率|我是学生) 一个小故事 A story 女朋友和妈妈掉河里&#xff0c;路人拿出3颗豆&#xff0c;两颗红豆1颗绿豆。如果我抽中红豆救女朋友&#xff0c;抽中绿…