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

文章目录

  • 先看本次实现的最终效果
  • 前言
  • 把敌人和炮塔全部配置成预制体
  • 炮塔商店
  • 打开商店
  • 放置炮塔
  • 升级炮塔
  • 出售
  • 显示炮塔攻击范围
  • 显示玩家金额和血量
  • 关闭升级面板和商店功能
  • 源码
  • 完结

先看本次实现的最终效果

在这里插入图片描述

前言

本期紧接着上一篇,本期主要内容是实现商店、购买、出售、升级等功能。

把敌人和炮塔全部配置成预制体

在这里插入图片描述

炮塔商店

新增TurretSettings

[CreateAssetMenu(fileName = "炮塔商店设置", menuName = "数据/炮塔商店设置")]
public class TurretSettings : ScriptableObject
{
    [SerializeField]
    public GameObject turretPrefab; // 炮塔预制体
    [SerializeField]
    public int turretShopCost; // 炮塔商店价格
    [SerializeField]
    public Sprite turretShopSprite; // 炮塔商店显示的图标
}

配置不同炮塔参数
在这里插入图片描述

绘制商店UI
在这里插入图片描述

新增TurretCard,渲染商品数据,如果前面有绘制价格文本,还可以渲染价格文本,这里我就偷懒不弄了

public class TurretCard : MonoBehaviour
{
    [SerializeField]
    private Image turretImage; // 炮塔图片
    [SerializeField]
    // private TextMeshProUGUI turretCost; // 炮塔价格文本

    public void SetupTurretButton(TurretSettings turretSettings)
    {
        turretImage.sprite = turretSettings.turretShopSprite; // 设置炮塔图片
        // turretCost.text = turretSettings.turretShopCost.ToString(); // 设置炮塔价格文本
    }
}

挂载脚本,并配置

在这里插入图片描述

新增TurretShopManager,商店管理器

public class TurretShopManager : MonoBehaviour
{
    [SerializeField]
    private GameObject turretCardPrefab; // 炮塔卡片预制体
    [SerializeField]
    private Transform turretPanelContainer; // 放置炮塔卡片的容器

    [Header("炮塔商店配置")]
    [SerializeField]
    private TurretSettings[] turrets; // 可用炮塔设置数组

    private void Start()
    {
        // 在开始时生成炮塔卡片
        for (int i = 0; i < turrets.Length; i++)
        {
            CreateTurretCard(turrets[i]);
        }
    }

    private void CreateTurretCard(TurretSettings turretSettings)
    {
        // 创建炮塔卡片实例
        GameObject newInstance = Instantiate(turretCardPrefab, turretPanelContainer);
        // 设置炮塔卡片实例的比例为默认值
        newInstance.transform.localScale = Vector3.one;
        // 获取炮塔卡片组件,并设置炮塔信息
        TurretCard cardButton = newInstance.GetComponent<TurretCard>();
        cardButton.SetupTurretButton(turretSettings);
    }
}

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

效果
在这里插入图片描述

打开商店

新增Node ,放置节点

public class Node : MonoBehaviour
{
    public static Action<Node> OnNodeSelected; // 当节点被选中时的事件

    public Turret Turret { get; set; } // 节点上的炮塔

    public void SetTurret(Turret turret)
    {
        Turret = turret; // 设置节点上的炮塔
    }

    public bool IsEmpty()
    {
        return Turret == null; // 判断节点是否为空(没有炮塔)
    }

    public void SelectTurret()
    {
        OnNodeSelected?.Invoke(this); // 触发节点被选中事件
    }
}

挂载并配置点击事件
在这里插入图片描述

新增UI管理器

public class UIManager : MonoBehaviour
{
    [SerializeField, Header("炮塔商店面板")]
    private GameObject turretShopPanel;

    private Node _currentNodeSelected; // 当前选中的节点

    private void NodeSelected(Node nodeSelected)
    {
        _currentNodeSelected = nodeSelected; // 更新当前选中的节点

        if (_currentNodeSelected.IsEmpty())
        {
            turretShopPanel.SetActive(true); // 显示炮塔商店面板
        }
    }

