前言
欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第25篇中,我们将探索如何用unity制作一个3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱等功能,我会附带项目源码,以便你更好理解它。
战利品箱子
新增LootTable ,配置战利品表信息
//战利品表 [CreateAssetMenu(fileName = "ChestLootTable", menuName = "Inventory/ChestLootTable")] public class LootTable : ScriptableObject { public List<LootItem> lootItems = new List<LootItem>(); // 掉落物品列表 [Range(0, 100)] public int spawnChancePerSlot = 20; // 单个槽位生成物品的概率 // 初始化掉落物品列表,计算总生成概率并进行归一化 public void InitialiseLootTable() { float totalSpawnChance = CalculateTotalSpawnChance(); if (totalSpawnChance > 100f) { NormaliseSpawnChances(); } } // 归一化生成概率,使其总和为 100% private void NormaliseSpawnChances() { float normalisationFactor = 100f / CalculateTotalSpawnChance(); foreach (LootItem item in lootItems) { item.spawnChance *= normalisationFactor; } } // 计算总生成概率 private float CalculateTotalSpawnChance() { float totalSpawnChance = 0f; foreach (LootItem item in lootItems) { totalSpawnChance += item.spawnChance; } return totalSpawnChance; } // 在宝箱内生成物品 public void SpawnLoot(List<Slot> allChestSlots) { foreach (Slot chestSlot in allChestSlots) { if (Random.Range(0f, 100f) <= spawnChancePerSlot) { SpawnRandomItem(chestSlot); } } } // 在指定槽位内生成随机物品 private void SpawnRandomItem(Slot slot) { LootItem chosenItem = ChooseRandomItem(); if (chosenItem != null) { int spawnCount = Random.Range(chosenItem.minSpawn, chosenItem.maxSpawn + 1); GameObject spawnedItem = Instantiate(chosenItem.itemPrefab, Vector3.zero, Quaternion.identity); spawnedItem.SetActive(false); Item itemComponent = spawnedItem.GetComponent<Item>(); if (itemComponent != null) { itemComponent.currentQuantity = spawnCount; } slot.setItem(itemComponent); // slot.updateData(); } } // 随机选择一个物品 private LootItem ChooseRandomItem() { float randomValue = Random.Range(0f, 100f); float cumulativeChance = 0f; foreach (LootItem item in lootItems) { cumulativeChance += item.spawnChance; if (randomValue <= cumulativeChance) { return item; } } return null; } } [System.Serializable] // 掉落物品信息类 public class LootItem { public GameObject itemPrefab; // 物品预制体 public int minSpawn; // 最小生成数量 public int maxSpawn; // 最大生成数量 [Range(0, 100)] public float spawnChance; // 生成概率 }
配置信息
修改Chest
[Header("战利品")] [SerializeField] private bool randomLoot; [SerializeField] private LootTable lootTable; private void Start() { //... if(randomLoot){ lootTable.InitialiseLootTable(); lootTable.SpawnLoot(allChestSlots); }else{ Inventory.Instance.allInventorySlots.AddRange(allChestSlots); } }
修改Inventory
// 打开宝箱时的操作 private void openChest(Chest chest) { //。。。 //如果是战利品宝箱 if (chest.randomLoot) allInventorySlots.AddRange(chestSloats);// 将宝箱内的所有槽位临时添加到玩家背包槽位列表中 } //去除战利品宝箱数据 public List<Slot> GetAllInventorySlots() { List<Slot> newAllInventorySlots = allInventorySlots; if (chest && chest.randomLoot) { foreach (Slot chestSloat in chestSloats) { newAllInventorySlots.Remove(chestSloat); } } return newAllInventorySlots; } //开关背包 private void toggleInventory(bool enable) { //关闭背包时,隐藏信息框 if (!enable) itemHoverInformation.gameObject.SetActive(false); //关闭背包时,关闭所有鼠标悬停在该槽位上的标志 if (!enable) { foreach (Slot curSlot in allInventorySlots) { curSlot.hovered = false; } } //关闭背包时,清除所有的宝箱数据 if (!enable && chestSlotParent != null) { allInventorySlots = GetAllInventorySlots(); chestSlotParent.SetActive(false); chestSlotParent = null; chestSloats = null; chest = null; } inventory.SetActive(enable); // 根据参数显示或隐藏背包界面 Cursor.lockState = enable ? CursorLockMode.None : CursorLockMode.Locked; // 根据背包界面的状态锁定或解锁鼠标指针 Cursor.visible = enable; // 设置鼠标指针的可见性 // 禁用或启用相机的旋转控制 Camera.main.GetComponent<MouseLook>().enabled = !enable; }
修改SaveInventory,不保存战利品宝箱数据
// 保存物品数据 private void saveInventory() { List<Slot> allInventorySlots = Inventory.Instance.GetAllInventorySlots(); //。。。 } // 加载物品数据 private void loadInventory() { List<Slot> allInventorySlots = Inventory.Instance.GetAllInventorySlots(); //。。。 }
效果