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

news2024/9/22 7:29:46

文章目录

  • 本节最终效果
  • 前言
  • 能力升级系统
  • 绘制升级按钮
  • 武器升级
  • 道具升级
  • 治疗物品效果
  • 双手放置武器
  • 控制武器移动转向排序
  • 默认先隐藏武器,去除默认的武器精灵图片
  • 数据联动
  • 完善升级界面
  • 控制窗口开启关闭
  • 时间控制,升级暂停游戏
  • 每次升级随机获取属性项目
  • 控制等级上限
  • 参考
  • 源码
  • 完结

本节最终效果

在这里插入图片描述

前言

本节紧跟着上一篇,主要实现能力升级系统。

能力升级系统

新增ItemData

[CreateAssetMenu(fileName = "Item", menuName = "Scriptable Object/ItemData")]
public class ItemData : ScriptableObject
{
    public enum ItemType { Melee, Range, Glove, Shoe, Heal } // 物品类型枚举

    [Header("#Main Info")]
    public ItemType itemType; // 物品类型
    public int itemId; // 物品ID
    public string itemName; // 物品名称
    public string itemDesc; // 物品描述
    public Sprite itemIcon; // 物品图标

    [Header("#Level Data")]
    public float baseDamage; // 基础伤害
    public int baseCount; // 基础数量
    public float[] damages; // 不同等级的伤害数组
    public int[] counts; // 不同等级的数量数组

    [Header("#Weapon")]
    public GameObject projectile; // 投射物对象
}

配置各种物品
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

绘制升级按钮

绘制UI按钮,只是用于测试
在这里插入图片描述
新增Item,该类的作用是管理物品的显示和交互,以便在游戏中方便地使用和管理各种物品。

public class Item : MonoBehaviour
{
    // 物品数据,由其他地方赋值
    public ItemData data;
    // 物品等级
    public int level;

    // 引用武器组件
    public Weapon weapon;

    // 物品图标
    Image icon;
    // 物品等级文本
    Text textLevel;

    void Awake()
    {
        // 获取子物体中的Image组件,并将其赋值给icon变量
        icon = GetComponentsInChildren<Image>()[1];
        // 设置icon的sprite为物品的图标
        icon.sprite = data.itemIcon;

        // 获取子物体中的Text组件,并将其赋值给texts数组
        Text[] texts = GetComponentsInChildren<Text>();
        // 将texts数组中的第一个元素赋值给textLevel变量
        textLevel = texts[0];
    }

    // LateUpdate方法,在Update之后调用
    // 通常在此方法中更新UI
    void LateUpdate()
    {
        // 更新物品等级文本的内容
        textLevel.text = "Lv." + (level + 1);
    }
}

挂载脚本,配置参数
在这里插入图片描述
效果
在这里插入图片描述
修改Item,定义点击事件

// 当点击物品时调用的方法
public void OnClick()
{
    // 根据物品类型进行不同的处理
    switch (data.itemType)
    {
        // 如果是近战武器或远程武器
        case ItemData.ItemType.Melee:
        case ItemData.ItemType.Range:
            // 这里可以添加处理近战武器和远程武器的逻辑
            break;
        // 如果是手套
        case ItemData.ItemType.Glove:
            // 这里可以添加处理手套的逻辑
            break;
        // 如果是鞋子
        case ItemData.ItemType.Shoe:
            // 这里可以添加处理鞋子的逻辑
            break;
        // 如果是治疗物品
        case ItemData.ItemType.Heal:
            // 这里可以添加处理治疗物品的逻辑
            break;
    }

    // 物品等级加1
    level++;

    // 如果等级等于物品伤害数组的长度
    if (level == data.damages.Length)
    {
        // 获取Button组件,并将其交互状态设置为false,即不可交互
        GetComponent<Button>().interactable = false;
    }
}

绑定点击事件
在这里插入图片描述
效果
在这里插入图片描述

武器升级

修改Weapon

void Awake()
{
    player = GameManager.instance.player;
    // Init(); // 初始化武器属性
}

void Update()
{
    switch (id)
    {
       //。。。
       if (timer > speed && count > 0)
       {
           timer = 0f;
           Fire();
       }
       break;
    }
}