    private void OnEnable()
    {
        Node.OnNodeSelected += NodeSelected; // 注册节点被选中事件的回调方法
    }

    private void OnDisable()
    {
        Node.OnNodeSelected -= NodeSelected; // 取消注册节点被选中事件的回调方法
    }
}

挂载并配置参数
在这里插入图片描述
效果,点击打开商店
在这里插入图片描述

放置炮塔

修改TurretCard

public static Action<TurretSettings> OnPlaceTurret;// 放置炮塔时的事件
public TurretSettings TurretLoaded { get; set; }// 载入的炮塔设置信息

TurretLoaded = turretSettings;

// 放置炮塔的方法
public void PlaceTurret()
{
	// 检查玩家金币是否足够购买炮塔
    if (CurrencySystem.Instance.TotalCoins >= TurretLoaded.turretShopCost)
    {
    	// 扣除对应金币
        CurrencySystem.Instance.RemoveCoins(TurretLoaded.turretShopCost);
        UIManager.Instance.CloseTurretShopPanel();
        // 触发放置炮塔事件,传递炮塔设置信息
        OnPlaceTurret?.Invoke(TurretLoaded);
    }
}

修改UIManager

public void CloseTurretShopPanel()
{
    turretShopPanel.SetActive(false);
}

修改TurretShopManager

private Node _currentNodeSelected;// 当前选中的节点

// 当节点被选中时的回调方法
private void NodeSelected(Node nodeSelected)
{
    _currentNodeSelected = nodeSelected;
}

// 放置炮塔的方法,接受传入的炮塔设置信息
private void PlaceTurret(TurretSettings turretLoaded)
{
    if (_currentNodeSelected != null)
    {
        GameObject turretInstance = Instantiate(turretLoaded.turretPrefab);
        turretInstance.transform.localPosition = _currentNodeSelected.transform.position;
        turretInstance.transform.parent = _currentNodeSelected.transform;
        Turret turretPlaced = turretInstance.GetComponent<Turret>();
        // 在当前节点上设置放置的炮塔
        _currentNodeSelected.SetTurret(turretPlaced);
    }
}

private void OnEnable()
{
    Node.OnNodeSelected += NodeSelected;
    TurretCard.OnPlaceTurret += PlaceTurret;
}

private void OnDisable()
{
    Node.OnNodeSelected -= NodeSelected;
    TurretCard.OnPlaceTurret -= PlaceTurret;
}

配置点击事件
在这里插入图片描述
效果
在这里插入图片描述

升级炮塔

绘制升级UI面板
在这里插入图片描述

修改UIManager,开启升级面板

[SerializeField] private GameObject nodeUIPanel;
[SerializeField] private TextMeshProUGUI upgradeText;
[SerializeField] private TextMeshProUGUI sellText;

private void ShowNodeUI()
{
    nodeUIPanel.SetActive(true);
}

private void NodeSelected(Node nodeSelected)
{
    _currentNodeSelected = nodeSelected; // 更新当前选中的节点

    if (_currentNodeSelected.IsEmpty())
    {
        //。。。
    }
    else
    {
        ShowNodeUI();
    }
}

配置
在这里插入图片描述

修改Turret

public TurretUpgrade TurretUpgrade {get;set;}

TurretUpgrade = GetComponent<TurretUpgrade>();

修改UIManager

private void ShowNodeUI()
{
    nodeUIPanel.SetActive(true);
    UpdateUpgradeText();
}

//升级
public void UpgradeTurret()
{
    _currentNodeSelected.Turret.TurretUpgrade.UpgradeTurret();
    UpdateUpgradeText();
}

private void UpdateUpgradeText()
{
    upgradeText.text = _currentNodeSelected.Turret.TurretUpgrade.UpgradeCost.ToString();
}

配置点击事件
在这里插入图片描述
显示等级
修改TurretUpgrade

public int Level { get; set; }

Level = 1;

