7月份自己做了一个模拟经营类的游戏Demo,在此总结UI、库存系统、交易系统、游戏循环等相关内容的代码和实现。
目录
UI
库存系统
交易系统
游戏循环
本项目的UI通过Unity自家的UGUI实现,所有面板的父对象皆为Canvas,各面板为一个实例化的单例对象,其数据由自己进行存储和更新。
IPanel接口:
interface IPanel
{
public void ShowPanel();
public void HidePanel();
}
以商店面板为例:
(通过给面板添加CanvasGroup组件,并更改其参数实现面板的显隐)
public class ShopPanel : MonoBehaviour, IPanel
{
//单例
private static ShopPanel instance;
public static ShopPanel Instance
{
get
{
return instance;
}
}
//获取商店面板信息
public TMP_Text txtTime;
public TMP_Text txtDays;
public TMP_Text txtShopMoney;
public KnapsackPanel knapsack1Panel;
public KnapsackPanel knapsack2Panel;
public KnapsackPanel knapsack3Panel;
public RolePanel role1Panel;
public RolePanel role2Panel;
public RolePanel role3Panel;
private CanvasGroup canvasGroup;
private int money = 100;
public int Money
{
get { return money; }
set
{
money = value;
txtShopMoney.text = money.ToString();
}
}
public Button btnStorage;
public Button btnCreate;
public static bool storageVisible = false;
public static bool createVisible = false;
private void Awake()
{
//实例化单例
instance = this;
}
// Start is called before the first frame update
void Start()
{
canvasGroup = gameObject.GetComponent();
HidePanel();
btnStorage.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
//仓库按钮按下的逻辑
if (!storageVisible)
{
storageVisible = true;
StoragePanel.Instance.ShowPanel();
createVisible = false;
CreatePanel.Instance.HidePanel();
}
else
{
storageVisible = false;
StoragePanel.Instance.HidePanel();
}
});
btnCreate.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
//制造按钮按下的逻辑
if (!createVisible)
{
createVisible = true;
CreatePanel.Instance.ShowPanel();
storageVisible = false;
StoragePanel.Instance.HidePanel();
}
else
{
createVisible = false;
CreatePanel.Instance.HidePanel();
}
});
txtShopMoney.text = money.ToString();
}
//实现接口IPanel
public void ShowPanel()
{
canvasGroup.alpha = 1;
canvasGroup.interactable = true;
canvasGroup.blocksRaycasts = true;
}
public void HidePanel()
{
canvasGroup.alpha = 0;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
}
///
/// 花费金钱
///
public bool ConsumeMoney(int amount)
{
if (money < amount)
{
NoticePanel.Instance.ShowNotice("金钱不足!");
return false;
}
money -= amount;
txtShopMoney.text = money.ToString();
NoticePanel.Instance.ShowNotice("交易成功!");
return true;
}
///
/// 赚取金钱
///
public void EarnMoney(int amount)
{
money += amount;
txtShopMoney.text = money.ToString();
}
}
库存系统由Inventory、InventoryManager、Slot、ItemUI等类实现。
Inventory类:
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class Inventory : MonoBehaviour
{
protected Slot[] slots;
public Slot[] Slots
{
get
{
return slots;
}
set
{
slots = value;
}
}
// Start is called before the first frame update
public virtual void Start()
{
slots = GetComponentsInChildren();
}
///
/// 通过ID存储物品
///
///
///
public bool StoreItem(int id)
{
Item item = InventoryManager.Instance.GetItemID(id);
return StoreItem(item);
}
///
/// 是否存储成功
///
///
///
public bool StoreItem(Item item)
{
if (item == null)
return false;
if (item.capacity == 1)
{
Slot slot = FindEmptySlot();
if (slot == null)
{
NoticePanel.Instance.ShowNotice("没空的物品槽!");
return false;
}
else
{
slot.CreateItem(item);
}
}
else
{
Slot slot = FindSameIDSlot(item);
if (slot != null)
{
slot.CreateItem(item);
}
else //找新的空物品槽
{
Slot slot2 = FindEmptySlot();
if (slot2 != null)
slot2.CreateItem(item);
else
{
NoticePanel.Instance.ShowNotice("没空的物品槽!");
return false;
}
}
}
return true;
}
///
/// 减少物品数量
///
///
///
///
///
public bool ReduceItem(Item targetItem, int total, int amount = 1)
{
if (amount > total)
return false;
foreach (Slot slot in slots)
{
if (slot.transform.childCount != 0)
{
GameObject items = slot.transform.GetChild(0).GetComponent().gameObject;
if (items.GetComponent().Item.id == targetItem.id)
{
int currentAmount = int.Parse(items.transform.GetChild(0).gameObject.GetComponent().text);
if (amount >= currentAmount)
{
amount -= currentAmount;
total -= currentAmount;
items.transform.GetChild(0).gameObject.GetComponent().text = 0.ToString();
DestroyImmediate(items);
items = null;
if (total == 0)
{
BuyPanel.CancelBuy();
return true;
}
}
else
{
currentAmount -= amount;
total -= amount;
items.GetComponent().Amount = currentAmount;
items.transform.GetChild(0).gameObject.GetComponent().text = currentAmount.ToString();
amount = 0;
}
}
if (amount == 0)
{
return true;
}
}
}
return false;
}
///
/// 找空的物品槽
///
///
private Slot FindEmptySlot()
{
foreach (Slot slot in slots)
{
if (slot.transform.childCount == 0)
return slot;
}
return null;
}
///
/// 找相同ID的物品槽
///
///
private Slot FindSameIDSlot(Item item)
{
foreach (Slot slot in slots)
{
if (slot.transform.childCount >= 1 && slot.GetItemID() == item.id && slot.IsFull() == false)
return slot;
}
return null;
}
///
/// 统计相同ID物品的总数量
///
///
///
public int CountSameIDSlot(Item item)
{
int count = 0;
foreach (Slot slot in slots)
{
if (slot.transform.childCount >= 1 && slot.GetItemID() == item.id)
count += int.Parse(slot.transform.GetChild(0).transform.GetChild(0).GetComponent().text);
}
return count;
}
///
/// 背包整理(空格收纳、物品排序、材料收纳)
///
public void InventoryClear()
{
EmptyClear();
Sort();
Combine();
}
///
/// 空格收纳
///
public void EmptyClear()
{
int itemCount = 0;
foreach(Slot slot in slots)
{
if (slot.transform.childCount != 0)
itemCount++;
}
for (int i = 0; i < slots.Length; i++)
{
if (slots[i].transform.childCount == 0)
{
OneEmptyClear(i);
i = -1;
}
if (i + 1 == itemCount)
return;
}
}
///
/// 单个空格收纳
///
///
public void OneEmptyClear(int index)
{
for (int i = index + 1; i < slots.Length; i++)
{
if (slots[i].transform.childCount != 0)
{
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slots[i - 1].transform);
go1.transform.localPosition = Vector3.zero;
}
}
}
///
/// 物品排序
///
public void Sort()
{
//整体排序
int i, j;
for (i = 0; i < slots.Length - 1; i++)
{
if (slots[i].transform.childCount == 0)
break;
for (j = i + 1; j < slots.Length; j++)
{
if (slots[j].transform.childCount == 0)
break;
if (slots[i].transform.GetChild(0).GetComponent().Item.id < slots[j].transform.GetChild(0).GetComponent().Item.id)
{
Swap(i, j);
}
}
}
int l = 0;
int k = l;
//装备耐久度排序(优先低耐久度)
while (slots[l].transform.childCount != 0 && slots[l].transform.GetChild(0).GetComponent().Item.type == Item.ItemType.Equipment)
{
while (slots[k].transform.childCount != 0 && slots[k].transform.GetChild(0).GetComponent().Item.id == slots[l].transform.GetChild(0).GetComponent().Item.id)
k++;
for (i = l; i < k - 1; i++)
{
for (j = i + 1; j < k; j++)
{
if (slots[i].transform.GetChild(0).GetComponent().durability > slots[j].transform.GetChild(0).GetComponent().durability)
{
Swap(i, j);
}
}
}
l = k;
}
}
///
/// 交换物品位置
///
///
///
public void Swap(int a, int b)
{
GameObject go1 = slots[a].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slots[b].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slots[b].transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[a].transform);
go2.transform.localPosition = Vector3.zero;
}
///
/// 合并材料
///
public void Combine()
{
int i = 0;
//结束范围
while (slots[i].transform.childCount != 0 && i < slots.Length)
{
//开始范围
if (slots[i].transform.GetChild(0).GetComponent().Item.type == Item.ItemType.EquipMaterial)
{
int j = i, k = i;
//设置此种材料的下界
while (slots[k].transform.childCount != 0 && slots[k].transform.GetChild(0).GetComponent().Item.id == slots[i].transform.GetChild(0).GetComponent().Item.id)
k++;
int sum = 0;
for (; j < k; j++)
{
//局部计算当前材料的总数量
sum += int.Parse(slots[j].transform.GetChild(0).transform.GetChild(0).GetComponent().text);
}
j = i;
while (sum != 0)
{
//满足条件则是此种材料最后一格
if (sum <= slots[i].transform.GetChild(0).GetComponent().Item.capacity)
{
slots[j].transform.GetChild(0).transform.GetChild(0).GetComponent().text = sum.ToString();
sum = 0;
if (slots[j + 1].transform.childCount != 0 && slots[j + 1].transform.GetChild(0).GetComponent().Item.id == slots[i].transform.GetChild(0).GetComponent().Item.id)
{
DestroyImmediate(slots[j + 1].transform.GetChild(0).gameObject);
EmptyClear();
}
}
else
{
slots[j].transform.GetChild(0).transform.GetChild(0).GetComponent().text = slots[i].transform.GetChild(0).GetComponent().Item.capacity.ToString();
sum -= slots[i].transform.GetChild(0).GetComponent().Item.capacity;
}
j++;
}
i = k - 1;
}
i++;
}
}
}
需要实现库存功能的面板继承Inventory类,以KnapsackPanel为例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class KnapsackPanel : Inventory, IPanel
{
public Button btnKnapsackClose;
public RolePanel rolePanel;
private CanvasGroup canvasGroup;
// Start is called before the first frame update
public override void Start()
{
base.Start();
canvasGroup = gameObject.GetComponent();
HidePanel();
btnKnapsackClose.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
//关闭逻辑
RolePanel.knapsackVisible = false;
HidePanel();
});
}
// Update is called once per frame
void Update()
{
}
public void ShowPanel()
{
//整理库存
InventoryClear();
canvasGroup.alpha = 1;
canvasGroup.interactable = true;
canvasGroup.blocksRaycasts = true;
}
public void HidePanel()
{
canvasGroup.alpha = 0;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
}
public void Equip()
{
int i = 0;
for (; i < slots.Length; i++)
{
//结束判断
if (slots[i].transform.childCount == 0 || slots[i].transform.GetChild(0).GetComponent().Item.type == Item.ItemType.EquipMaterial)
return;
Item item = slots[i].transform.GetChild(0).GetComponent().Item;
int itemID = item.id;
switch(Equipment.GetTypeID(itemID))
{
case "Head":
foreach (Slot slot in rolePanel.Slots)
{
//如果类型匹配
if (slot.name == "Head")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtHead.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
case "Chest":
foreach (Slot slot in rolePanel.Slots)
{
//如果装备类型匹配
if (slot.name == "Chest")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtChest.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
case "Weapon":
foreach (Slot slot in rolePanel.Slots)
{
//如果装备类型匹配
if (slot.name == "Weapon")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtWeapon.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
case "Glove":
foreach (Slot slot in rolePanel.Slots)
{
//如果装备类型匹配
if (slot.name == "Glove")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtGlove.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
case "Jewelry":
foreach (Slot slot in rolePanel.Slots)
{
//如果装备类型匹配
if (slot.name == "Jewelry")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtJewelry.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
case "Shield":
foreach (Slot slot in rolePanel.Slots)
{
//如果装备类型匹配
if (slot.name == "Shield")
{
int equipCount = slot.transform.childCount;
//装备栏为空
if (equipCount == 0 || slot.transform.GetChild(equipCount - 1).GetComponent().durability <= 0)
{
//将背包内的装备放入装备栏
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
//为角色加上装备属性
Equipment equipment = InventoryManager.Instance.GetEquipmentID(go1.GetComponent().Item.id);
if (equipment != null)
{
rolePanel.Hp += equipment.hp;
rolePanel.Str += equipment.str;
rolePanel.Def += equipment.def;
rolePanel.Atk += equipment.atk;
rolePanel.Crit += equipment.crit;
rolePanel.CritDam += equipment.critDam;
}
//隐藏装备类型文字
rolePanel.txtShield.alpha = 0;
//整理背包
InventoryClear();
i--;
}
//优先穿戴高阶装备
else if (equipCount == 1 && slot.transform.GetChild(0).GetComponent().Item.id < itemID)
{
//将背包内的装备和装备栏的互换
GameObject go1 = slots[i].transform.Find("Items(Clone)").gameObject;
GameObject go2 = slot.transform.Find("Items(Clone)").gameObject;
go1.transform.SetParent(slot.transform);
go1.transform.localPosition = Vector3.zero;
go2.transform.SetParent(slots[i].transform);
go2.transform.localPosition = Vector3.zero;
//角色属性调整
Equipment equipment1 = InventoryManager.Instance.GetEquipmentID(slots[i].transform.GetChild(0).GetComponent().Item.id);
Equipment equipment2 = InventoryManager.Instance.GetEquipmentID(slot.transform.GetChild(0).GetComponent().Item.id);
rolePanel.Hp += equipment2.hp - equipment1.hp;
rolePanel.Str += equipment2.str - equipment1.str;
rolePanel.Def += equipment2.def - equipment1.def;
rolePanel.Atk += equipment2.atk - equipment1.atk;
rolePanel.Crit += equipment2.crit - equipment1.crit;
rolePanel.CritDam += equipment2.critDam - equipment1.critDam;
//整理背包
InventoryClear();
}
}
}
break;
}
}
}
public void ClearMaterial()
{
foreach (Slot slot in slots)
{
if (slot.transform.childCount > 0 && slot.transform.GetChild(0).GetComponent().Item.type == Item.ItemType.EquipMaterial)
Destroy(slot.transform.GetChild(0).gameObject);
}
}
}
InventoryManager类:
(游戏内物品的信息以及合成配方信息使用JSON格式进行存储读取)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InventoryManager : MonoBehaviour
{
//单例
private static InventoryManager instance;
public static InventoryManager Instance
{
get
{
return instance;
}
}
private ToolTip toolTip;
private ForgeTip forgeTip;
///
/// 判断是否显示ToolTip
///
private bool isShowToolTipLeft = false;
private bool isShowToolTipRight = false;
private bool isShowForgeTip = false;
private static Canvas canvas;
private void Awake()
{
//实例化单例
instance = this;
ParseItemsJSON();
}
// Start is called before the first frame update
void Start()
{
toolTip = FindObjectOfType();
forgeTip = FindObjectOfType();
canvas = GameObject.Find("Canvas").GetComponent
Slot类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public GameObject itemPrefab;
public void CreateItem(Item item)
{
if (transform.childCount == 0)
{
GameObject itemPrefabs = Instantiate(itemPrefab);
itemPrefabs.transform.SetParent(transform);
itemPrefabs.transform.localPosition = Vector3.zero;
itemPrefabs.transform.localScale = Vector3.one;
transform.GetChild(0).GetComponent().SetItem(item);
}
else
{
transform.GetChild(0).GetComponent().AddAmount();
}
}
public void CreateItem(Item item,int amount)
{
if (transform.childCount == 0)
{
GameObject itemPrefabs = GameObject.Instantiate(itemPrefab);
itemPrefabs.transform.SetParent(transform);
itemPrefabs.transform.localPosition = Vector3.zero;
itemPrefabs.transform.localScale = Vector3.one;
transform.GetChild(0).GetComponent().SetItem(item, amount);
}
else
{
return;
}
}
///
/// 得到当前物品槽存储的物品类型
///
///
public Item.ItemType GetItemType()
{
return transform.GetChild(0).GetComponent().Item.type;
}
///
/// 得到当前物品槽存储的物品ID
///
///
public int GetItemID()
{
return transform.GetChild(0).GetComponent().Item.id;
}
///
/// 当前物品槽的物品容量是否已满
///
///
///
public bool IsFull()
{
ItemUI itemUI = transform.GetChild(0).GetComponent();
return itemUI.Amount >= itemUI.Item.capacity;
}
public void OnPointerEnter(PointerEventData eventData)
{
if (transform.childCount > 0)
{
//当指向制作栏中的装备时
if (transform.GetChild(0).GetComponent().Item.type == Item.ItemType.Equipment && transform.parent.parent.GetComponent() == CreatePanel.Instance)
{
string content = transform.GetChild(0).GetComponent().Item.GetToolTipContent();
InventoryManager.Instance.ShowToolTipContentLeft(content);
string forge = transform.GetChild(0).GetComponent().Item.GetForgeTipContent();
InventoryManager.Instance.ShowForgeTipContent(forge);
}
//当指向背包和装备栏中的装备时
else if (transform.GetChild(0).GetComponent().Item.type == Item.ItemType.Equipment && transform.parent.parent.GetComponent() != CreatePanel.Instance)
{
string content = transform.GetChild(0).GetComponent().Item.GetToolTipContent() + string.Format("\n耐久度: {0} ", transform.GetChild(0).GetComponent().durability);
InventoryManager.Instance.ShowToolTipContentRight(content);
}
//当指向仓库中的材料时
else if (transform.parent.parent.GetComponent() == StoragePanel.Instance)
{
string content = transform.GetChild(0).GetComponent().Item.GetToolTipContent();
InventoryManager.Instance.ShowToolTipContentLeft(content);
}
//当指向背包中的材料时
else
{
string content = transform.GetChild(0).GetComponent().Item.GetToolTipContent();
InventoryManager.Instance.ShowToolTipContentRight(content);
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (transform.childCount > 0)
{
if (transform.GetChild(0).GetComponent().Item.type == Item.ItemType.Equipment)
InventoryManager.Instance.HideForgeTipContent();
InventoryManager.Instance.HideToolTipContent();
}
}
}
为需要实现库存功能的格子Button添加Slot组件:
ItemUI类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ItemUI : MonoBehaviour
{
public int Amount { get; set; }
public Item Item { get; set; }
private TMP_Text ItemText;
private Image ItemImage;
private Vector3 AnimationScale = new Vector3(1.3f, 1.3f, 1.3f);
private float TargetScale = 1;
private float Smoothing = 3.0f;
public float durability = 100f;
private void Awake()
{
ItemText = GetComponentInChildren();
ItemImage = GetComponent();
}
private void Update()
{
if (transform.localScale.x != TargetScale)
{
float scale = Mathf.Lerp(transform.localScale.x, TargetScale, Smoothing * Time.deltaTime);
transform.localScale = new Vector3(scale, scale, scale);
if (Mathf.Abs(AnimationScale.x - TargetScale) <= 0.03f)
AnimationScale = Vector3.one;
}
}
///
/// 设置当前物品信息
///
///
///
public void SetItem(Item item, int amount = 1)
{
transform.localScale = AnimationScale;
Item = item;
Amount = amount;
//更新UI
ItemImage.sprite = Resources.Load(item.sprite);
if (item.capacity > 1)
ItemText.text = amount.ToString();
else
ItemText.text = "";
}
public void ReduceAmount(int amount = 1)
{
transform.localScale = AnimationScale;
Amount -= amount;
//更新UI
if (Item.capacity > 1)
ItemText.text = Amount.ToString();
else
ItemText.text = "";
}
public void AddAmount(int amount = 1)
{
transform.localScale = AnimationScale;
Amount += amount;
//更新UI
if (Item.capacity > 1)
ItemText.text = Amount.ToString();
else
ItemText.text = "";
}
public void SetAmount(int amount)
{
transform.localScale = AnimationScale;
Amount = amount;
if (Item.capacity > 1)
ItemText.text = Amount.ToString();
else
ItemText.text = "";
}
}
将挂载ItemUI组件的对象制成预制体,供Slot类动态加载:
游戏内的交易通过购买面板和售卖面板两个单例实现。
购买面板:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class BuyPanel : MonoBehaviour
{
//单例
private static BuyPanel instance;
public static BuyPanel Instance
{
get
{
return instance;
}
}
public Button btnBuy;
public Button btnBuyClose;
public TMP_Text txtStandardPrice;
public TMP_Text txtTotal;
public TMP_InputField txtPrice;
public TMP_InputField txtQuantity;
public float topCoefficient = 0.5f;
public float bottomCoefficient = 0.5f;
public static int StandardPrice { get; set; }
public static int ItemID { get; set; }
public static int ItemAmount { get; set; }
public static Item item;
public static KnapsackPanel knapsackPanel;
public static GameObject slot;
private int result = 0;
private int total = 0;
private int quantity = 0;
private int price = 0;
private void Start()
{
//默认以标准价格购买1个物品
price = StandardPrice;
txtPrice.text = price.ToString();
quantity = 1;
txtQuantity.text = quantity.ToString();
total = price * quantity;
txtTotal.text = "总价:" + total;
txtPrice.onValueChanged.AddListener((string value) =>
{
//保证输入为数字
if (int.TryParse(value, out result) && int.TryParse(txtQuantity.text, out result))
{
quantity = int.Parse(txtQuantity.text);
price = int.Parse(value);
total = price * quantity;
//更新界面
txtTotal.text = "总价:" + total;
}
});
txtQuantity.onValueChanged.AddListener((string value) =>
{
//保证输入为数字
if (int.TryParse(txtPrice.text, out result) && int.TryParse(value, out result))
{
quantity = int.Parse(value);
price = int.Parse(txtPrice.text);
//检测购买数量是否大于物品总数或小于1,并进行调整
if (quantity > ItemAmount)
quantity = ItemAmount;
//else if (quantity < 1)
// quantity = 1;
total = price * quantity;
//更新界面
txtQuantity.text = quantity.ToString();
txtTotal.text = "总价:" + total;
}
});
//购买逻辑
btnBuy.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
if (txtPrice.text == "" || txtQuantity.text == "")
NoticePanel.Instance.ShowNotice("请输入购买的单价和数量");
//检测购买价格是否低于标准价格一定倍数,并进行调整
else if (price < (int)(StandardPrice * (1 - bottomCoefficient)))
{
NoticePanel.Instance.ShowNotice("不应与标准价差距过大");
price = (int)(StandardPrice * (1 - bottomCoefficient));
total = price * quantity;
txtPrice.text = price.ToString();
txtTotal.text = "总价:" + total;
}
//检测购买价格是否高于标准价格一定倍数,并进行调整
else if (price > (int)(StandardPrice * (1 + topCoefficient)))
{
NoticePanel.Instance.ShowNotice("不应与标准价差距过大");
price = (int)(StandardPrice * (1 + topCoefficient));
total = price * quantity;
txtPrice.text = price.ToString();
txtTotal.text = "总价:" + total;
}
else if (ShopPanel.Instance.ConsumeMoney(total))
{
//角色背包物品减少
knapsackPanel.ReduceItem(item, ItemAmount, quantity);
//更新角色背包剩余物品数量
ItemAmount -= quantity;
//仓库物品增加
for (int i = 0; i < quantity; i++)
StoragePanel.Instance.StoreItem(item);
//角色金钱增加
knapsackPanel.rolePanel.EarnMoney(total);
//根据角色背包剩余物品数量限制购买数量
if (ItemAmount < quantity)
{
quantity = ItemAmount;
total = price * quantity;
//更新界面
txtQuantity.text = quantity.ToString();
txtTotal.text = "总价:" + total;
}
//整理背包和仓库
knapsackPanel.InventoryClear();
StoragePanel.Instance.InventoryClear();
}
});
btnBuyClose.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
CancelBuy();
});
txtStandardPrice.text = "标准价格:" + StandardPrice;
}
private void Update()
{
}
///
/// 实例化面板对象
///
///
public static void CreateBuy(GameObject slot)
{
//槽内没有物品或是和已打开购买面板的物品属于同种物品
if (slot.transform.childCount == 0 || slot.transform.GetChild(0).GetComponent().Item.id == ItemID)
return;
//点击的物品是装备类型
else if (slot.transform.GetChild(0).GetComponent().Item.type == Item.ItemType.Equipment)
return;
if (instance == null)
{
item = slot.transform.GetChild(0).GetComponent().Item;
ItemID = slot.GetComponent().GetItemID();
ItemAmount = slot.transform.parent.parent.GetComponent().CountSameIDSlot(item);
StandardPrice = item.standardPrice;
knapsackPanel = slot.transform.parent.parent.GetComponent();
GameObject res = Resources.Load("Panels/BuyPanel");
GameObject obj = Instantiate(res);
//设置父对象
obj.transform.SetParent(GameObject.Find("Canvas/Panels").transform, false);
instance = obj.GetComponent();
}
else
{
CancelBuy();
CreateBuy(slot);
}
}
public static void CancelBuy()
{
if (instance != null)
{
Destroy(instance.gameObject);
instance = null;
}
StandardPrice = 0;
ItemID = 0;
ItemAmount = 0;
}
}
售卖面板:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using System;
using UnityEngine.Events;
public class SellPanel : MonoBehaviour
{
//单例
private static SellPanel instance;
public static SellPanel Instance
{
get
{
return instance;
}
}
public Button btnSell;
public Button btnSellClose;
public TMP_Text txtStandardPrice;
public TMP_InputField txtPrice;
public float topCoefficient = 0.5f;
public float bottomCoefficient = 0.5f;
public static int StandardPrice { get; set; }
public static int ItemID { get; set; }
public static Item item;
public static KnapsackPanel knapsackPanel;
public static RolePanel rolePanel;
public static GameObject slot;
private static int choose = 1;
UnityAction a1;
// Start is called before the first frame update
void Start()
{
btnSell.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
if (txtPrice.text == "")
NoticePanel.Instance.ShowNotice("请输入卖出的价格");
//检测售出价格是否低于标准价格一定倍数,并进行调整
else if (int.Parse(txtPrice.text) < (int)(StandardPrice * (1 - bottomCoefficient)))
{
NoticePanel.Instance.ShowNotice("不应与标准价差距过大");
txtPrice.text = ((int)(StandardPrice * (1 - bottomCoefficient))).ToString();
}
//检测售出价格是否高于标准价格一定倍数,并进行调整
else if (int.Parse(txtPrice.text) > (int)(StandardPrice * (1 + topCoefficient)))
{
NoticePanel.Instance.ShowNotice("不应与标准价差距过大");
txtPrice.text = ((int)(StandardPrice * (1 + topCoefficient))).ToString();
}
else if (rolePanel.ConsumeMoney(int.Parse(txtPrice.text)))
{
//制造装备并添加到角色背包
CreatePanel.Instance.ForgeItem(ItemID);
//商店增加金钱
ShopPanel.Instance.EarnMoney(int.Parse(txtPrice.text));
//整理背包
knapsackPanel.InventoryClear();
//穿戴装备
knapsackPanel.Equip();
CancelSell();
}
//判断是否能继续制造
if (!CreatePanel.Instance.CanForge(ItemID))
CancelSell();
});
btnSellClose.onClick.AddListener(() =>
{
//提示面板清空
NoticePanel.Instance.HideNotice();
CancelSell();
});
txtStandardPrice.text = "标准价格:" + StandardPrice;
}
// Update is called once per frame
void Update()
{
}
///
/// 实例化面板对象
///
///
public static void CreateSell(GameObject slot)
{
//点击相同的装备
if (slot.transform.GetChild(0).GetComponent().Item.id == ItemID)
return;
if (CreatePanel.Instance.CanForge(slot.GetComponent().GetItemID()))
{
item = slot.transform.GetChild(0).GetComponent().Item;
ItemID = slot.GetComponent().GetItemID();
StandardPrice = item.standardPrice;
if (GameObject.Find("Role1Panel").GetComponent().alpha == 1)
{
choose = 1;
}
else if (GameObject.Find("Role2Panel").GetComponent().alpha == 1)
{
choose = 2;
}
else if (GameObject.Find("Role3Panel").GetComponent().alpha == 1)
choose = 3;
switch (choose)
{
case 1:
knapsackPanel = GameObject.Find("Knapsack1Panel").GetComponent();
rolePanel = GameObject.Find("Role1Panel").GetComponent();
break;
case 2:
knapsackPanel = GameObject.Find("Knapsack2Panel").GetComponent();
rolePanel = GameObject.Find("Role2Panel").GetComponent();
break;
case 3:
knapsackPanel = GameObject.Find("Knapsack3Panel").GetComponent();
rolePanel = GameObject.Find("Role3Panel").GetComponent();
break;
}
}
else
{
if (instance != null)
CancelSell();
return;
}
if (instance == null)
{
GameObject res = Resources.Load("Panels/SellPanel");
GameObject obj = Instantiate(res);
//设置父对象
obj.transform.SetParent(GameObject.Find("Canvas/Panels").transform, false);
instance = obj.GetComponent();
}
else
{
CancelSell();
CreateSell(slot);
}
}
public static void CancelSell()
{
if (instance != null)
{
Destroy(instance.gameObject);
instance = null;
}
StandardPrice = 0;
ItemID = 0;
}
}
游戏内循环通过Animator Controller的有限状态机实现,并通过FSM脚本与状态机外的其他对象进行通信。