/// <summary>
/// 初始化武器/子弹属性
/// </summary>
public void Init(ItemData data)
{
    name = "Weapon " + data.itemId; // 设置物品名称
    transform.parent = player.transform; // 设置物品的父级为玩家对象
    transform.localPosition = Vector3.zero; // 设置物品在父级坐标系下的本地位置为(0, 0, 0)
    id = data.itemId; // 设置物品ID
    damage = data.baseDamage; // 设置物品基础伤害
    count = data.baseCount; // 设置物品基础数量

    for (int index = 0; index < GameManager.instance.pool.prefabs.Length; index++)
    {
        if (data.projectile == GameManager.instance.pool.prefabs[index])
        {
            prefabId = index; // 设置投射物的预制体ID
            break;
        }
    }
    //。。。
}

修改Item

// 如果是近战武器或远程武器
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
    // 这里可以添加处理近战武器和远程武器的逻辑
    if(level == 0){
        //开始给玩家一个武器
        GameObject newWeapon = new GameObject();
        weapon = newWeapon.AddComponent<Weapon>();
        weapon.Init(data);
    }else{
        float nextDamage = data.baseDamage;
        int nextCount = 0;
        nextDamage += data.baseDamage * data.damages[level];
        nextCount += data.counts[level];
        weapon.LevelUp(nextDamage, nextCount);
    }
    break;

效果
在这里插入图片描述

道具升级

新增Gear,用于处理道具的属性和应用。

public class Gear : MonoBehaviour
{
    public ItemData.ItemType type; // 物品类型
    public float rate; // 比率

    public void Init(ItemData data)
    {
        // 基本设置
        name = "Gear " + data.itemId; // 设置物品名称
        transform.parent = GameManager.instance.player.transform; // 将物品的父物体设置为玩家对象
        transform.localPosition = Vector3.zero; // 将物品的本地坐标设置为零向量

        // 属性设置
        type = data.itemType; // 设置物品类型
        rate = data.damages[0]; // 选择第一个等级的伤害作为初始值
        ApplyGear(); // 应用物品属性
    }

    public void LevelUp(float rate)
    {
        this.rate = rate; // 更新比率
        ApplyGear(); // 应用物品属性
    }

    void ApplyGear()
    {
        switch (type)
        {
            case ItemData.ItemType.Glove:
                RateUp(); // 手套类型的物品增加攻击速率
                break;
            case ItemData.ItemType.Shoe:
                SpeedUp(); // 鞋子类型的物品增加玩家速度
                break;
        }
    }

    void RateUp()
    {
        Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>(); // 获取所有子物体中的武器组件
        foreach (Weapon weapon in weapons)
        {
            switch (weapon.id)
            {
                case 0:
                    weapon.speed = 150 * (1.0f + rate); // 增加150%速度
                    break;
                default:
                    weapon.speed = 0.5f * (1.0f + rate); // 增加50%速度
                    break;
            }
        }
    }

    void SpeedUp()
    {
        float speed = 3.0f; // 默认玩家速度
        GameManager.instance.player.speed = speed * (1.0f + rate); // 根据rate调整玩家速度
    }
}

修改Item

public Gear gear;

// 如果是手套/鞋子
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
    // 这里可以添加处理手套/鞋子的逻辑
    if (level == 0)
    {
        GameObject newGear = new GameObject();
        gear = newGear.AddComponent<Gear>();
        gear.Init(data);
    }
    else
    {
        float nextRate = data.damages[level];
        gear.LevelUp(nextRate);
    }
    break;

运行效果,点击手套和鞋子buff在人物会生成对应属性,且人物增加攻速和移速效果
在这里插入图片描述

治疗物品效果

修改Item

// 如果是治疗物品
case ItemData.ItemType.Heal:
    // 这里可以添加处理治疗物品的逻辑
    GameManager.instance.health = GameManager.instance.maxHealth;
    break;

双手放置武器

在这里插入图片描述

控制武器移动转向排序

新增Hand,控制左右手翻转位置,具体的位置数据可以自己按情况修改

public class Hand : MonoBehaviour
{
    public bool isLeft; // 是否是左手
    public SpriteRenderer spriter; // 手的sprite renderer组件
    SpriteRenderer player; // 玩家的sprite renderer组件
    Quaternion rightRot = Quaternion.Euler(0, 0, -25);
    Quaternion rightRotReverse = Quaternion.Euler(0, 0, 25);