private void UpdateUpgrade()
{
    CurrencySystem.Instance.RemoveCoins(UpgradeCost);//扣除金额
    UpgradeCost += upgradeCostIncremental;//加下次升级金额
    Level++;
}

修改UIManager

[SerializeField]private TextMeshProUGUI turretLevelText;

private void ShowNodeUI()
{
    //。。。
    UpdateTurretLevel();
}

//升级
public void UpgradeTurret()
{
    //。。。
    UpdateTurretLevel();
}

private void UpdateTurretLevel(){
    turretLevelText.text = $"等级 {_currentNodeSelected.Turret.TurretUpgrade.Level}";
}

配置等级文本参数
在这里插入图片描述
效果
在这里插入图片描述

出售

修改TurretUpgrade

[Header("出售折扣")]
[Range(0, 1)]
[SerializeField] private float sellPert;
public float SellPerc { get; set; }

SellPerc = sellPert;

//计算出售价格
public int GetSellValue()
{
    int sellValue = Mathf.RoundToInt(UpgradeCost * SellPerc);
    return sellValue;
}

修改UIManager

private void ShowNodeUI()
{
    //。。。
    UpdateSellValue();
}

//升级
public void UpgradeTurret()
{
    //。。。
    UpdateSellValue();
}

private void UpdateSellValue()
{
    int sellAmount = _currentNodeSelected.Turret.TurretUpgrade.GetSellValue();
    sellText.text = sellAmount.ToString();
}

//出售
public void SellTurret()
{
    _currentNodeSelected.SellTurret();
    _currentNodeSelected = null;
    nodeUIPanel.SetActive(false);
}

修改Node

public static Action OnTurretSold;

public void SellTurret()
{
    if (!IsEmpty())
    {
        CurrencySystem.Instance.AddCoins(Turret.TurretUpgrade.GetSellValue());
        Destroy(Turret.gameObject);
        Turret = null;
        OnTurretSold?.Invoke();
    }
}

修改TurretShopManager

private void TurretSold()
{
    _currentNodeSelected = null;
}

private void OnEnable()
{
    Node.OnNodeSelected += NodeSelected;
    TurretCard.OnPlaceTurret += PlaceTurret;
    Node.OnTurretSold += TurretSold;
}

private void OnDisable()
{
    Node.OnNodeSelected -= NodeSelected;
    TurretCard.OnPlaceTurret -= PlaceTurret;
    Node.OnTurretSold -= TurretSold;
}

配置出售点击事件
在这里插入图片描述
配置各个炮塔的出售折扣,比如这里我配置0.5,则只能卖一半的钱
在这里插入图片描述
效果
在这里插入图片描述

显示炮塔攻击范围

修改Node

[SerializeField] private GameObject attackRangeSprite;//攻击范围显示
private float _rangesize;
private Vector3 _rangeOriginalsize;

private void Start()
{
    _rangesize = attackRangeSprite.GetComponent<SpriteRenderer>().bounds.size.y;
    _rangeOriginalsize = attackRangeSprite.transform.localScale;
}

private void ShowTurretInfo()
{
    attackRangeSprite.SetActive(true);
    attackRangeSprite.transform.localScale = _rangeOriginalsize * Turret.attackRange / (_rangesize / 2);
}

public void SelectTurret()
{
    OnNodeSelected?.Invoke(this); // 触发节点被选中事件
    if (!IsEmpty())
    {
        ShowTurretInfo();
    }
}

public void SellTurret()
{
    if (!IsEmpty())
    {
        //。。。
        attackRangeSprite.SetActive(false);
    }
}

配置参数
在这里插入图片描述
效果
在这里插入图片描述

显示玩家金额和血量

修改UIManager

[SerializeField] private TextMeshProUGUI totalCoinsText;
[SerializeField] private TextMeshProUGUI lifesText;
private void Update()
{
    totalCoinsText.text = "金币:" + CurrencySystem.Instance.TotalCoins.ToString();
    lifesText.text = "生命:" + LevelManager.Instance.TotalLives.ToString();
}

配置
在这里插入图片描述
效果
在这里插入图片描述

关闭升级面板和商店功能

