Unity游戏框架设计之背包管理器
Unity游戏框架设计之背包管理器
简单介绍
背包系统通常分为两个部分,第一个部分是背包的 UI 界面,第二个部分是对背包进行逻辑操作的管理器。
在下述代码中,实现了对背包的基本逻辑操作,包括向背包添加物品,从背包中取出物品,移动背包中的物品和使用背包中的物品的基本操作,并将这些操作封装为背包管理器。
为实现完整的背包系统,我们需要背包 UI 资源,并基于 MVC 模式编写背包 UI 的脚本,并配合背包管理器进行实现。
代码设计
public class BackpackManager : SingletonMono<BackpackManager>
{
private Dictionary<string, BackpackMetadata> _backpackMetadataSet;
protected override void Awake()
{
base.Awake();
_backpackMetadataSet = new Dictionary<string, BackpackMetadata>();
}
public void CreateBackpack(string backpackName, int height, int width)
{
if (!_backpackMetadataSet.TryAdd(backpackName, new BackpackMetadata(backpackName, height, width)))
{
return;
}
}
public void RemoveBackpack(string backpackName)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return;
}
_backpackMetadataSet.Remove(backpackName);
}
public (BackpackSlotMetadata metadata, int slotX, int slotY) AddItem(string backpackName, string itemID)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
BackpackMetadata backpackMetadata = _backpackMetadataSet[backpackName];
(int putSlotX, int putSlotY) = backpackMetadata.AddItem(itemID);
if (putSlotX == -1 || putSlotY == -1)
{
return (null, -1, -1);
}
return (backpackMetadata.SlotSet[putSlotX][putSlotY], putSlotX, putSlotY);
}
public BackpackSlotMetadata TakeItem(string backpackName, int x, int y)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
return _backpackMetadataSet[backpackName].TakeItem(x, y);
}
public (BackpackSlotMetadata from, BackpackSlotMetadata to) MoveItem(string backpackName, int fromX, int fromY, int toX, int toY)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
return _backpackMetadataSet[backpackName].MoveItem(fromX, fromY, toX, toY);
}
public BackpackSlotMetadata UseItem<T>(string backpackName, int x, int y, T target, bool consume = true) where T : Component
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
BackpackMetadata backpackMetadata = _backpackMetadataSet[backpackName];
BackpackSlotMetadata slotMetadata = backpackMetadata.SlotSet[x][y];
if (slotMetadata == null)
{
return default;
}
if (ItemManager.Instance.UseItem(slotMetadata.ItemID, target))
{
if (consume)
{
return backpackMetadata.TakeItem(x, y);
}
else
{
return slotMetadata;
}
}
return default;
}
public bool IsExistsItem(string backpackName, int x, int y)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
return _backpackMetadataSet[backpackName].SlotSet[x][y] != null;
}
public List<List<BackpackSlotMetadata>> GetBackpackItemSet(string backpackName)
{
if (!_backpackMetadataSet.ContainsKey(backpackName))
{
return default;
}
return _backpackMetadataSet[backpackName].SlotSet;
}
private class BackpackMetadata
{
public readonly string BackpackName;
public readonly int Height;
public readonly int Width;
public readonly List<List<BackpackSlotMetadata>> SlotSet;
public BackpackMetadata(string backpackName, int height, int width)
{
BackpackName = backpackName;
Height = height;
Width = width;
SlotSet = new List<List<BackpackSlotMetadata>>(Height);
for (int i = 0; i < Height; i++)
{
SlotSet.Add(new List<BackpackSlotMetadata>(Width));
for (int j = 0; j < Width; j++)
{
SlotSet[i].Add(null);
}
}
}
public (int, int) AddItem(string itemID)
{
(int sameItemSlotX, int sameItemSlotY) = FindSameItemSlotCoordinate(itemID);
if (sameItemSlotX != -1 && sameItemSlotY != -1)
{
SlotSet[sameItemSlotX][sameItemSlotY].Quantity++;
return (sameItemSlotX, sameItemSlotY);
}
(int emptySlotX, int emptySlotY) = FindNextEmptySlotCoordinate();
if (emptySlotX == -1 || emptySlotY == -1)
{
return (-1, -1);
}
ItemMetadata itemMetadata = ItemManager.Instance.FindItemMetadataByItemID(itemID);
SlotSet[emptySlotX][emptySlotY] = new BackpackSlotMetadata(itemID, itemMetadata.IconItemAssetPath, 1);
return (emptySlotX, emptySlotY);
}
public (BackpackSlotMetadata from, BackpackSlotMetadata to) MoveItem(int fromX, int fromY, int toX, int toY)
{
BackpackSlotMetadata fromSlotMetadata = SlotSet[fromX][fromY];
BackpackSlotMetadata toSlotMetadata = SlotSet[toX][toY];
if (fromSlotMetadata != null && toSlotMetadata != null && fromSlotMetadata.ItemID.Equals(toSlotMetadata.ItemID))
{
ItemMetadata itemMetadata = ItemManager.Instance.FindItemMetadataByItemID(fromSlotMetadata.ItemID);
int itemMaxStackQuantity = itemMetadata.MaxStackQuantity;
if (itemMaxStackQuantity - toSlotMetadata.Quantity >= fromSlotMetadata.Quantity)
{
SlotSet[toX][toY].Quantity += fromSlotMetadata.Quantity;
SlotSet[fromX][fromY] = null;
}
else
{
int moveQuantity = itemMaxStackQuantity - toSlotMetadata.Quantity;
SlotSet[toX][toY].Quantity += moveQuantity;
SlotSet[fromX][fromY].Quantity -= moveQuantity;
}
return (SlotSet[fromX][fromY], SlotSet[toX][toY]);
}
(SlotSet[fromX][fromY], SlotSet[toX][toY]) = (SlotSet[toX][toY], SlotSet[fromX][fromY]);
return (SlotSet[fromX][fromY], SlotSet[toX][toY]);
}
public BackpackSlotMetadata TakeItem(int x, int y)
{
BackpackSlotMetadata backpackSlotMetadata = SlotSet[x][y];
if (backpackSlotMetadata == null)
{
return default;
}
backpackSlotMetadata.Quantity--;
if (backpackSlotMetadata.Quantity <= 0)
{
SlotSet[x][y] = null;
backpackSlotMetadata.Quantity = 0;
}
return backpackSlotMetadata;
}
private (int, int) FindSameItemSlotCoordinate(string itemID)
{
int maxStackQuantity = ItemManager.Instance.FindItemMetadataByItemID(itemID).MaxStackQuantity;
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
BackpackSlotMetadata backpackSlotMetadata = SlotSet[i][j];
if (backpackSlotMetadata == null)
{
continue;
}
string slotItemID = backpackSlotMetadata.ItemID;
if (itemID.Equals(slotItemID) && backpackSlotMetadata.Quantity < maxStackQuantity)
{
return (i, j);
}
}
}
return (-1, -1);
}
private (int, int) FindNextEmptySlotCoordinate()
{
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
BackpackSlotMetadata backpackSlotMetadata = SlotSet[i][j];
if (backpackSlotMetadata == null)
{
return (i, j);
}
}
}
return (-1, -1);
}
}
}
代码说明
(一)实现创建背包、删除背包的功能。
(二)实现向背包添加物品、取出物品、移动物品和使用物品的功能。
后记
由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。
热门相关:天龙剑尊 重生之男神追妻忙 纨绔仙医 恶魔总裁霸道宠:老婆,甜似火 别吃那个鬼