    Vector3 leftPos = new Vector3(0.4f, -0.2f, 0);
    Vector3 leftPosReverse = new Vector3(0.1f, -0.2f, 0);

    void Awake()
    {
        player = GetComponentsInParent<SpriteRenderer>()[1]; // 获取玩家的sprite renderer组件
    }

    void LateUpdate()
    {
        bool isReverse = player.flipX; // 判断玩家是否水平翻转

        if (isLeft)
        {
            // 处理左手
            spriter.flipX = isReverse; 
            spriter.sortingOrder = isReverse ? 6 : 4;
            transform.localPosition = !isReverse ? leftPos : leftPosReverse;
        }
        else
        {
            // 处理右手
            transform.localRotation = isReverse ? rightRotReverse : rightRot;
            spriter.flipX = isReverse;
            spriter.sortingOrder = isReverse ? 4 : 6;
        }
    }
}

左右手挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

默认先隐藏武器,去除默认的武器精灵图片

在这里插入图片描述

修改ItemData

public Sprite hand;

物品数据,绑定对应的武器精灵图片数据
在这里插入图片描述

在这里插入图片描述

数据联动

修改Player

public Hand[] hands;

hands = GetComponentsInChildren<Hand>();

修改Weapon

public void Init(ItemData data)
{
    //。。。
    
    Hand hand = player.hands[(int)data.itemType];
    hand.spriter.sprite = data.hand;
}

效果,现在开启不同的能力,会在左右手绑定对应的武器
在这里插入图片描述

完善升级界面

绘制升级UI
在这里插入图片描述
配置道具物品描述
在这里插入图片描述

修改Item,注意删除了原来的lateupdate方法

TextMeshProUGUI textName;
TextMeshProUGUI textDesc;

void Awake()
{
    // 。。。
    textLevel = texts[0];
    textName = texts[1];
    textDesc = texts[2];
    textName.text = data.itemName;
}

void OnEnable()
{
    textLevel.text = "Lv." + (level + 1);
    switch (data.itemType)
    {
        case ItemData.ItemType.Melee:
        case ItemData.ItemType.Range:
            textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100, data.counts[level]);
            break;
        case ItemData.ItemType.Glove:
        case ItemData.ItemType.Shoe:
            textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100);
            break;
        default:
            textDesc.text = string.Format(data.itemDesc);
            break;
    }
}

和之前一样挂载,配置参数
在这里插入图片描述

运行效果
在这里插入图片描述

控制窗口开启关闭

新增LevelUp代码

public class LevelUp : MonoBehaviour
{
    RectTransform rect; // 用于存储RectTransform组件的引用

    void Awake()
    {
        rect = GetComponent<RectTransform>(); // 获取LevelUp对象上的RectTransform组件
    }

    /// <summary>
    /// 显示LevelUp界面
    /// </summary>
    public void Show()
    {
        rect.localScale = Vector3.one; // 将界面的缩放设置为(1, 1, 1),即正常大小
    }

    /// <summary>
    /// 隐藏LevelUp界面
    /// </summary>
    public void Hide()
    {
        rect.localScale = Vector3.zero; // 将界面的缩放设置为(0, 0, 0),即隐藏界面
    }
}

配置点击事件

在这里插入图片描述
修改GameManager,人物升级开启面板

public LevelUp uiLevelUp;

//加经验和升级
public void GetExp(){
    exp++;
    if(exp == nextExp[level]){
        level ++;
        exp = 0;
        uiLevelUp.Show();
    }
}

修改LevelUp,默认给主角一个武器

Item[] items;

items = GetComponentsInChildren<Item>(true);

public void Select(int index){
    items[index].OnClick();
}

修改GameManager

private void Start() {
    //...
    uiLevelUp.Select(0);
}

效果
在这里插入图片描述

时间控制,升级暂停游戏

我们希望升级进行属性选择时,可以暂停游戏

修改GameManager

public bool isLive;

public void Stop()
{
    isLive = false;
    Time.timeScale = 0;
}
public void Resume()
{
    isLive = true;
    Time.timeScale = 1;
}

修改LevelUp