修改Node

public void CloseAttackRangeSprite(){
	attackRangeSprite.SetActive(false);
}

修改UIManager

public void CloseNodeUIPanel(){
	currentNodeSelected.CloseAttackRangeSprite();
	nodeUIPanel.SetActive(false);
}

配置
在这里插入图片描述

效果
在这里插入图片描述

关闭商店
在这里插入图片描述

在这里插入图片描述

源码

见本项目最后一节

完结

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

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

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

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

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

相关文章

Python学习笔记--自定义元类

四、自定义元类 到现在&#xff0c;我们已经知道元类是什么鬼东西了。 那么&#xff0c;从始至终我们还不知道元类到底有啥用。 只是了解了一下元类。 在了解它有啥用的时候&#xff0c;我们先来了解下怎么自定义元类。 因为只有了解了怎么自定义才能更好的理解它的作用。…

《向量数据库指南》——2023云栖大会现场,向量数据库Milvus Cloud成关注焦点

近期,广受关注的2023 云栖大会正式收官,来自全球各地的开发者集聚一堂,共同探索 AI 时代的更多可能性。 云栖大会是由阿里巴巴集团主办的科技盛宴,是中国最早的开发者创新展示平台。据悉,今年云栖大会的主题为“计算,为了无法计算的价值”,共吸引了全球 44 个国家和地区…

【MySQL8】1130 - Host *** is not allowed to connect to this MySOL server

问题描述 使用 Navicat 连接 MySQL8 报错&#xff1a; 1130 - Host *** is not allowed to connect to this MySOL server解决方案 use mysql;select host ,user from user; -- 将 root 用户的主机&#xff08;host&#xff09;值修改为 %&#xff0c;即允许从任何主机连接 …

进阶JAVA篇- Lambda 表达式与 Lambda 表达式的省略规则

目录 1.0 什么是 Lambda 表达式&#xff1f; 1.1 既然跟匿名内部类相关&#xff0c;先来回顾匿名内部类。 1.2 Lambda 表达式与匿名内部类之间的关系。 1.3 函数式接口 1.4 在具体代码中来操作一下 2.0 Lambda 表达式省略规则 1.0 什么是 Lambda 表达式&#xff1f; Lambda 表达…

SQL server从安装到入门(一)

文章目录 彻底安装怎么安装&#xff1f;Polybase要求安装orcale jre 7更新 51或更高版本&#xff1f;安装完怎么配置&#xff1f;没有SSMS&#xff1f; 熟悉一下SMSS&#xff01; 根据本人实际安装和初步使用SQL server的过程中&#xff0c;经历的一些关键性的步骤和精品文章。…

【volatality 3】使用说明文档

由于volatility2.6 和3.0 版本之间略有差异,所以特写本文档用来学习参考。 在vol3 中不需要指定profile,而是在命令中指定系统。 如windows.info、Windows.pslist 使用示例 文档说明 本文作者:SwBack 创作时间:‎2022‎年‎6‎月‎14‎日&#xff0c;‏‎15:47:05 知乎:https…

OPPO发布AndesGPT大模型;Emu Video和Emu Edit的新突破

&#x1f989; AI新闻 &#x1f680; OPPO发布全新ColorOS 14及自主训练的AndesGPT大模型 摘要&#xff1a;OPPO在2023 OPPO开发者大会上发布了全新的ColorOS 14&#xff0c;并正式推出了自主训练的安第斯大模型&#xff08;AndesGPT&#xff09;。AndesGPT拥有对话增强、个人…

集合贴——智能客服是什么

基础课1——智能客服的定义-CSDN博客文章浏览阅读166次。智能客服是一种采用人工智能技术的客户服务方式&#xff0c;它通过语音识别、自然语言处理、语义理解等技术&#xff0c;实现了与客户的自动交互。https://blog.csdn.net/2202_75469062/article/details/134406392?spm1…

为什么选择CodeEase?

