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

news2024/11/29 0:41:23

文章目录

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

本节最终效果

在这里插入图片描述

前言

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

近战武器

新增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; // 武器/子弹的ID
    public int prefabId; // 武器/子弹预制体的ID
    public 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; // 初始化最近的目标为null
        float 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。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

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

相关文章

医疗器械企业升级路:直连客户盘活存量,布局出海寻求增量

随着随着医疗各领域VBP&#xff08;带量采购&#xff09;的稳步推进以及医疗机构DRG/DIP&#xff08;按疾病诊断相关分组/病种分值支付&#xff09;的深化应用&#xff0c;降本增效和精细化管理已经成为医院管理者的头等大事。 这也在倒逼医疗器械厂商提升管理水平和营销效率。…

Springboot的excel导出

这里导出excel用到的是 阿里巴巴的easyexcel 1、首先导入依赖 <!--alibaba easyexcel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.6</version> </dependency> 2、…

IWDG和WWDG HAL库+cubeMX

一.IWDG 1.原理 启用IWDG后&#xff0c;LSI时钟会自动开启 2.IWDG溢出时间计算 3.IWDG配置步骤 4.HAL库相关函数介绍 HAL_IWDG_Init //使能IWDG&#xff0c;设置预分频系数和重装载值等 HAL_IWDG_Refresh //把重装载寄存器的值重载到计数器中&#xff0c;喂狗typedef str…

解决苹果手机iphone手机强制重启

强制关机&#xff1a; 方法1.同时按住左侧的&#xff0c;- 键中的一个和右侧的电源键 方法2.点击桌面的悬浮键–设备–更多–重新启动

华住三季报:韧性增长超预期,夯实可持续发展底座

美股研究社获悉&#xff0c;2023年11月27日&#xff0c;华住集团2023年第三季度业绩发布会在线上举行。受华住三季度财报向好表现&#xff0c;多家证券公司给予买入评级。中信证券认为&#xff0c;本季度华住集团国内外RevPAR修复优于前期指引上限、净开店数优于预期。且华住集…

JAVA面向对象三大特征

1.面向对象的三大特征包括封装、继承和多态。 封装&#xff1a;封装是指将数据和操作数据的方法绑定起来&#xff0c;外界对数据的访问只能通过已定义的接口。这种特性有两层含义&#xff0c;一层是将属性和行为看成一个密不可分的整体&#xff0c;将这两者封装在一个对象中&a…

【虚拟机】Docker基础 【一】

1.1.部署MySQL 首先&#xff0c;我们利用Docker来安装一个MySQL软件&#xff0c;大家可以对比一下之前传统的安装方式&#xff0c;看看哪个效率更高一些。 如果是利用传统方式部署MySQL&#xff0c;大概的步骤有&#xff1a; 搜索并下载MySQL安装包上传至Linux环境编译和配置…

c++|类与对象(中)

目录 一、类的6个默认成员函数 二、构造函数 2.1概念 2.2七大特性 三、析构函数 3.1概念 3.2特性 四、拷贝构造函数 4.1概念 4.2特性 五、赋值运算符重载 5.1运算符重载 5.2赋值运算符重载 5.3前置和后置重载 六、const成员函数 七、取地址及const取地址操作符重…

AI 学习笔记(持续更新)

What is AI PS &#xff1a;代码块里的统一是 gpt4 回复 在大模型中 1 b 10 亿参数的含义 AI 目前是什么&#xff1f; 目前的人工智能&#xff08;AI&#xff09;是指使计算机和机器能够模仿人类智能的技术&#xff0c;包括学习、推理、解决问题、知觉、语言理解等能力。A…

每日一练2023.11.28——A-B【PTA】

题目链接&#xff1a;L1-011 A-B 题目要求&#xff1a; 本题要求你计算A−B。不过麻烦的是&#xff0c;A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉&#xff0c;剩下的字符组成的就是字符串A−B。 输入格式&#xff1a; 输入在2行中先后给出字符串A和B…

基于Spring Boot的疫苗接种系统-计算机毕设 附源码 32315