public void Show()
{
   rect.localScale = Vector3.one;
   GameManager.instance.Stop();
}
public void Hide()
{
   rect.localScale = Vector3.zero;
   GameManager.instance.Resume();
}

效果
在这里插入图片描述

每次升级随机获取属性项目

修改levelUp

public void Show()
{
    Next();
    //。。。
}

void Next()
{
    // 1. 隐藏所有物品
    foreach (Item item in items)
    {
        item.gameObject.SetActive(false);
    }

    // 2. 随机选择三个不同的索引
    int[] ran = new int[3];
    while (true)
    {
        ran[0] = Random.Range(0, items.Length);
        ran[1] = Random.Range(0, items.Length);
        ran[2] = Random.Range(0, items.Length);

        if (ran[0] != ran[1] && ran[1] != ran[2] && ran[0] != ran[2])
        {
            break;
        }
    }

    // 3. 根据随机索引显示对应的物品
    for (int index = 0; index < ran.Length; index++)
    {
        Item ranItem = items[ran[index]];

        if (ranItem.level == ranItem.data.damages.Length)
        {
        	//保留最后恢复生命效果
            items[4].gameObject.SetActive(true);
        }
        else
        {
            ranItem.gameObject.SetActive(true);
        }
    }
}

效果
在这里插入图片描述

控制等级上限

修改GameManager

//加经验和升级
public void GetExp()
{
    exp++;
    if (exp == nextExp[Mathf.Min(level, nextExp.Length -1)])
    {
        level++;
        exp = 0;
        uiLevelUp.Show();
    }
}

修改HUD

case InfoType.Exp:
   // 处理经验信息逻辑
   float curExp = GameManager.instance.exp;
   float maxExp = GameManager.instance.nextExp[Mathf.Min(GameManager.instance.level, GameManager.instance.nextExp.Length - 1)];
   mySlider.value = curExp / maxExp;
   break;

为了方便测试,可以把升级经验设置少点
在这里插入图片描述

效果
在这里插入图片描述

参考

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

源码

源码在最后一节

完结

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

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

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

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

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

相关文章

2023/11/24JAVAweb学习(Vue常用指令,Vue.js文件,Ajax,Axios两种请求,Vue-cli脚手架,Vue项目,Element)

age只会执行成立的,show其实都展示了,通过display不展示 使用Vue,必须引入Vue.js文件 假如运行报错,以管理员身份打开vscode,再运行 ------------------------------------------------------------------- 更改端口号

如何有效避免七个常见的身份验证漏洞

引言 随着网络威胁的数量不断增加&#xff0c;了解学习可能会危及到客户在线身份的常见身份验证漏洞就显得格外重要。如果需要在网上满足客户的需求&#xff0c;并使用传统的身份验证机制时&#xff0c;就要对身份验证漏洞保持警惕。 只有了解了这些漏洞&#xff0c;才可以更…

如何配置mybatis中mapper对应关系,解决mybatis报错:Invalid bound statement (not found):

先看一下报错信息&#xff1a; Invalid bound statement&#xff1a;意思是无效的绑定语句 原因就是&#xff1a;在使用mybatis时mapper.xml没有和mapper接口对应起来 解决方式 第一种&#xff1a; 将mapper.xml和mapper接口放在同一位置 在pom中配置&#xff1a; <reso…

C# WPF上位机开发(抽奖程序)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 每到年末或者是尾牙的时候&#xff0c;很多公司都会办一些年终的清楚活动&#xff0c;感谢员工过去一年辛苦的付出。这个时候&#xff0c;作为年会…

专访|OpenTiny 开源社区 常浩:完成比完美更重要

前言 2023年已过大半&#xff0c;备受关注的 OpenTiny*开源之夏活动也顺利结项。开源之夏由中国科学院软件研究所发起的计划&#xff0c;目的在于鼓励在校学生积极参与开源软件的开发维护&#xff0c;推动优秀开源软件社区的繁荣发展。该活动联合各大开源社区&#xff0c;聚焦…

五要素超声波气象站-气象站小百科

随着科技的发展&#xff0c;人们对气象监测的需求也越来越高。为了满足这一需求&#xff0c;一款全新的五要素超声波气象站应运而生。这款气象站不仅具有高精度的测量能力&#xff0c;而且能够实时监测天气变化&#xff0c;为人们提供准确的气象数据。 一、实时监测&#xff0…

