Unity C#农场游戏等级系统问题:无法限制指定等级种植作物
Unity农场游戏「等级限制作物种植」功能修复
我正在使用Unity开发一款农场游戏,已实现EXP系统,但无法完成「达到指定玩家等级才可种植对应作物」的功能。尝试修改代码后,不仅未禁用未达等级的作物按钮,还出现大量错误,卡壳数周,寻求解决方案。
原代码
管理农场的FarmManager脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class FarmManager : MonoBehaviour { [Header("Money Settings")] public PlantItem selectPlant; public bool isPlanting = false; public int money = 100; public Text moneyTxt; [Header("Button Color Settings")] public Color buyColor = Color.green; public Color cancelColor = Color.red; public Color lockedColor = Color.grey; [Header("Button Audio Settings")] public AudioSource clickSound; [Header("Cursor Settings")] public Texture2D cursorArrow; public Texture2D cursorPickaxe; [Header("XP Settings")] public int maxExp; public float updatedExp; public float plusXp; public Image ExpBar; public float expIncreasedPerSecond; public int playerLevel; public Text levelText; public Text xpLevel; // Start is called before the first frame update void Start() { Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware); moneyTxt.text = "$"+money; playerLevel =1; expIncreasedPerSecond =5f; maxExp = 25; updatedExp = 0; plusXp = 0; } void Update () { //updatedExp += expIncreasedPerSecond * Time.deltaTime; ExpBar.fillAmount = updatedExp / maxExp; levelText.text = playerLevel + ""; xpLevel.text = updatedExp + "/" + maxExp; if (updatedExp >= maxExp) { plusXp = updatedExp-maxExp; playerLevel++; updatedExp=0+plusXp; maxExp+=maxExp; } } public void SelectPlant(PlantItem newPlant) { if(selectPlant == newPlant) { Debug.Log("Deselected" + selectPlant.plant.plantName); selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; selectPlant = null; isPlanting = false; clickSound.Play(); } else { if(selectPlant!=null) { selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; } selectPlant = newPlant; selectPlant.btnImage.color = cancelColor; selectPlant.btnTxt.text = "Cancel"; Debug.Log("Selected" + selectPlant.plant.plantName); isPlanting = true; clickSound.Play(); } } public void Transaction(int value) { money+=value; moneyTxt.text = "$"+money; } public void GiveXP (float value) { updatedExp += value; } }
作物信息PlantObject可编辑对象代码
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "New Plant", menuName ="Plant")] public class PlantObject : ScriptableObject { [Header("Plant settings")] public string plantName; public Sprite[] plantStages; public float timeBtwStages; [Header("Money Settings")] public int buyPrice; public int sellPrice; [Header("XP Settings")] public int xpAmount; public int levelNeeded; [Header("Plant Icon")] public Sprite icon; }
尝试修改后的错误代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class FarmManager : MonoBehaviour { [Header("Money Settings")] public PlantItem selectPlant; public bool isPlanting = false; public int money = 100; public Text moneyTxt; [Header("Button Color Settings")] public Color buyColor = Color.green; public Color cancelColor = Color.red; public Color lockedColor = Color.grey; [Header("Button Audio Settings")] public AudioSource clickSound; [Header("Cursor Settings")] public Texture2D cursorArrow; public Texture2D cursorPickaxe; [Header("XP Settings")] public int maxExp; public float updatedExp; public float plusXp; public Image ExpBar; public float expIncreasedPerSecond; public int playerLevel; public Text levelText; public Text xpLevel; // Start is called before the first frame update void Start() { Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware); moneyTxt.text = "$"+money; playerLevel =1; expIncreasedPerSecond =5f; maxExp = 25; updatedExp = 0; plusXp = 0; } void Update () { //updatedExp += expIncreasedPerSecond * Time.deltaTime; ExpBar.fillAmount = updatedExp / maxExp; levelText.text = playerLevel + ""; xpLevel.text = updatedExp + "/" + maxExp; if (updatedExp >= maxExp) { plusXp = updatedExp-maxExp; playerLevel++; updatedExp=0+plusXp; maxExp+=maxExp; } } public void SelectPlant(PlantItem newPlant) { if(selectPlant == newPlant) { Debug.Log("Deselected" + selectPlant.plant.plantName); selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; selectPlant = null; isPlanting = false; clickSound.Play(); } else { if(selectPlant!=null) { selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; } selectPlant = newPlant; selectPlant.btnImage.color = cancelColor; selectPlant.btnTxt.text = "Cancel"; Debug.Log("Selected" + selectPlant.plant.plantName); isPlanting = true; clickSound.Play(); } if (selectPlant.plant.levelNeeded > playerLevel) { selectPlant.btnImage.color = lockedColor; } } public void Transaction(int value) { money+=value; moneyTxt.text = "$"+money; } public void GiveXP (float value) { updatedExp += value; } }
问题分析与修复方案
核心问题
- 空引用错误:取消选择作物后
selectPlant为null,此时访问selectPlant.plant.levelNeeded会触发空引用异常。 - 未初始化按钮状态:游戏启动时未根据初始等级设置作物按钮锁定状态,未达等级的按钮仍显示可点击。
- 等级提升后未更新按钮:玩家升级后,未自动解锁对应等级的作物按钮。
- 锁定作物仍可被选择:点击未达等级的作物按钮时,仍会执行选择逻辑,没有拦截。
修复后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class FarmManager : MonoBehaviour { [Header("Money Settings")] public PlantItem selectPlant; public bool isPlanting = false; public int money = 100; public Text moneyTxt; [Header("Button Color Settings")] public Color buyColor = Color.green; public Color cancelColor = Color.red; public Color lockedColor = Color.grey; [Header("Button Audio Settings")] public AudioSource clickSound; [Header("Cursor Settings")] public Texture2D cursorArrow; public Texture2D cursorPickaxe; [Header("XP Settings")] public int maxExp; public float updatedExp; public float plusXp; public Image ExpBar; public float expIncreasedPerSecond; public int playerLevel; public Text levelText; public Text xpLevel; // 存储所有作物按钮的列表,需在Inspector中赋值 public List<PlantItem> allPlantItems; // Start is called before the first frame update void Start() { Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware); moneyTxt.text = "$"+money; playerLevel =1; expIncreasedPerSecond =5f; maxExp = 25; updatedExp = 0; plusXp = 0; // 初始化所有作物按钮状态 UpdatePlantButtonStates(); } void Update () { //updatedExp += expIncreasedPerSecond * Time.deltaTime; ExpBar.fillAmount = updatedExp / maxExp; levelText.text = playerLevel + ""; xpLevel.text = updatedExp + "/" + maxExp; if (updatedExp >= maxExp) { plusXp = updatedExp-maxExp; playerLevel++; updatedExp=0+plusXp; maxExp+=maxExp; // 升级后更新所有作物按钮状态 UpdatePlantButtonStates(); } } public void SelectPlant(PlantItem newPlant) { // 先判断当前作物是否锁定 if (newPlant.plant.levelNeeded > playerLevel) { Debug.Log("等级不足,无法种植" + newPlant.plant.plantName); newPlant.btnImage.color = lockedColor; newPlant.btnTxt.text = "锁定"; return; // 直接返回,不执行选择逻辑 } if(selectPlant == newPlant) { Debug.Log("Deselected" + selectPlant.plant.plantName); selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; selectPlant = null; isPlanting = false; clickSound.Play(); } else { if(selectPlant!=null) { selectPlant.btnImage.color = buyColor; selectPlant.btnTxt.text = "Buy"; } selectPlant = newPlant; selectPlant.btnImage.color = cancelColor; selectPlant.btnTxt.text = "Cancel"; Debug.Log("Selected" + selectPlant.plant.plantName); isPlanting = true; clickSound.Play(); } } // 更新所有作物按钮的锁定/可用状态 private void UpdatePlantButtonStates() { foreach (var plantItem in allPlantItems) { if (plantItem.plant.levelNeeded > playerLevel) { plantItem.btnImage.color = lockedColor; plantItem.btnTxt.text = "锁定"; plantItem.GetComponent<Button>().interactable = false; // 禁用按钮点击 } else { plantItem.btnImage.color = buyColor; plantItem.btnTxt.text = "Buy"; plantItem.GetComponent<Button>().interactable = true; // 启用按钮点击 } } } public void Transaction(int value) { money+=value; moneyTxt.text = "$"+money; } public void GiveXP (float value) { updatedExp += value; } }
关键修改点说明
- 新增
allPlantItems列表:在Inspector中把所有作物按钮的PlantItem组件拖入列表,方便批量更新状态。 - 初始化与升级时更新按钮:在
Start和玩家升级时调用UpdatePlantButtonStates,确保按钮状态与当前等级匹配。 - 拦截锁定作物的点击:在
SelectPlant开头先判断等级,不足则直接返回,不执行选择逻辑,并设置按钮为锁定状态。 - 禁用锁定按钮的交互:在
UpdatePlantButtonStates中设置按钮的interactable属性,彻底禁止未达等级按钮的点击事件。
额外注意事项
- 确保
PlantItem类包含btnImage、btnTxt和plant(引用PlantObject)的公共字段,否则代码会报错。 - 在Inspector中正确赋值
allPlantItems列表,把所有作物按钮对应的PlantItem组件添加进去。
内容的提问来源于stack exchange,提问作者Fl4shÝ
相关产品推荐
相关产品推荐

