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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

REST-Assured--JAVA REST服务自动化测试的Swiss Army Knife

什么是REST-Assured REST Assured是一套基于 Java 语言实现的开源 REST API 测试框架 Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into t…

Java第二十章多线程

一、线程简介 线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。一个进程可以包含多个线程&#xff0c;这些线程可以并发执行。线程拥有自己的栈和局部变量&#xff0c;但是它们共享进程的其他资源&#xff0c;如…

STM32_10(I2C)

I2C通信 I2C&#xff08;Inter IC Bus&#xff09;是由Philips公司开发的一种通用数据总线两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;、SDA&#xff08;Serial Data&#xff09;同步&#xff0c;半双工带数据应答支持总线挂载多设备&#xff08;一主多从…

网络和信息系统指令 ( NIS2 ) 及其全球影响

网络和信息系统指令 ( NIS2 ) 将于 2024 年 10 月生效&#xff0c;旨在提高欧盟 (EU) 的网络弹性。 不过&#xff0c;其影响可能会更广泛&#xff0c;带来更严格的流程和控制&#xff0c;并重新定义我们向被视为国家关键的组织提供服务的方式。 该强制性指令将具有效力&#x…

如果每天工资按代码行数来算,来看看你每天工资是多少

说在前面 &#x1f63c;&#x1f63c;如果每天的工资取决于我们所编写的代码行数&#xff0c;那么我们的生活会发生怎样的改变&#xff1f;来看看你的同事们今天都提交了多少代码吧&#xff0c;看看谁是卷王&#xff0c;谁在摸鱼&#xff08;&#x1f436;&#x1f436;狗头保命…

利用Spring Boot构建restful web service的详细流程

本文档构建一个简单的restful webservice&#xff0c; 在官网原文Getting Started | Building a RESTful Web Service (spring.io)的基础上进行操作 文章目录 一、项目创建流程1.1 创建项目1.2 创建资源表示类1.3 创建资源控制类 二、项目运行参考资料 一、项目创建流程 本文的…

笔记61:注意力提示

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章&#xff1a;动手学深度学习~注意力机制 a a a a a a a a

七、Lua字符串

文章目录 一、字符串&#xff08;一&#xff09;单引号间的一串字符&#xff08;二&#xff09;local str "Hello, "&#xff08;三&#xff09;[[ 与 ]] 间的一串字符&#xff08;四&#xff09;例子 二、字符串长度计算&#xff08;一&#xff09;string.len&…

RabbitMQ高级特性2 、TTL、死信队列和延迟队列

MQ高级特性 1.削峰 设置 消费者 测试 添加多条消息 拉取消息 每隔20秒拉取一次 一次拉取五条 然后在20秒内一条一条消费 TTL Time To Live&#xff08;存活时间/过期时间&#xff09;。 当消息到达存活时间后&#xff0c;还没有被消费&#xff0c;会被自动清除。 RabbitMQ…

服务器主机安全如何保障

随着互联网的快速发展&#xff0c;服务器主机安全问题日益凸显。服务器主机是网络世界中的核心&#xff0c;其安全性关乎着整个网络系统的稳定性和可靠性。 当前&#xff0c;服务器主机面临着多种安全威胁。其中&#xff0c;网络攻击是最为常见的一种。网络攻击者利用各种手段…

ELK+Filebeat

Filebeat概述 1.Filebeat简介 Filebeat是一款轻量级的日志收集工具&#xff0c;可以在非JAVA环境下运行。 因此&#xff0c;Filebeat常被用在非JAVAf的服务器上用于替代Logstash&#xff0c;收集日志信息。实际上&#xff0c;Filebeat几乎可以起到与Logstash相同的作用&…

Linux—进程状态

目录 一.前言 1.1.通过系统调用获取进程标示符 1.2.通过系统调用创建进程 二.进程状态 三.Z(zombie)-僵尸进程 四.僵尸进程危害 一.前言 学习进程的状态&#xff0c;我们首先了解一下进程的基本数据 1.1.通过系统调用获取进程标示符 由getpid&#xff08;&#xff09…

多个nginx共享值、缓存问题

背景 目前我在集成登录认证功能&#xff08;cas&#xff09;&#xff0c;使用的架构是nginxlua&#xff0c;由于我们有多个系统&#xff08;全是前端项目&#xff09;&#xff0c;每套系统都采用nginxlua的方式进行部署&#xff08;即每个系统都是一个nginx&#xff09;&#…

pytorch读取tiny-imagenet-200的验证集(val)

ori_train torchvision.datasets.ImageFolder(root args.datadir /tiny-imagenet-200/train/, transformtransform)#可以获取class_idx的映射class_idx ori_train.class_to_idx val_annotations.txt中存储着每个图片对应的类别 获取验证集的标签 test_target []#读取val_…

java:jpa、Hibernate、Spring Data JPA、ORM以及和mybatis的区别

文章目录 Java连接数据库几种方式JPAHibernate和Spring Data JPAORM框架jpa和mybatis区别Spring Boot JPA使用例子1、创建库和表2、添加依赖3、配置数据源和Hibernate属性4、配置实体类5、创建一个继承JpaRepository的接口&#xff1a;6、创建一个控制器&#xff08;Controller…

汽车电子 -- 车载ADAS之FCTA/FCTB(前方横向来车碰撞预警/制动)

参看&#xff1a;功能定义-前方交通穿行提示&制动 1、前方横向来车碰撞预警/制动 FCTA/FCTB&#xff08; Front Cross Traffic Alert /Brake&#xff09; 前方横向来车碰撞预警FCTA&#xff08; Front Cross Traffic Alert &#xff09; 其功能表现为在车辆低速前进时&am…

解锁 ElasticJob 云原生实践的难题

发生了什么 最近在逛 ElasticJob 官方社区时发现很多小伙伴都在头疼这个 ElasticJob 上云的问题&#xff0c;ElasticJob 本就号称分布式弹性任务调度框架&#xff0c;怎么在云原生环境就有了问题了呢&#xff0c;这就要从 Kubenertes 和 ElasticJob 的一些状态化说起。 有意思的…

Java SE

目录 编程编的其实就是启动之后的内存⭐配置环境Java环境Windows配置Java环境变量Linux配置Java环境变量前言&#xff1a;常见Linux系统 Java基础类型八大基本数据类型数值型非数值型 void引用数据类型 运算符位运算符其他 基本结构表达式方法类实例&#xff08;对象&#xff0…

战略制定|竞争战略管理分析六大常用工具

企业战略可从多个角度理解&#xff0c;体现为著名的5P模型。首先&#xff0c;从未来发展视角看&#xff0c;战略是一种计划(Plan)&#xff0c;指导企业朝向既定目标前进。而从过去的发展历程看&#xff0c;它呈现为一种模式(Pattern)&#xff0c;反映了企业的历史行为趋势。在产…

【Apifox】测试工具自动编写接口文档

在开发过程中&#xff0c;我们总是避免不了进行接口的测试&#xff0c; 而相比手动敲测试代码&#xff0c;使用测试工具进行测试更为便捷&#xff0c;高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman&#xff0c;他还拥有一个非常nb的功能&#xff0c; 在接…