【数值计算方法(黄明游)】矩阵特征值与特征向量的计算(三):Jacobi 旋转法【理论到程序】

文章目录 一、Jacobi 旋转法1. 基本思想2. 计算过程演示 二、Python实现迭代过程&#xff08;调试&#xff09; 矩阵的特征值&#xff08;eigenvalue&#xff09;和特征向量&#xff08;eigenvector&#xff09;在很多应用中都具有重要的数学和物理意义。Jacobi 旋转法是一种用…

华为云之云桌面Workspace的使用体验

华为云之云桌面Workspace的使用体验 一、云桌面Workspace介绍1.云桌面简介2.云桌面特点3. 云桌面应用场景①远程移动办公②协同办公③安全办公④公用终端⑤图形制作渲染 二、本次实践介绍1. 本次实践目的2. 本次实践环境 三、购买云桌面1. 进入华为云的云桌面购买界面2. 选择购…

智能优化算法应用:基于生物地理学算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于生物地理学算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于生物地理学算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.生物地理学算法4.实验参数设定5.算法结果…

【蓝桥杯选拔赛真题70】Scratch输入输出数字 少儿编程scratch图形化编程 蓝桥杯创意编程选拔赛真题解析

目录 scratch输入输出数字 一、题目要求 编程实现 二、案例分析 1、角色分析

文件夹重命名技巧:用关键词替换文件夹名称指定内容的右侧文字

在日常生活中&#xff0c;经常要管理大量的文件夹&#xff0c;这时候掌握一些文件夹重命名的技巧就非常实用。例如文件夹重命名时&#xff0c;经常要将一些通用的文字替换成其他关键词&#xff0c;以便更好地标识和分类文件夹。而用关键词替换文件夹名称指定内容的右侧文字&…

智能优化算法应用:基于纵横交叉算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于纵横交叉算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于纵横交叉算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.纵横交叉算法4.实验参数设定5.算法结果6.参考…

亚马逊云科技re:Invent Peter DeSantis演讲,数据规模拓展无极限引领Serverless构建之路

re:lnvent 2023 Peter DeSantis主题演讲&#xff0c;数据规模拓展无极限引领Serverless构建之路&#xff08;Road to Serverless&#xff09;。 Logical Qubit全新发布&#xff1a;量子计算硬件&#xff0c;6倍的量子纠错效率提升。 Amazon全新发布Redshift Serverless&#xf…

RedisTemplate中使用scan方法代替keys指令

keys * 这个命令千万别在生产环境乱用&#xff0c;危险级别不亚于flushdb。因为Redis是单线程操作&#xff0c;在数据特别庞大的情况下。Keys会引发Redis锁&#xff08;数据过多一直查询处理&#xff09;&#xff0c;并且增加Redis的CPU占用。很多公司的运维都是禁止了这个命令…

Python实现FA萤火虫优化算法优化循环神经网络回归模型(LSTM回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , …

狗都会配的SNAT和DNAT配置

1 SNAT 1.1 SNAT SNAT原理与应用:. SNAT 应用环境:局域网主机共享单个公网IP地址接入Internet (私有IP不能在Internet中正常路由) SNAT原理:源地址转换&#xff0c;根据指定条件修改数据包的源IP地址&#xff0c;通常被叫做源映谢 SNAT转换前提条件: 1.局域网各主机已正确设…

13-Vue基础之自定义指令与插槽的使用

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Apipost推出IDEA插件,代码写完直接调试

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…

mysql 日志分析

程序启动标志 可以直接全局搜索&#xff0c;查看启动了几次 可以看到总共11次&#xff0c;当前是第2次 如何判断mysql是正常关闭&#xff0c;手动启动的 下图中启动之前出现 Shutdown complete打印说明启动之前是正常关闭的

2024 本田 CBR1000RR-R Fireblade SP

本田在米兰车展期间也发布了自家的旗舰仿赛&#xff0c;虽然不是重大改款&#xff0c;只是更新一些内容&#xff0c;性能方面有所小提升&#xff0c;但是毕竟人家是本田&#xff0c;毕竟人家是火刃&#xff0c;还是要尊重一下&#xff0c;写一篇内容的。 新款还是有一些亮点&am…