1、目标
当角色经过道具时会拾取道具放到库存列表中,此时道具消失并打印库存信息。
2、创建新的Enum
在Assets -> Scripts -> Enums -> Enum.cs中添加库存位置相关的信息。
cs
public enum InventoryLocation
{
player, // 在角色手中
chest, // 在箱子里
count // 枚举位置的计数, 值为2,只要把count放在最后一位,自动进行了计数
}
最后一个枚举值为count,此时count值自动为枚举个数值。
此时Enum.cs完整代码如下:
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以及数量。
cs
[System.Serializable]
public struct InventoryItem
{
public int itemCode;
public int itemQuantity;
}
4、增加Settings中配置项
cs
// Inventory
public static int playerInitialInventoryCapacity = 24;
public static int playerMaximumInventoryCapacity = 48;
此时Settings.cs完整代码为:
cs
using UnityEngine;
public static class Settings
{
// Obscuring Item Fader
public const float fadeInSeconds = 0.25f;
public const float fadeOutSeconds = 0.35f;
public const float targetAlpha = 0.45f;
// Player Movement
public const float runningSpeed = 5.333f;
public const float walkingSpeed = 2.666f;
// Inventory
public static int playerInitialInventoryCapacity = 24;
public static int playerMaximumInventoryCapacity = 48;
// Player Animation Parameters
public 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 Parameters
public static int idleUp;
public static int idleDown;
public static int idleLeft;
public static int idleRight;
// static constructor
static 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中,添加库存变更事件。
cs
// Inventory Updated Event
public static event Action<InventoryLocation, List<InventoryItem>> InventoryUpdatedEvent;
public static void CallInventoryUpdatedEvent(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList)
{
if(InventoryUpdatedEvent != null) // 有订阅者
{
InventoryUpdatedEvent(inventoryLocation, inventoryList);
}
}
此时EventHandler.cs完整代码如下:
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 Event
public static event Action<InventoryLocation, List<InventoryItem>> InventoryUpdatedEvent;
public static void CallInventoryUpdatedEvent(InventoryLocation inventoryLocation, List<InventoryItem> inventoryList)
{
if(InventoryUpdatedEvent != null) // 有订阅者
{
InventoryUpdatedEvent(inventoryLocation, inventoryList);
}
}
// Movement Event
public static event MovementDelegate MovementEvent;
// Movement Event Call For Publishers
public 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)。这个对应的逻辑就是:当角色拾取某个道具时,需要更新下对应的库存,同时将这个道具删除下。
cs
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 lists
CreateInventoryLists();
// Create item details dictionary
CreateItemDetailsDictionary();
}
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 array
inventoryListCapacityIntArray = new int[(int)InventoryLocation.count];
// initialize player inventory list capacity
inventoryListCapacityIntArray[(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 item
int itemPosition = FindItemInInventory(inventoryLocation, itemCode);
if(itemPosition != -1)
{
AddItemPosition(inventoryList, itemCode, itemPosition);
}
else
{
AddItemPosition(inventoryList, itemCode);
}
// Send event that inventory has been updated
EventHandler.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脚本
之前的代码时,用户经过道具时可以感知到,会打印道具的名称。
现在是:用户经过道具时,道具消失,同时用户库存清单的值被更新。
新增如下代码:
cs
// If item can be picked up
if(itemDetails.canBePickedUp == true)
{
// Add item to inventory
InventoryManager.Instance.AddItem(InventoryLocation.player, item, collision.gameObject);
}
此时ItemPickup.cs完整代码是:
cs
using UnityEngine;
public class ItemPickup : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision)
{
Item item = collision.GetComponent<Item>();
if(item != null)
{
// Get item details
ItemDetails itemDetails = InventoryManager.Instance.GetItemDetails(item.ItemCode);
// If item can be picked up
if(itemDetails.canBePickedUp == true)
{
// Add item to inventory
InventoryManager.Instance.AddItem(InventoryLocation.player, item, collision.gameObject);
}
}
}
}
效果如下:

