【用unity实现100个游戏之17】从零开始制作一个类幸存者肉鸽(Roguelike)游戏3(附项目源码)

本文主要是介绍【用unity实现100个游戏之17】从零开始制作一个类幸存者肉鸽(Roguelike)游戏3(附项目源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 本节最终效果
  • 前言
  • 近战武器
  • 控制近战武器生成
  • 升级增加武器伤害和数量
  • 查找离主角最近的敌人
  • 子弹预制体
  • 生成子弹
  • 发射子弹
  • 参考
  • 源码
  • 完结

本节最终效果

在这里插入图片描述

前言

本节紧跟着上一篇,主要实现武器功能。

近战武器

新增Bullet,子弹脚本

public class Bullet : MonoBehaviour
{public float damage; // 子弹的伤害值/// <summary>/// 初始化子弹的属性/// </summary>/// <param name="damage">伤害值</param>public void Init(float damage){this.damage = damage; // 设置子弹的伤害值}
}

新增近战武器预制体,添加触发器,挂载脚本,配置参数
在这里插入图片描述

修改Enemy敌人脚本,添加触发器检测

void OnTriggerEnter2D(Collider2D collision)
{if (!collision.CompareTag("Bullet")) return;health -= collision.GetComponent<Bullet>().damage;if (health > 0){}else{Dead();}
}void Dead()
{gameObject.SetActive(false);
}

效果,敌人触碰死亡
在这里插入图片描述

控制近战武器生成

配置近战武器进对象池
在这里插入图片描述

新增Weapon。控制武器/子弹的生成

public class Weapon : MonoBehaviour
{public int id; // 武器/子弹的IDpublic int prefabId; // 武器/子弹预制体的IDpublic float damage; // 武器/子弹的伤害值public int count; // 发射武器/子弹的数量public float speed; // 武器旋转的速度void Start(){Init(); // 初始化武器属性}void Update(){switch (id){case 0:transform.Rotate(Vector3.back, speed * Time.deltaTime); // 绕z轴旋转武器break;default:break;}}/// <summary>/// 初始化武器/子弹属性/// </summary>public void Init(){switch (id){case 0:speed = 150; // 设置武器旋转的速度Batch();break;default:break;}}/// <summary>/// 批量配置武器属性/// </summary>void Batch(){for (int index = 0; index < count; index++){Transform bullet = GameManager.instance.pool.Get(prefabId).transform; // 从对象池中获取武器预制体的实例bullet.parent = transform; // 设置武器的父级为武器Vector3 rotvec = Vector3.forward * 360 * index / count; // 计算武器的旋转角度,使其均匀分布在圆周上bullet.Rotate(rotvec); // 设置武器的旋转角度bullet.Translate(bullet.up * 1.5f, Space.World); // 将武器沿着自身的y轴方向向前移动一定距离bullet.GetComponent<Bullet>().Init(damage); // 初始化武器的属性}}
}

挂载配置参数
在这里插入图片描述
单武器效果
在这里插入图片描述
多武器效果
在这里插入图片描述
在这里插入图片描述

升级增加武器伤害和数量

修改Weapon

void Update()
{//。。。//测试if (Input.GetKeyDown(KeyCode.Space)){LevelUp(20, 5);}
}/// <summary>
/// 批量配置武器属性
/// </summary>
void Batch()
{for (int index = 0; index < count; index++){Transform bullet;if (index < transform.childCount){bullet = transform.GetChild(index);}else{bullet = GameManager.instance.pool.Get(prefabId).transform;// 从对象池中获取武器预制体的实例bullet.parent = transform;// 设置武器的父级为武器}//。。。}
}

效果
在这里插入图片描述

查找离主角最近的敌人

新增Scanner

public class Scanner : MonoBehaviour
{public float scanRange; // 扫描范围public LayerMask targetLayer; // 目标层public RaycastHit2D[] targets; // 扫描到的目标public Transform nearestTarget; // 最近的目标void FixedUpdate(){targets = Physics2D.CircleCastAll(transform.position, scanRange, Vector2.zero, 0, targetLayer); // 在扫描范围内发射圆形光线,获取扫描到的目标nearestTarget = GetNearest();}// 获取最近的目标Transform GetNearest(){Transform result = null; // 初始化最近的目标为nullfloat diff = scanRange; // 初始化最小距离为100,用于后面比较foreach (RaycastHit2D target in targets){Vector3 myPos = transform.position; // 获取自身位置Vector3 targetPos = target.transform.position; // 获取目标位置float curDiff = Vector3.Distance(myPos, targetPos); // 计算自身与目标的距离if (curDiff < diff) // 如果当前目标距离比之前的最小距离还小,说明这个目标更近{diff = curDiff; // 更新最小距离result = target.transform; // 更新最近的目标}}return result; // 返回最近的目标}//场景窗口可视化射线private void OnDrawGizmos(){Gizmos.DrawWireSphere(transform.position, scanRange);Gizmos.color = Color.red;}
}

挂载脚本,配置参数
在这里插入图片描述

效果,获取了离自己最近的敌人
在这里插入图片描述

子弹预制体

在这里插入图片描述

对象池挂载子弹
在这里插入图片描述

生成子弹

修改Weapon

float timer;
Player player;void Start()
{player = GameManager.instance.player;Init(); // 初始化武器属性
}void Update()
{switch (id){//。。。default:timer += Time.deltaTime;if (timer > speed){timer = 0f;Fire();}break;}
}/// <summary>
/// 初始化武器/子弹属性
/// </summary>
public void Init()
{switch (id){//。。。default:speed = 0.3f;break;}
}//发射子弹
void Fire()
{if (!player.scanner.nearestTarget) return;Transform bullet = GameManager.instance.pool.Get(prefabId).transform;bullet.position = transform.position;
}

修改Player,获取最近的敌人数据

[NonReorderable]
public Scanner scanner;scanner = GetComponent<Scanner>();

配置子弹生成容器及数据
在这里插入图片描述
效果,每0.3秒生成一个子弹
在这里插入图片描述

发射子弹

修改Bullet

Rigidbody2D rigid;
private int per; // 子弹的穿透次数void Awake()
{rigid = GetComponent<Rigidbody2D>(); // 获取子弹的刚体组件
}public void Init(float damage, int per, Vector3 dir)
{this.damage = damage; // 初始化子弹的伤害值this.per = per; // 初始化子弹的穿透次数if (per > -1){rigid.velocity = dir * 15f; // 如果子弹具有穿透次数,则设置子弹的初始速度和方向}
}void OnTriggerEnter2D(Collider2D collision)
{if (!collision.CompareTag("Enemy") || per == -1) return; // 如果碰撞物体不是敌人或子弹没有穿透次数,直接返回per--; // 穿透次数减一if (per == -1){rigid.velocity = Vector2.zero; // 如果穿透次数减到-1,即没有穿透能力了,将子弹的速度设为零gameObject.SetActive(false); // 将子弹设为非激活状态,使其隐藏或回收}
}

修改Weapon

void Batch()
{//。。。bullet.GetComponent<Bullet>().Init(damage, -1, Vector3.zero); // 初始化武器的属性}
}// 发射子弹
void Fire()
{if (!player.scanner.nearestTarget) return; // 如果玩家的扫描器没有最近的目标,直接返回Vector3 targetPos = player.scanner.nearestTarget.position; // 获取最近目标的位置Vector3 dir = targetPos - transform.position; // 计算从当前位置指向目标位置的方向向量dir = dir.normalized; // 将方向向量归一化,使其成为单位向量Transform bullet = GameManager.instance.pool.Get(prefabId).transform; // 从对象池中获取一个子弹对象bullet.position = transform.position; // 设置子弹的初始位置为当前位置bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir); // 将子弹的朝向调整为指向目标位置的方向bullet.GetComponent<Bullet>().Init(damage, count, dir); // 初始化子弹的伤害值、穿透次数和初始速度方向
}

效果
在这里插入图片描述

修改Weapon,升级测试

//测试
if (Input.GetKeyDown(KeyCode.Space))
{LevelUp(10, 1);
}

效果,升级后子弹具有了一定穿透性
在这里插入图片描述

参考

【视频】https://www.youtube.com/watch?v=MmW166cHj54&list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x

源码

源码在最后一节

完结

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

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

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

这篇关于【用unity实现100个游戏之17】从零开始制作一个类幸存者肉鸽(Roguelike)游戏3(附项目源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/431723

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、