目录 为什么选择CodeEase核心功能后端前端 框架结构总结 为什么选择CodeEase CodeEase是一个标准化的低代码平台 愿景 我们励志开发一站式服务&#xff0c;缩短网站开发周期&#xff0c;降低程序bug率&#xff0c;减少开发人力和成本&#xff0c;推出了多租户SaaS平台开发模板…

unity中的模型坐标系与3dmax导出的模型坐标系不一致的解决方案

unity中的模型坐标系与3dmax导出的模型坐标系不一致的解决方案 unity是左手坐标系&#xff0c;3dmax为右手坐标系 需要在3dmax中修改坐标系 顶视图中改成&#xff1a;X轴&#xff08;红色&#xff09;向右&#xff1a; Y轴&#xff08;蓝色&#xff09;朝向自己: Z轴&#xff…

码住!听我说护眼台灯这样选!

台灯的显色指数是其非常重要的指标&#xff0c;它可以表示灯光照射到物体身上&#xff0c;物体颜色的真实程度&#xff0c;一般用平均显色指数Ra来表示&#xff0c;Ra值越高&#xff0c;灯光显色能力越强。常见的台灯显色指数最低要求一般是在Ra80以上即可&#xff0c;比较好的…

机械人必须要了解的丝杆螺母参数

丝杆螺母是机械中重要的零部件之一&#xff0c;主要用于将旋转运动转化为直线运动&#xff0c;或者将直线运动转化为旋转运动。只有正确了解丝杆螺母的参数&#xff0c;才能进行选型。 1、螺纹规格&#xff1a;丝杆螺母的螺纹规格是按照国家标准进行分类的&#xff0c;常见的有…

CleanMyMac X2024免费苹果笔记本清理内存清理工具

CleanMyMac X的优点包括&#xff1a; 全面的系统清理&#xff1a;CleanMyMac X可以扫描和清理系统中的垃圾文件、缓存文件、无用的语言文件、残留文件等&#xff0c;从而释放磁盘空间&#xff0c;提高系统性能。 优化工具&#xff1a;该软件还提供了一系列优化工具&#xff0c…

Linux下好玩有趣的指令(持续更新)

适用于centOS下&#xff0c;别的Linux换个指令就行&#xff0c;内容是一样的 centOS有的指令安装不了&#xff1f;试试拓展yum源&#xff0c;再安装基本就OK啦&#xff01; yum install -y epel-release 下面是作者在centOS环境下亲测可以使用的&#xff0c;如果你是root用户直…

网络运维Day19

文章目录 环境准备数据备份为什么要备份什么是备份备份到哪里什么时候备份如何备份 完整备份物理备份逻辑备份测试恢复所有库 构建MySQL服务xtrabackup完全备份与恢复完全备份完全恢复增量备份增量恢复 总结 环境准备 IP地址采用自动分配&#xff0c;以自己的为准 可以将之前的…

几种典型的深度学习算法:(CNN、RNN、GANS、RL)

以下是几种典型的深度学习算法&#xff1a; 1、卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;&#xff1a;主要用于图像和视频等视觉任务。通过使用卷积层、池化层和全连接层等不同类型的神经网络层&#xff0c;CNN 可以学习图像中的特征并…

VMware17虚拟机Linux安装教程(详解附图,带VMware Workstation 17 Pro安装)

一、安装 VMware 附官方下载链接&#xff08;VM 17 pro&#xff09;&#xff1a;https://download3.vmware.com/software/WKST-1701-WIN/VMware-workstation-full-17.0.1-21139696.exe 打开下载好的VMware Workstation 17 Pro安装包&#xff1b; 点击下一步&#xff1b; 勾选我…

【微信小程序开发】小程序的事件处理和交互逻辑(最详细)

前言 在微信小程序中&#xff0c;事件处理和交互逻辑是开发过程中非常重要的环节&#xff0c;它们直接影响到用户体验和功能实现。今天为大家继续详解小程序的事件处理和交互逻辑 文章目录 前言为什么要学习事件处理和交互逻辑&#xff1f;事件处理基础事件类型和触发条件事件绑…

轻松搭建个人web站点:OpenWRT教程结合内网穿透技术实现公网远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…