【用unity实现100个游戏之15】开发一个类保卫萝卜的Unity2D塔防游戏2(附项目源码)

news2024/11/27 19:36:38

文章目录

  • 先看本次实现的最终效果
  • 前言
  • 敌人生命值
  • 扣血测试,
  • 敌人死亡
  • 控制敌人动画
  • 敌人死亡动画
  • 敌人转向问题
  • 源码
  • 完结

先看本次实现的最终效果

在这里插入图片描述

前言

本期紧接着上一篇,本期主要内容是实现敌人血条、动画和行为逻辑。

敌人生命值

绘制血条UI
在这里插入图片描述

新建

public class EnemyHealth : MonoBehaviour
{
    [SerializeField, Header("血条预制体")] private GameObject healthBarPrefab;
    [SerializeField, Header("血条位置")] private Transform barPosition;
    [SerializeField, Header("初始生命值")] private float initialHealth = 10f;
    [SerializeField, Header("最大生命值")] private float maxHealth = 10f;

    private void Start()
    {
        CreateHealthBar();
    }

    // 创建血条
    private void CreateHealthBar()
    {
        // 实例化血条预制体并设置位置为敌人的位置
        GameObject newBar = Instantiate(healthBarPrefab, barPosition.position, Quaternion.identity);
        
        // 设置血条的父物体为当前敌人,使血条随着敌人移动
        newBar.transform.SetParent(transform);
    }
}

配置
在这里插入图片描述

效果
在这里插入图片描述

扣血测试,

新增

public class EnemyHealthContainer : MonoBehaviour {
    [SerializeField]private Image fillAmountImage;
    public Image FillAmountImage => fillAmountImage;
}

修改EnemyHealth

public class EnemyHealth : MonoBehaviour
{
    [SerializeField, Header("血条预制体")] private GameObject healthBarPrefab;
    [SerializeField, Header("血条位置")] private Transform barPosition;
    [SerializeField, Header("初始生命值")] private float initialHealth = 10f;
    [SerializeField, Header("最大生命值")] private float maxHealth = 10f;

    public float CurrentHealth { get; set; }
    private Image _healthBar;
    private void Start()
    {
        CreateHealthBar();
        CurrentHealth = initialHealth;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.P))
        {
            DealDamage(5f);
        }
        _healthBar.fillAmount = Mathf.Lerp(_healthBar.fillAmount, CurrentHealth / maxHealth, Time.deltaTime * 10f);
    }

    // 创建血条
    private void CreateHealthBar()
    {
        // 实例化血条预制体并设置位置为敌人的位置
        GameObject newBar = Instantiate(healthBarPrefab, barPosition.position, Quaternion.identity);

        // 设置血条的父物体为当前敌人,使血条随着敌人移动
        newBar.transform.SetParent(transform);

        EnemyHealthContainer container = newBar.GetComponent<EnemyHealthContainer>();

        _healthBar = container.FillAmountImage;
    }

    public void DealDamage(float damage)
    {
        CurrentHealth -= damage;
    }
}

效果
在这里插入图片描述

敌人死亡

敌人死亡送回池内,并重置健康值,修改EnemyHealth

public static Action OnEnemyKilled;//定义敌人被杀死委托事件

    public void ResetHealth(){
        CurrentHealth = initialHealth;
        _healthBar.fillAmount = 1f;
    }

    public void DealDamage(float damage)
    {
        CurrentHealth -= damage;
        if (CurrentHealth <= 0)
        {
            CurrentHealth = 0;
            Die();
        }
    }

    private void Die()
    {
        ResetHealth();
        OnEnemyKilled?.Invoke();
        ObjectPooler.ReturnToPool(gameObject);
    }

修改Spawner,调用敌人死亡委托

    private void RecordEnemy()
    {
        _enemiesRamaining--;
        if (_enemiesRamaining <= 0) StartCoroutine(NextWave());
    }

    private void OnEnable()
    {
        Enemy.OnEndReached += RecordEnemy;
        EnemyHealth.OnEnemyKilled += RecordEnemy;
    }

    private void OnDisable()
    {
        Enemy.OnEndReached -= RecordEnemy;
        EnemyHealth.OnEnemyKilled -= RecordEnemy;
    }

敌人扣除部分生命值,到达终点也要重置生命值

修改Enemy

private EnemyHealth _enemyHealth;

_enemyHealth = GetComponent<EnemyHealth>();

