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

文章目录

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

先看本次实现的最终效果

在这里插入图片描述

前言

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

敌人生命值

绘制血条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.hqwc.cn/news/185971.html

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

相关文章

嵌入式酒精壁炉:时尚生活的新宠

在这个注重品质与生活方式的时代&#xff0c;我们对于家居生活的要求早已不仅仅停留在实用性上。越来越多的人希望能够在家中营造一种时尚、温馨的氛围&#xff0c;而酒精壁炉恰好成为了这个潮流生活的代表。 如今&#xff0c;品质生活已经成为时尚的代名词。酒精壁炉以其精湛的…

使用VMware安装linux虚拟机

文章目录 一、介绍二、下载VMware三、下载centOS镜像文件四、新建虚拟机1. 选择配置类型2. 安装centOS操作系统3. 命名4. 指定磁盘容量5. 虚拟机配置信息确认6. 稍后选择系统镜像 五、安装虚拟机1. 选择语言2. 设置时间、系统、以及yum源3. 开始安装4. 设置root用户密码5. 完成…

抖音自动评论助手,其开发流程与需要的技术和代码分享

先来看实操成果&#xff0c;↑↑需要的同学可看我名字↖↖↖↖↖&#xff0c;或评论888无偿分享 在当今这个信息爆炸的时代&#xff0c;我们不难发现&#xff0c;无论是在线上还是线下&#xff0c;我们都无法忽视一个重要的信息传播工具——抖音。这款短视频平台以其强大的传播…

应用在城市井盖积水检测中的深水液位传感芯片

城市井盖积水检测系统以实现城市下水道水雨情信息“全要素、全量程、全覆盖”自动测报为目标&#xff0c;具备下水道水位、雨量、流速、流量、雨量、气象参数、现场图像、视频等水文信息采集、传输、处理及预警等功能&#xff0c;有效提升了雨水情信息的时效性和准确度&#xf…

二进制分析工具-radare2使用教程

二进制分析工具-radare2使用教程 按照如下执行命令 按照如下执行命令 r2 -A 二进制文件

解析CAD图纸出现乱码的原因及解决方法

解析CAD图纸出现乱码的原因及解决方法 CAD&#xff08;计算机辅助设计&#xff09;是现代工程设计中不可或缺的工具&#xff0c;它能够帮助工程师们高效地完成复杂的设计任务。然而&#xff0c;有时在使用CAD软件过程中&#xff0c;可能会遇到图纸出现乱码的问题&#xff0c;影…

6块钱改变世界,网易和拼多多踏入同一条河流?

年底将至&#xff0c;各种颁奖盛典星光熠熠。如果要给今年深蹲反弹中的互联网大厂颁奖&#xff0c;2023表现最突出的可能是师出同门的兄弟网易和拼多多。 从市场表现来看&#xff0c;两家企业录得今年互联网中概股最高涨幅&#xff0c;被称为“中概股之光”&#xff1a;2023年…

python列出本地文件路径

按照之前的设想&#xff0c;如果要罗列出本地文件的列表&#xff0c;那不是需要不断的判断文件夹里面的文件夹吗&#xff1f;或者需要使用递归函数本身&#xff0c;才能达到目的吧&#xff1f;没想到使用pop这个函数就可以了。pop是取出元素&#xff0c;那列表里就少了一个&…

babel 无法加载解决方案

Visual Studio Code babel无法加载文件 babel : 无法加载文件 C:\Users\18327\AppData\Roaming\npm\babel.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c; 请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 所在…

会声会影2024什么时候发布更新?有哪些新功能

会声会影2024升级来袭&#xff0c;Corel公司这次为用户带来了多项功能更新&#xff0c;软件风格整体更偏向于“轻松剪辑&#xff0c;快速出片”。会声会影的本次更新还是很令人惊喜的&#xff0c;在各种人工智能算法的加持下&#xff0c;用户只需要进行几步简单地设置&#xff…

PUBG官方【违规处罚工作公示】11月6日-11月12日

11月6日至11月12日期间&#xff0c;共计对63,355个违规账号进行了封禁&#xff0c;其中56,123个账号因使用外挂被永久封禁。 若您游戏中遇到违规行为&#xff0c;建议您优先在游戏内进行举报&#xff1b;另外您也可以在官方微信公众号【PUBG国际版】中点击“ 服务中心 - 举报外…

C++第一讲:起源和规范

面向过程和面向对象 大千世界中&#xff0c;事务的发展规律都是面向过程的状态。例如一颗种子从生根到发芽&#xff0c;从发芽到开花&#xff0c;从开花到结果。 但是面向过程是一个更贴近**“机械”**的表达方式&#xff0c;而更贴近人类思想的却是面向对象的表达方式。 以…