文章目录
- 先看本次实现的最终效果
- 前言
- 把敌人和炮塔全部配置成预制体
- 炮塔商店
- 打开商店
- 放置炮塔
- 升级炮塔
- 出售
- 显示炮塔攻击范围
- 显示玩家金额和血量
- 关闭升级面板和商店功能
- 源码
- 完结
先看本次实现的最终效果
前言
本期紧接着上一篇,本期主要内容是实现商店、购买、出售、升级等功能。
把敌人和炮塔全部配置成预制体
炮塔商店
新增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。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~