//回收敌人
private void ReturnEnemyToPool()
{
    OnEndReached?.Invoke();
    _enemyHealth.ResetHealth();
    ObjectPooler.ReturnToPool(gameObject);
}

效果
在这里插入图片描述

控制敌人动画

添加一个敌人动画控制器
在这里插入图片描述

因为敌人的逻辑都一样,除了动画不一样,所以其他敌人我们可以创建动画覆盖控制器实现,修改对应的动画即可
在这里插入图片描述

在这里插入图片描述

修改EnemyHealth,定义敌人受伤委托

public static Action<Enemy> OnEnemyHit;//定义敌人受伤委托事件
private Enemy _enemy;

_enemy = GetComponent<Enemy>();

public void DealDamage(float damage)
    {
        CurrentHealth -= damage;
        if (CurrentHealth <= 0)
        {
            //。。。
        }
        else
        {
            OnEnemyHit?.Invoke(_enemy);
        }
    }

新增EnemyAnimations类用于控制敌人的动画播放。PlayHurt方法是一个协程,用于播放受伤动画并暂停敌人的移动一段时间后恢复移动。EnemyHit方法是处理敌人被击中事件的方法,通过判断传入的敌人和当前敌人是否匹配来决定是否播放受伤动画。在OnEnable方法中注册了对EnemyHealth.OnEnemyHit事件的监听,在OnDisable方法中取消了对该事件的监听。

public class EnemyAnimations : MonoBehaviour
{
    private Animator _animator; // 敌人动画控制组件
    private Enemy _enemy; // 敌人组件

    private void Start()
    {
        _animator = GetComponent<Animator>(); // 获取敌人动画控制组件
        _enemy = GetComponent<Enemy>(); // 获取敌人组件
    }

    // 播放受伤动画
    private void PlayHurtAnimation()
    {
        _animator.SetTrigger("Hurt"); // 设置触发器播放受伤动画
    }

    // 播放死亡动画
    private void PlayDieAnimation()
    {
        _animator.SetTrigger("Die"); // 设置触发器播放死亡动画
    }

    // 播放受伤动画的协程
    private IEnumerator PlayHurt()
    {
        _enemy.StopMovement(); // 停止敌人移动
        PlayHurtAnimation(); // 播放受伤动画
        yield return new WaitForSeconds(GetCurrentAnimationLength() + 0.3f); // 等待当前动画长度+0.3秒
        _enemy.ResumeMovement(); // 恢复敌人移动
    }

    // 敌人被击中的事件处理方法
    private void EnemyHit(Enemy enemy)
    {
        if (_enemy == enemy)
        {
            StartCoroutine(PlayHurt()); // 开始播放受伤动画的协程
        }
    }

    private void OnEnable()
    {
        EnemyHealth.OnEnemyHit += EnemyHit; // 注册敌人被击中的事件监听
    }

    private void OnDisable()
    {
        EnemyHealth.OnEnemyHit -= EnemyHit; // 取消敌人被击中的事件监听
    }
}

修改Enemy

public float MoveSpeed;//保存移速

public void StopMovement()
{
    moveSpeed = 0f;
}

public void ResumeMovement()
{

    moveSpeed = MoveSpeed;
}

效果
在这里插入图片描述

敌人死亡动画

订阅敌人死亡事件
修改EnemyHealth

public static Action<Enemy> OnEnemyKilled;//定义敌人被杀死委托事件

private void Die()
{
    // ResetHealth();
    OnEnemyKilled?.Invoke(_enemy);
    // ObjectPooler.ReturnToPool(gameObject);
}

修改EnemyAnimations

private EnemyHealth _enemyHealth; // 敌人组件

_enemyHealth = GetComponent<EnemyHealth>();

private IEnumerator PlayDead()
{
    _enemy.StopMovement();
    PlayDieAnimation();
    yield return new WaitForSeconds(GetCurrentAnimationLength());
    _enemy.ResumeMovement();
    _enemyHealth.ResetHealth();
    ObjectPooler.ReturnToPool(_enemy.gameObject);
}

private void EnemyDead(Enemy enemy)
{
    if (_enemy == enemy)
    {
        StartCoroutine(PlayDead());
    }
}

private void OnEnable()
{
    EnemyHealth.OnEnemyHit += EnemyHit; // 注册敌人被击中的事件监听
    EnemyHealth.OnEnemyKilled += EnemyDead;
}

private void OnDisable()
{
    EnemyHealth.OnEnemyHit -= EnemyHit; // 取消敌人被击中的事件监听
    EnemyHealth.OnEnemyKilled -= EnemyDead;
}

修改死亡动画为不循环
在这里插入图片描述

效果
在这里插入图片描述

敌人转向问题

修改Enemy

private Vector3 _lastPointPosition;
private SpriteRenderer _spriteRenderer;

private void Start()
{
     //...
     _spriteRenderer = GetComponent<SpriteRenderer>();

     _lastPointPosition = transform.position;
 }
private void Update()
{
	//...
    Rotate();
}
 
//控制转向
private void Rotate()
{
    if (CurrentPointPosition.x > _lastPointPosition.x)
    {
        _spriteRenderer.flipX = false;
    }
    else
    {
        _spriteRenderer.flipX = true;
    }
}

效果
在这里插入图片描述

源码

见本项目最后一节

完结

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

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

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

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

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

相关文章

快速入门:构建您的第一个 .NET Aspire 应用程序

##前言 云原生应用程序通常需要连接到各种服务&#xff0c;例如数据库、存储和缓存解决方案、消息传递提供商或其他 Web 服务。.NET Aspire 旨在简化这些类型服务之间的连接和配置。在本快速入门中&#xff0c;您将了解如何创建 .NET Aspire Starter 应用程序模板解决方案。 …

unity 烘焙的时候出现模型没有光影的情况

unity 烘焙的时候出现模型没有光影的情况 1.模型没有设置生成光照贴图 需要勾选模型的生成光照贴图UVs,然后应用 2.游戏对象没有勾选静态选项 点开静态下拉列表&#xff0c;选择 contribute GI

Accelerate 0.24.0文档 四:Megatron-LM

参考《Megatron-LM》 文章目录 一、Megatron-LM集成简介二、环境配置设置conda环境的步骤&#xff1a; 二、Accelerate Megatron-LM Plugin三、自定义训练过程四、检查点转换五、文本生成六、支持ROPE 、 ALiBi和Multi-Query Attention七、注意事项 一、Megatron-LM集成简介 在…

再谈谷歌GMS认证之Android 13

写在前面的话 2023年来到一个新的公司&#xff0c;传说中的做互联网金融即将上市的高大上公司。 入职后才发现就是做pos机设备的一个小厂 哎&#xff0c;什么命啊&#xff01; 工作和手机开发的工作重合度可以达到95%以上&#xff0c;我不想做手机&#xff0c;偏偏又干上…

全网首位数字军人“穆兰”惊艳亮相,与拓世法宝共同绘就未来社会图景

古有穆桂英、花木兰挂帅出征&#xff0c;今有全网首位虚拟数字军人“穆兰”展巾帼风采。今年国庆节后&#xff0c;中国军号在全网为解放军新闻传播中心数字记者暨全军首位超写实虚拟数字军人征名&#xff0c;历时一个多月&#xff0c;经过征名提交、评委初评、公众投票、专家共…

验证码识别之OCR识别

验证码识别&#xff1a; 背景&#xff1a; ​ 决定开一个专题给大家讲一下验证码识别&#xff0c;不要多想&#xff0c;我们不搞深度学习&#xff0c;知识用于攻破模拟登录的时候弹出的验证码&#xff0c;后续会给大家讲讲滑块等等&#xff0c;反爬虫策略如何应对。 好了&am…

如何实现业务系统的单点退出

当前我国各领域正在加速向数字化、移动化、智能化发展&#xff0c;大力投入信息化建设与数字化转型已成为企业的共识&#xff0c;但对于很多企业而言&#xff0c;组织信息环境庞大复杂&#xff0c;业务场景变化频繁&#xff0c;给身份管理与信息安全管理带来很大挑战。随着信息…

Spring Bean的生命周期详细梳理

1. 理解Bean的生命周期 1.1 生命周期的各个阶段 在Spring IOC容器中&#xff0c;Bean的生命周期大致如下&#xff1a; 实例化&#xff1a;当启动Spring应用时&#xff0c;IOC容器就会为在配置文件中声明的每个<bean>创建一个实例。属性赋值&#xff1a;实例化后&#…

linux虚拟机环境快速搭建redis5.x版本的主从集群总结

原创/朱季谦 我在阿里云服务器上曾参与过公司redis集群的搭建&#xff0c;但时间久了&#xff0c;都快忘记当时的搭建过程了&#xff0c;故而决定在虚拟机centOS 7的环境&#xff0c;自行搭建一套redis5.x版本的集群&#xff0c;该版本集群的搭建比较方便&#xff0c;不用再像…

