前言
欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第25篇中,我们将探索如何用unity制作一个3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱等功能,我会附带项目源码,以便你更好理解它。
新增简单的泛型单例
我们会有有很多单例,如果每个单例都去写会很麻烦,所以我们定义泛型单例模式 Singleton,我们将所有的单例都继承这个泛型单例,就省略很多重复的工作
//简单的泛型单例 public class Singleton<T> : MonoBehaviour where T : Singleton<T> { private static T instance; public static T Instance { get { if (instance == null) { instance = FindObjectOfType<T>(); if (instance == null) { GameObject obj = new GameObject(typeof(T).Name); instance = obj.AddComponent<T>(); } } return instance; } } public void Awake() { if(instance == null){ instance = this as T; //确保单例对象在场景切换时不会被销毁 DontDestroyOnLoad(gameObject); }else{ Destroy(gameObject); } } }
调用例子:
public class MySingletonClass : Singleton<MySingletonClass> { // 添加自己的方法和属性 }
消耗品
新增玩家健康类控制脚本
public class PlayerHealth : MonoBehaviour { [SerializeField] private int health = 0; // 玩家健康值 [SerializeField] private int food = 0; // 玩家食物值 [SerializeField] private int water = 0; // 玩家水分值 // 增加健康值 public void AddHealth(int addedHealth) { health += addedHealth; } // 增加食物值 public void AddFood(int addedFood) { food += addedFood; } // 增加水分值 public void AddWater(int addedWater) { water += addedWater; } }
因为物品都会配置为预制体,如果我们直接在物品上挂载配置触发的事件,变为预制体后事件配置数据会丢失,所以我们可以新增物品事件管理器类ItemEventManager ,动态的绑定相关事件到对应物品上
// 物品事件管理器类 public class ItemEventManager : Singleton<ItemEventManager> { [SerializeField] private List<ItemReferences> itemReferences = new List<ItemReferences>(); // 物品引用列表 // 获取物品事件 public UnityEvent GetItemEvents(Item item) { ItemReferences itemRef = itemReferences.Find(x => x.item.name == item.name); // 查找物品引用 return (itemRef != null && itemRef.events != null) ? itemRef.events : null; // 返回物品事件,如果为空则返回 null } } // 物品引用类 [System.Serializable] public class ItemReferences { public Item item; // 物品引用 public UnityEvent events; // 物品事件 }
比如我们配置苹果使用可以加人物5饱食度和5水分值
修改Item,绑定对应的事件和使用物品功能
[Header("使用物品")] public bool removeOneOnUse;// 是否是一次性物品 public UnityEvent myEvent;// 使用物品时触发的事件 private void Start() { // 从物品事件管理器中获取该物品对应的物品事件 UnityEvent newEvent = ItemEventManager.Instance.GetItemEvents(this); if (newEvent != null) myEvent = newEvent; } private void OnDisable() { // 如果该物品不在场景中并且其使用物品事件没有任何持续事件,则直接返回 if (!gameObject.scene.isLoaded || myEvent.GetPersistentEventCount() != 0) return; UnityEvent newEvent = ItemEventManager.Instance.GetItemEvents(this); if (newEvent != null) myEvent = newEvent; } //使用物品 public void UseItem() { if (myEvent.GetPersistentEventCount() > 0) { myEvent.Invoke();// 触发使用物品事件 if (removeOneOnUse) currentQuantity--;// 根据设置决定是否减少物品数量 } }
解释:
GetPersistentEventCount 是 Unity 中的方法,用于获取 UnityEvent 中持久化(persistent)事件的数量。在这里,它用于检查一个物品的使用事件中是否包含任何持久化的事件。
Unity 的事件系统允许您在编辑器中将方法绑定到事件,这些绑定在运行时会被称为“持久化”事件。GetPersistentEventCount 方法用于获取 UnityEvent 中已经绑定的持久化事件的数量,以便在代码中进行相应的逻辑处理。
在上述代码中,myEvent.GetPersistentEventCount() 用于检查 myEvent 中是否有持久化事件的绑定。如果事件绑定的数量不为 0,则说明该物品的使用事件已经被设置过,因此在禁用时不需要重新获取事件。
勾选苹果为一次性物品,及消耗品
修改Inventory
public void Update() { //... if (Input.GetMouseButtonDown(0)) { attemptToUseItem();//使用物品 } } //使用物品 private void attemptToUseItem() { if (curHotbarIndex == -1) return; Item curItem = hotbarSlots[curHotbarIndex].getItem();// 获取选中的快捷栏中的物品 if (curItem && curItem.myEvent.GetPersistentEventCount() != 0) { curItem.UseItem();// 使用物品 if (curItem.currentQuantity != 0) hotbarSlots[curHotbarIndex].updateData();// 更新快捷栏数据 else hotbarSlots[curHotbarIndex].setItem(null);// 如果物品数量为0,清空快捷栏中的物品 enableHotbarItem(curHotbarIndex);// 再次激活快捷栏中的物品 } }
效果
运行看物品事件是否绑定上了
拿在手上点击使用
源码
源码不出意外的话我会放在最后一节