基于Spring Boot的疫苗接种系统 摘 要 预防预接种工作实行网络信息化管理&#xff0c;是我国免疫规划工作发展的需要。接种信息实行网络信息化不仅是预防接种工作步入了一个新的台阶&#xff0c;更重要的是解决了多年疫苗接种过程种&#xff0c;免疫接种剂次不清&#xff0c;难…

接手了一个外包开发的项目,我感觉我的头快要裂开了~

嗨&#xff0c;大家好&#xff0c;我是飘渺。 最近&#xff0c;我和小伙伴一起接手了一个由外包团队开发的微服务项目&#xff0c;这个项目采用了当前流行的Spring Cloud Alibaba微服务架构&#xff0c;并且是基于一个“大名鼎鼎”的微服务开源脚手架&#xff08;附带着模块代…

JAVA基础进阶(一)

一、什么是继承 把相同的属性和行为抽离出来放到父类&#xff0c;再让子类使用extends关键字继承父类后&#xff0c;就可以直接使用父类公共的属性和方法了&#xff0c;提高了代码的复用性可以降低重复代码的书写。 子类既有自己类的属性和行为&#xff0c;也有父类的属性和行…

两个mongo表,A和B,以A中的_id记录的为准, 删掉B表中A表中没有的记录

可以使用 MongoDB 的聚合管道和 $lookup 操作符来实现这个需求。以下是一个示例的查询语句,假设集合 A 和集合 B 分别对应表 A 和表 B: db.B.aggregate([{$lookup: {from: "A",localField: "_id",foreignField:

双十二有什么好物是值得推荐?智能家居好物推荐

都知十一月份跟十二月份都有两个大促的时间&#xff0c;那就是双十一跟双十二&#xff0c;距离双十一过去已经半个月了&#xff0c;是不是还有很多朋友在双十一的时候也没有买尽兴&#xff0c;别慌&#xff01;错过了双十一咱还有双十二&#xff0c;双十二的优惠力度也不会低于…

Day44力扣打卡

打卡记录 给小朋友们分糖果 II&#xff08;容斥原理 隔板法&#xff09; 链接 def c2(n):return n * (n - 1) // 2 if n > 1 else 0class Solution:def distributeCandies(self, n: int, limit: int) -> int:return c2(n 2) - 3 * c2(n - limit 1) 3 * c2(n - 2 * …

Git 是一种分布式版本控制系统常用指令

Git 是一种分布式版本控制系统&#xff0c;用于跟踪文件的变化并协同多人在同一个项目中进行开发。以下是一些常用的 Git 指令和它们的使用介绍&#xff1a; 1. 初始化一个新仓库 git init 用途&#xff1a;在当前目录初始化一个新的 Git 仓库。使用&#xff1a;在项目根目录执…

Istio新架构揭秘:环境化Mesh

自问世以来&#xff0c;Istio因其使用Sidecar&#xff08;可编程代理与应用容器一同部署&#xff09;而备受认可。这种架构选择使Istio用户能够享受其好处&#xff0c;而无需对其应用进行 drast 改变。这些可编程代理&#xff0c;与应用容器紧密部署在一起&#xff0c;因其能够…

进入最后倒计时!就在深圳福田明天上午9点正式开幕!不容错过!

会展中心介绍 深圳会展中心交通快捷便利&#xff0c;南邻滨河快速干道&#xff0c;与口岸、港口及高速公路相连&#xff0c;驾车驱往深圳火车站仅需15分钟、深圳机场仅需30分钟。地铁1号、4号线在会展中心站接驳&#xff0c;通过市政地下通道可从馆内直达地铁站&#xff0c;仅需…

Paragon NTFS16Mac读写外置移动硬盘专业工具

Paragon NTFS for Mac16是一款非常不错的Mac读写工具&#xff0c;解决了大部分Mac电脑用户无法读取移动硬盘的困扰&#xff0c;Paragon NTFS for 16版一直是Mac OS平台上最受欢迎的NTFS硬盘格式读取工具&#xff0c;有了NTFS for Mac &#xff0c;安装了双系统的Mac用户可以在O…