先看本次实现的最终效果
前言
本期紧接着上一篇,本期主要内容是实现商店、购买、出售、升级等功能。
把敌人和炮塔全部配置成预制体
炮塔商店
新增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); }
配置
效果
关闭商店