免费图像压缩工具分享:15 个最佳免费图像压缩工具

您想在将图像上传到网上之前对其进行压缩吗&#xff1f;优化摄影网站的图像将有助于您的网站加载速度更快。而且&#xff0c;更快的加载速度意味着更好的搜索引擎排名&#xff01;在本指南中&#xff0c;我们将分享用于图像压缩的最佳免费图像优化工具。 许多照片编辑程序&…

【网络奇遇记】我和因特网的初相遇3 —— 计算机网络体系结构

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 常见的三种计算机网络体系结构1.1 开放系统互连参考模型1.2 TCP/IP参考模型1.3 原理参考模型 二…

电脑上明明保存了文件却不见了?4个恢复技巧分享!

“真的很奇怪&#xff0c;我有一些重要的文件明明保存在电脑上了&#xff0c;但是当我在电脑上查找它们时&#xff0c;却发现有很多文件都不见了。这些保存在电脑上的文件如果不见了怎么找回呢&#xff1f;” 在使用电脑过程中&#xff0c;有时我们会遇到明明保存了文件&#x…

【双向链表】带头双向循环(1)

目录 链表的分类 Test.c主函数 test1头插 test2头删 test3尾插 test4尾删 test5查询 test6插入pos位置后一个 test7删除pos Test.c总代码 DList.h头文件&函数声明 头文件 函数声明 DList.h总代码 DList.c函数实现 Createnode创建节点 LTInit初始化 LTPr…

1~2亿条数据需要缓存之安装redis集群(哈希取余分区、一致性哈希算法分区、哈希槽分区)

安装redis集群 面试题 1~2亿条数据需要缓存&#xff0c;请问如何设计这个存储案例??? 回答: 单机单台100%不可能&#xff0c;肯定是分布式存储&#xff0c;用redis如何落地&#xff1f; 上述问题阿里P6~P7工程案例和场景设计类必考题目&#xff0c; 一般业界有3种解决方案 …

STM32H743 RTC精密数字校准 深度剖析

一、问题 项目中数据报文收到的RTC时间总是会慢一些,经过实际几天的测试得出结论:24小时要慢5S左右。根据手册我了解到可以有误差但不会差这么多,所以进行了如下分析并解决问题。 二、分析 1.影响RTC准确性的因素罗列 硬件基础误差(也就是待校准部分) …

青岛数字孪生赋能工业制造,加速推进制造业数字化转型

随着企业数字化进程的推进&#xff0c;数字孪生技术逐渐在汽车行业得到广泛应用。5G与数字孪生、工业互联网的融合将加速数字中国、智慧社会建设&#xff0c;加速中国新型工业化进程&#xff0c;为中国经济发展注入新动能。数字孪生、工业物联网、工业互联网等新一代信息通信技…

【用unity实现100个游戏之15】开发一个类保卫萝卜的Unity2D塔防游戏3(附项目源码)

文章目录 先看本次实现的最终效果前言绘制炮塔UI炮塔转向敌人生成炮弹旋转我们的子弹对敌人造成伤害&#xff0c;回收子弹自动发射子弹添加攻击间隔显示伤害字体设计通用泛型单例创建更多炮塔升级增加伤害升级缩短攻击间隔添加货币杀死敌人获取金币源码完结 先看本次实现的最终…

有趣的按钮分享

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 广告打完&#xff0c;我们进入正题&#xff0c;先看效果&#xff1a; 废话不多&#xff0c;上源码&#xff1a; <button class&quo…

牛只识别 牛脸识别 个体识别 身份识别

融合YOLOv5s与通道剪枝算法的奶牛轻量化个体识别方法 Light-weight recognition network for dairy cows based on the fusion of YOLOv5s and channel pruning algorithm 论文链接 知网链接 点击进入正文 该文章讨论了奶牛花斑、光照条件、不同剪枝方法、不同剪枝率对准确率的…

OPPO发布AndesGPT大模型;Emu Video和Emu Edit的新突破

&#x1f989; AI新闻 &#x1f680; OPPO发布全新ColorOS 14及自主训练的AndesGPT大模型 摘要&#xff1a;OPPO在2023 OPPO开发者大会上发布了全新的ColorOS 14&#xff0c;并正式推出了自主训练的安第斯大模型&#xff08;AndesGPT&#xff09;。AndesGPT拥有对话增强、个人…