1、目标
当角色经过道具时会拾取道具放到库存列表中,此时道具消失并打印库存信息。
2、创建新的Enum
在Assets -> Scripts -> Enums -> Enum.cs中添加库存位置相关的信息。
public enum InventoryLocation
{player, // 在角色手中chest, // 在箱子里count // 枚举位置的计数, 值为2,只要把count放在最后一位,自动进行了计数
}
最后一个枚举值为count,此时count值自动为枚举个数值。
此时Enum.cs完整代码如下:
public enum ToolEffect
{none, watering
}public enum Direction
{up,down,left,right,none
}public enum ItemType
{Seed, // 种子Commodity, // 商品Watering_tool, // 浇水工具Hoeing_tool, // 锄头Chopping_tool, // 砍伐工具Breaking_tool, // 破碎工具Reaping_tool, // 收割工具Collecting_tool, // 收集工具Reapable_scenary, // 可达到场景Furniture, // 家具none,count // 计数,记录列表中东西的个数
}public enum InventoryLocation
{player, // 在角色手中chest, // 在箱子里count // 枚举位置的计数, 值为2,只要把count放在最后一位,自动进行了计数
}
3、创建InventoryItem脚本
在Assets -> Scripts -> Inventory下创建InventoryItem.cs脚本。
它是一个struct结构体,记录每个item的code以及数量。
[System.Serializable]
public struct InventoryItem
{public int itemCode;public int itemQuantity;
}
4、增加Settings中配置项
// Inventory
public static int playerInitialInventoryCapacity = 24;
public static int playerMaximumInventoryCapacity = 48;
此时Settings.cs完整代码为:
using UnityEngine;public static class Settings
{// Obscuring Item Faderpublic const float fadeInSeconds = 0.25f;public const float fadeOutSeconds = 0.35f;public const float targetAlpha = 0.45f;// Player Movementpublic const float runningSpeed = 5.333f;public const float walkingSpeed = 2.666f;// Inventorypublic static int playerInitialInventoryCapacity = 24;public static int playerMaximumInventoryCapacity = 48;// Player Animation Parameterspublic static int xInput;public static int yInput;public static int isWalking;public static int isRunning;public static int toolEffect;public static int isUsingToolRight;public static int isUsingToolLeft;public static int isUsingToolUp;public static int isUsingToolDown;public static int isLiftingToolRight;public static int isLiftingToolLeft;public static int isLiftingToolUp;public static int isLiftingToolDown;public static int isSwingingToolRight;public static int isSwingingToolLeft;public static int isSwingingToolUp;public static int isSwingingToolDown;public static int isPickingRight;public static int isPickingLeft;public static int isPickingUp;public static int isPickingDown;// Shared Animation Parameterspublic static int idleUp;public static int idleDown;public static int idleLeft;public static int idleRight;// static constructorstatic Settings(){xInput = Animator.StringToHash("xInput");yInput = Animator.StringToHash("yInput");isWalking = Animator.StringToHash("isWalking");isRunning = Animator.StringToHash("isRunning");toolEffect = Animator.StringToHash("toolEffect");isUsingToolRight = Animator.StringToHash("isUsingToolRight");isUsingToolLeft = Animator.StringToHash("isUsingToolLeft");isUsingToolUp = Animator.StringToHash("isUsingToolUp");isUsingToolDown = Animator.StringToHash("isUsingToolDown");isLiftingToolRight = Animator.StringToHash("isLiftingToolRight");isLiftingToolLeft = Animator.StringToHash("isLiftingToolLeft");isLiftingToolUp = Animator.StringToHash("isLiftingToolUp");isLiftingToolDown = Animator.StringToHash("isLiftingToolDown");isSwingingToolRight = Animator.StringToHash("isSwingingToolRight");isSwingingToolLeft = Animator.StringToHash("isSwingingToolLeft");isSwingingToolUp = Animator.StringToHash("isSwingingToolUp");isSwingingToolDown = Animator.StringToHash("isSwingingToolDown");isPickingRight = Animator.StringToHash("isPickingRight");isPickingLeft = Animator.StringToHash("isPickingLeft");isPickingUp = Animator.StringToHash("isPickingUp");isPickingDown = Animator.StringToHash("isPickingDown");idleUp = Animator.StringToHash("idleUp");idleDown = Animator.StringToHash("idleDown");idleLeft = Animator.StringToHash("idleLeft");idleRight = Animator.StringToHash("idleRight");}}
5、创建库存变更事件
在Assets -> Scripts -> Events -> EventHandler.cs中,添加库存变更事件。
// Inventory Updated Eventpublic static event Action<InventoryLocation, List<InventoryItem>> InventoryUpdatedEvent;public static void CallInventoryUpdatedEvent(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList){if(InventoryUpdatedEvent != null) // 有订阅者{InventoryUpdatedEvent(inventoryLocation, inventoryList);}}
此时EventHandler.cs完整代码如下:
using System;
using System.Collections.Generic;public delegate void MovementDelegate(float inputX, float inputY, bool isWalking, bool isRunning, bool isIdle, bool isCarrying, ToolEffect toolEffect, bool isUsingToolRight, bool isUsingToolLeft, bool isUsingToolUp, bool isUsingToolDown, bool isLiftingToolRight, bool isLiftingToolLeft, bool isLiftingToolUp, bool isLiftingToolDown, bool isPickingRight, bool isPickingLeft, bool isPickingUp, bool isPickingDown, bool isSwingToolRight, bool isSwingToolLeft, bool isSwingToolUp, bool isSwingToolDown, bool idleUp, bool idleDown, bool idleLeft, bool idleRight);public static class EventHandler
{// Inventory Updated Eventpublic static event Action<InventoryLocation, List<InventoryItem>> InventoryUpdatedEvent;public static void CallInventoryUpdatedEvent(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList){if(InventoryUpdatedEvent != null) // 有订阅者{InventoryUpdatedEvent(inventoryLocation, inventoryList);}}// Movement Eventpublic static event MovementDelegate MovementEvent;// Movement Event Call For Publisherspublic static void CallMovementEvent(float inputX, float inputY, bool isWalking, bool isRunning, bool isIdle, bool isCarrying,ToolEffect toolEffect,bool isUsingToolRight, bool isUsingToolLeft, bool isUsingToolUp, bool isUsingToolDown,bool isLiftingToolRight, bool isLiftingToolLeft, bool isLiftingToolUp, bool isLiftingToolDown,bool isPickingRight, bool isPickingLeft, bool isPickingUp, bool isPickingDown,bool isSwingToolRight, bool isSwingToolLeft, bool isSwingToolUp, bool isSwingToolDown,bool idleUp, bool idleDown, bool idleLeft, bool idleRight){if (MovementEvent != null){MovementEvent(inputX, inputY, isWalking, isRunning, isIdle, isCarrying,toolEffect,isUsingToolRight, isUsingToolLeft, isUsingToolUp, isUsingToolDown,isLiftingToolRight, isLiftingToolLeft, isLiftingToolUp, isLiftingToolDown,isPickingRight, isPickingLeft, isPickingUp, isPickingDown,isSwingToolRight, isSwingToolLeft, isSwingToolUp, isSwingToolDown,idleUp, idleDown, idleLeft, idleRight);}}}
6、更新库存管理类
在Assets -> Scritpts -> Inventory -> InventoryManager.cs中。
首先,创建两个变量inventoryLists和inventoryListCapacityIntArray,前面记录了每个位置(比如玩家身上的,玩家箱子里的等等)的库存情况,后面记录了每个位置库存的item数量。
然后,在Awake中通过CreateInventoryLists初始化inventoryLists和inventoryListCapacityIntArray值。
接着,创建添加Item的方法AddItem(InventoryLocation inventoryLocation, Item item),即在哪个位置放什么Item。需要先搜索一遍该位置的库存,检查下是否已经存在,存在则返回库存清单的索引值。然后在哪个索引对应的InventoryItem更新下库存数。如果找不到这个item,那么直接在位置对应的库存清单末尾增加这个InventoryItem。
最后,再创建AddItem重载方法 AddItem(InventoryLocation inventoryLocation, Item item, GameObject gameObjectToDelete)。这个对应的逻辑就是:当角色拾取某个道具时,需要更新下对应的库存,同时将这个道具删除下。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InventoryManager : SingletonMonobehaviour<InventoryManager>
{private Dictionary<int, ItemDetails> itemDetailsDictionary;public List<InventoryItem>[] inventoryLists; // 每个位置的库存清单// 每个位置的库存数。 The index of the array is the inventory list(from the// InventoryLocation enum), and the value is the capacity of that inventory list[HideInInspector] public int[] inventoryListCapacityIntArray; [SerializeField] private SO_ItemList itemList = null;protected override void Awake(){base.Awake();// Create Inventory listsCreateInventoryLists();// Create item details dictionaryCreateItemDetailsDictionary();}private void CreateInventoryLists(){inventoryLists = new List<InventoryItem>[(int)InventoryLocation.count];for (int i = 0; i < (int)InventoryLocation.count; i++){inventoryLists[i] = new List<InventoryItem>();}// initialize inventory list capacity arrayinventoryListCapacityIntArray = new int[(int)InventoryLocation.count];// initialize player inventory list capacityinventoryListCapacityIntArray[(int)InventoryLocation.player] = Settings.playerInitialInventoryCapacity;}/// <summary>/// Populates the itemDetailsDictionary from the scriptable object items list/// </summary>private void CreateItemDetailsDictionary(){itemDetailsDictionary = new Dictionary<int, ItemDetails>();foreach (ItemDetails itemDetails in itemList.itemDetails) {itemDetailsDictionary.Add(itemDetails.itemCode, itemDetails);}}/// <summary>/// Add an item to the inventory list for the inventoryLocation and then destroy the gameObjectToDelete/// 角色拾取到物品后,物品需要消失掉/// </summary>/// <param name="inventoryLocation"></param>/// <param name="item"></param>/// <param name="gameObjectToDelete"></param>public void AddItem(InventoryLocation inventoryLocation, Item item, GameObject gameObjectToDelete){AddItem(inventoryLocation, item);Destroy(gameObjectToDelete);}/// <summary>/// Add an item to the inventory list for the inventoryLocation/// </summary>/// <param name="inventoryLocation"></param>/// <param name="item"></param>public void AddItem(InventoryLocation inventoryLocation, Item item){int itemCode = item.ItemCode;List<InventoryItem> inventoryList = inventoryLists[(int)inventoryLocation];// Check if inventory already contains the itemint itemPosition = FindItemInInventory(inventoryLocation, itemCode);if(itemPosition != -1){AddItemPosition(inventoryList, itemCode, itemPosition);}else{AddItemPosition(inventoryList, itemCode);}// Send event that inventory has been updatedEventHandler.CallInventoryUpdatedEvent(inventoryLocation, inventoryLists[(int)inventoryLocation]); }/// <summary>/// Add item to position in the inventory/// </summary>/// <param name="inventoryList"></param>/// <param name="itemCode"></param>/// <param name="position"></param>/// <exception cref="NotImplementedException"></exception>private void AddItemPosition(List<InventoryItem> inventoryList, int itemCode, int position){InventoryItem inventoryItem = new InventoryItem();int quantity = inventoryList[position].itemQuantity + 1;inventoryItem.itemQuantity = quantity;inventoryItem.itemCode = itemCode;inventoryList[position] = inventoryItem;Debug.ClearDeveloperConsole();DebugPrintInventoryList(inventoryList);}private void DebugPrintInventoryList(List<InventoryItem> inventoryList){foreach(InventoryItem inventoryItem in inventoryList){Debug.Log("Item Description:" + InventoryManager.Instance.GetItemDetails(inventoryItem.itemCode).itemDescription + " Item Quantity:" + inventoryItem.itemQuantity);}Debug.Log("*******************************************************************************");}/// <summary>/// Add item to the end of the inventory /// </summary>/// <param name="inventoryList"></param>/// <param name="itemCode"></param>/// <exception cref="NotImplementedException"></exception>private void AddItemPosition(List<InventoryItem> inventoryList, int itemCode){InventoryItem inventoryItem = new InventoryItem(); inventoryItem.itemCode = itemCode;inventoryItem.itemQuantity = 1;inventoryList.Add(inventoryItem);DebugPrintInventoryList(inventoryList);}/// <summary>/// Find if an itemCode is already in the inventory. Returns the item position/// in the inventory list, or -1 if the item is not in the inventory/// </summary>/// <param name="inventoryLocation"></param>/// <param name="itemCode"></param>/// <returns></returns>/// <exception cref="NotImplementedException"></exception>private int FindItemInInventory(InventoryLocation inventoryLocation, int itemCode){List<InventoryItem> inventoryList = inventoryLists[(int)inventoryLocation];for (int i = 0; i < inventoryList.Count; i++){if(inventoryList[i].itemCode == itemCode){return i;}}return -1;}/// <summary>/// Returns the itemDetails (from the SO_ItemList) for the itemCode, or null if the item doesn't exist/// </summary>/// <param name="itemCode"></param>/// <returns></returns>public ItemDetails GetItemDetails(int itemCode) {ItemDetails itemDetails;if(itemDetailsDictionary.TryGetValue(itemCode, out itemDetails)){return itemDetails;}else{return null;}}
}
该代码目前还有个遗憾:库存更新事件还没有被订阅,这个后续再进一步处理。
7、更新ItemPickup脚本
之前的代码时,用户经过道具时可以感知到,会打印道具的名称。
现在是:用户经过道具时,道具消失,同时用户库存清单的值被更新。
新增如下代码:
// If item can be picked up
if(itemDetails.canBePickedUp == true)
{// Add item to inventoryInventoryManager.Instance.AddItem(InventoryLocation.player, item, collision.gameObject);
}
此时ItemPickup.cs完整代码是:
using UnityEngine;public class ItemPickup : MonoBehaviour
{private void OnTriggerEnter2D(Collider2D collision){Item item = collision.GetComponent<Item>();if(item != null){// Get item detailsItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(item.ItemCode);// If item can be picked upif(itemDetails.canBePickedUp == true){// Add item to inventoryInventoryManager.Instance.AddItem(InventoryLocation.player, item, collision.gameObject);}}}
}
效果如下: