好久都沒寫博客。是時候來更新一篇一直想寫的一個demo,前段時間網易出一個荒野行動。聽說還是unity做的,所以自己沒事做的時候就來寫的玩玩。由於是個人開發所以網絡端用的是一個Photon View插件來實現簡單的聯網同步操作。關於Photon View插件的運用,我會在接下來的幾篇博客來介紹一下,今天首先寫一個類似荒野行動的揹包。之前給大家介紹了MVC及MVVM框架的中心思想,所以這裏還是用MVC和響應式編程的思想來實現這樣一個揹包。首先截一下揹包的圖來講解揹包該如何實現。
首先角色靠近地上的物體。附近欄中會顯示地上的物體對應的UI icon。當打開揹包button的時候 附近欄中同時會出現地上物體對應的UI icon,當玩家拾取的時候角色會執行對應的動畫。今天我們只需要明白UI之間交互及UI與玩家數據的交互。按照響應式編程的思想。這裏應該有一個數據類來驅動UI的顯示工作,所以最開始寫揹包的時候,我們應該可以用簡單的GUI來顯示揹包數據,及對應的數據類,即在沒有UI素材的時候我們可以通過GUI來檢測我們的揹包數據邏輯的正確性。這種做法在早期的一些格子類型遊戲及卡牌(例如扎金花,鬥地主之類的),所以我們得先把揹包數據的邏輯跑通。在邏輯數據跑通之前我們的需要知道每種物體對應的編號,一般直接用一個數字來代替,如果我們只有10種類別的遊戲物體。每種種類只有10個左右的話,那麼我們可以這樣編號,11開始一直到19這樣代表一種裝備,21一直到29這樣代表另外一種裝備,依次類推一直到91一直到99.如果種類有100種的時候這個而每個種類有100種的時候,那麼總種類就應該是1000*100。這裏不多贅述這個問題,這個只是一個簡單的並且合理的分配一些ID而已。這裏我們儘量讓每種種類分配更多的數量,例如1001代表鞋子的一種,那麼第二個種類應該就是1002依次類推一直到1999,2001代表頭盔的一種,那麼依次類推就是2001到2999。首先建一個基本的數據類,將其定義爲:InventoryItem,首先它有幾個基本的字段:它的id(int),它的名字(string),它的屬性(是否可以被使用,是否可以被裝備)。它的類別(是武器,還是靴子,或者是揹包等等),它的重量。它的ui預設。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Inventory
{
/// <summary>
/// 基本的遊戲揹包
/// </summary>
///
[Serializable]
public class InventoryItem
{
/// <summary>
/// ItemId is uniqid of the Inventory name
/// </summary>
public int ItemId;
/// <summary>
/// describe this InventoryItem can be used
/// </summary>
public bool Usable;
/// <summary>
/// describe this InventoryItem can be used
/// </summary>
public bool Equipable;
/// <summary>
/// The name of current InventoryItem
/// </summary>
public string ItemName;
/// <summary>
/// This is Descripe The InventoryItem Type
/// </summary>
public InventoryItemType InventoryItemType;
/// <summary>
/// InventoryItem UI Prefab
/// </summary>
public GameObject UiPrefab;
/// <summary>
/// InventoryItem Weight
/// </summary>
public int Weight;
public bool CanMoveObject = true;
public bool CanSwapObject = true;
public InventoryItem(int id)
{
ItemId = id;
var item = InventoryConfigTable.Instance.GetItemById(id);
UiPrefab = item.UiPrefab;
ItemName = item.ItemName;
InventoryItemType = item.InventoryItemType;
Usable = item.Usable;
Equipable = item.Equipable;
Weight = item.Weight;
}
public InventoryItem()
{
}
public void Pick()
{
}
public void Use()
{
Debug.LogError("使用了" + ItemName);
//send ItemId message to Receiver
}
public void Equip()
{
Debug.LogError("裝備了" + ItemName);
//send ItemId message to Receiver
}
public void UnEquip()
{
Debug.LogError("卸掉了" + ItemName);
//send ItemId message to Receiver
}
public virtual void Swap()
{
}
public void Drop()
{
}
}
}
對應得枚舉類型爲InventoryItemType,定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Inventory
{
public enum InventoryItemType
{
None = 0,
Shoes, // 鞋子
Helmet, // 頭盔
Bodyarmor, // 防彈衣
Waistcoat, // 背心
Pants, // 褲子
Bandage, // 繃帶
BloodPack, // 血包
Rifle, // 步槍
Pistol, // 手槍
Ammo, // 彈藥
Bag, // 揹包
Clip // 彈夾
}
}
接下來就是寫一個關於基本的數據存儲類,如果在excel中理解的話,前面寫的就算是一行數據,那麼現在寫的就是一個數據的集合即很多行數據。所以這裏最起碼得有一個數組或者字典的東西。這裏我用的字典,這樣便於查詢方便。所以這裏基本操作基本上就有添加,刪除,查詢這些了。同樣這個類是作爲基類存在的。在喫雞裏面揹包項的添加存在幾種情況。例如鞋子只能添加一種,如果再添加另外一種就會被覆蓋原先的一種,但是子彈不會,彈夾不會。還有槍械只能添加2種等不同的情況,所以這些數據的添加和移除方式可能不一樣,所以我們需要將他們分開來處理。所以這裏的基類是很有必要的。
using System;
using System.Collections.Generic;
using Event;
using UnityEngine;
namespace Inventory
{
public abstract class InventoryBaseData
{
protected Dictionary<int, InventoryItem> Cache;
protected Dictionary<int, bool> CacheBools;
protected int TotalCount;
protected InventoryType InventoryType;
protected InventoryBaseData(int totalCount, InventoryType inventoryType)
{
TotalCount = totalCount;
InventoryType = inventoryType;
Cache = new Dictionary<int, InventoryItem>();
CacheBools = new Dictionary<int, bool>();
if (TotalCount > 0)
{
for (int i = 0; i < TotalCount; i++)
{
CacheBools.Add(i, false);
}
}
}
public virtual void AddToCache(InventoryItem item,ref int origin)
{
}
public virtual void RemoveFromCache(int index)
{
}
public virtual int GetItemFromCache(int index)
{
return 0;
}
/// <summary>
/// Test GUI
/// </summary>
public virtual void ShowGui(Vector2 originVector2, GUIStyle fontStyle)
{
int index = 0;
Vector2 v2 = originVector2;
foreach (var item in Cache)
{
var v1 = new Vector2(v2.x, v2.y + index * 30);
GUI.Label(new Rect(v1.x, v1.y, 200, 30), String.Format("位置:{0},名字:{1}", item.Key, item.Value.ItemName), fontStyle);
index++;
}
}
protected int GetEmptyIndex(bool isLimit)
{
if (isLimit)
{
for (int i = 0; i < TotalCount; i++)
{
bool b = CacheBools[i];
if (!b)
{
return i;
}
}
return -1;
}
int index = 0;
while (true)
{
if (!CacheBools.ContainsKey(index))
{
CacheBools.Add(index, true);
return index;
}
bool b = CacheBools[index];
if (!b)
{
return index;
}
index++;
}
}
protected int GetIndexByitemType(InventoryItemType itemItemType)
{
foreach (var item in Cache)
{
if (item.Value.InventoryItemType == itemItemType)
return item.Key;
}
return -1;
}
}
}
這裏的枚舉類型爲:
public enum InventoryType
{
None = -1,
ArticleInventory,
ClothInventory,
EquipInventory,
GunInventory
}
這裏我簡單把揹包數據分爲2類,一類是槍械,那麼剩下的就是另外一種類別了。
首先分析一些槍械這個類別,第一一個玩家只能存在2個槍械,這個是不分種類,可以2把同樣的槍械,第二,槍械只能被激活一把。所以需要重寫AddToCache方法,另外需要重寫添加一個SwitchItem方法。
public override void AddToCache(InventoryItem item,ref int origin)
{
int index = 0;
int count = Cache.Count;
if (count <= 1)
{
index = GetEmptyIndex(true);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
if (count == 0)
{
GunIndex = 0;
CurrentGunInventoryItem = item;
}
}
else if (count == 2)
{
origin -= Cache[GunIndex].Weight;
Cache.Remove(GunIndex);
Cache.Add(GunIndex, item);
CacheBools[GunIndex] = true;
GunIndex = 0;
index = GunIndex;
CurrentGunInventoryItem = item;
}
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
}
首先判斷槍械揹包中存在幾把槍械,如果<=1的時候,就直接添加就行了,如果==2的時候就替換已經激活的那把槍械。
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
public void SwitchItem(int preIndex,int nextIndex)
{
if (Cache.ContainsKey(preIndex)&& Cache.ContainsKey(nextIndex))
{
var preItem = Cache[preIndex];
var nextItem = Cache[nextIndex];
Cache[preIndex] = nextItem;
Cache[nextIndex] = preItem;
CurrentGunInventoryItem = Cache[preIndex];
}
}
槍械之間的交換就是字典中value的值的指針的交換而已。using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Event;
using Tool;
using UI;
using UnityEngine;
namespace Inventory
{
public class InventoryGunData : InventoryBaseData
{
protected int GunIndex;
protected InventoryItem CurrentGunInventoryItem;
public InventoryGunData(int totalCount, InventoryType inventoryType) : base(totalCount, inventoryType)
{
GunIndex = -1;
CurrentGunInventoryItem = null;
}
public override void AddToCache(InventoryItem item,ref int origin)
{
int index = 0;
int count = Cache.Count;
if (count <= 1)
{
index = GetEmptyIndex(true);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
if (count == 0)
{
GunIndex = 0;
CurrentGunInventoryItem = item;
}
}
else if (count == 2)
{
origin -= Cache[GunIndex].Weight;
Cache.Remove(GunIndex);
Cache.Add(GunIndex, item);
CacheBools[GunIndex] = true;
GunIndex = 0;
index = GunIndex;
CurrentGunInventoryItem = item;
}
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
}
public override void ShowGui(Vector2 originVector2, GUIStyle fontStyle)
{
base.ShowGui(originVector2, fontStyle);
if (CurrentGunInventoryItem != null)
GUI.Label(new Rect(1150, 0, 300, 100), String.Format("Pos:{0},Name:{1}", GunIndex, CurrentGunInventoryItem.ItemName));
}
public void SwitchItem(int preIndex,int nextIndex)
{
if (Cache.ContainsKey(preIndex)&& Cache.ContainsKey(nextIndex))
{
var preItem = Cache[preIndex];
var nextItem = Cache[nextIndex];
Cache[preIndex] = nextItem;
Cache[nextIndex] = preItem;
CurrentGunInventoryItem = Cache[preIndex];
}
}
}
}
接下來就是編寫除了槍械之外的數據揹包類,將其定義爲InventoryNormalData,同樣它需繼承InventoryBaseData這樣一個基類的方法。這裏繼承了AddToCache、RemoveFromCache和GetItemFromCache這3個方法。AddToCache存在是否忽略同一類型的物品只能添加一種這樣的情況。
public override void AddToCache(InventoryItem item,ref int origin)
{
var itemType = item.InventoryItemType;
int index = 0;
if (!_ignoreSameType)//不忽略同一類型(即同一類型的物品只能存在一個)
{
if (!_inventoryCount.ContainsKey(itemType))
{
_inventoryCount.Add(itemType, 1);
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
else
{
if (_inventoryCount[itemType] >= 1)
{
index = GetIndexByitemType(itemType);
if (index >= 0)
{
origin -= Cache[index].Weight;
Cache.Remove(index);
Cache.Add(index, item);
CacheBools[index] = true;
}
}
}
}
else
{
if (!_inventoryCount.ContainsKey(itemType))
{
_inventoryCount.Add(itemType, 1);
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
else
{
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
}
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
}
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
數據更新及時通知ui發生更新,把這句去掉之後代碼也不會有大問題,所以前期這裏測試數據邏輯的時候ui的更新就沒必要了。
public override void RemoveFromCache(int index)
{
if (!Cache.ContainsKey(index))
return;
InventoryItemType itemType = Cache[index].InventoryItemType;
Cache.Remove(index);
CacheBools[index] = false;
_inventoryCount[itemType] -= 1;
if (_inventoryCount[itemType] <= 0)
{
_inventoryCount.Remove(itemType);
}
}
RemoveFromCache只是簡單的從字典裏面移除一個揹包項。具體的代碼實現如下:
using System.Collections.Generic;
using Event;
using Inventory;
using Tool;
using UI;
namespace Inventory
{
public class InventoryNormalData: InventoryBaseData
{
private bool _ignoreSameType;
private Dictionary<InventoryItemType, int> _inventoryCount;
private bool _isLimit;
public InventoryNormalData(int totalCount, bool ignoreSameType,bool isLimit, InventoryType inventoryType) : base(totalCount, inventoryType)
{
_isLimit = isLimit;
_ignoreSameType = ignoreSameType;
_inventoryCount = new Dictionary<InventoryItemType, int>();
}
public override void AddToCache(InventoryItem item,ref int origin)
{
var itemType = item.InventoryItemType;
int index = 0;
if (!_ignoreSameType)//不忽略同一類型(即同一類型的物品只能存在一個)
{
if (!_inventoryCount.ContainsKey(itemType))
{
_inventoryCount.Add(itemType, 1);
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
else
{
if (_inventoryCount[itemType] >= 1)
{
index = GetIndexByitemType(itemType);
if (index >= 0)
{
origin -= Cache[index].Weight;
Cache.Remove(index);
Cache.Add(index, item);
CacheBools[index] = true;
}
}
}
}
else
{
if (!_inventoryCount.ContainsKey(itemType))
{
_inventoryCount.Add(itemType, 1);
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
else
{
index = GetEmptyIndex(_isLimit);
if (index >= 0)
{
Cache.Add(index, item);
CacheBools[index] = true;
}
}
}
EventManager.TriggerEvent(new IInventoryUIAddEvent(item, InventoryType, index));
}
public override void RemoveFromCache(int index)
{
if (!Cache.ContainsKey(index))
return;
InventoryItemType itemType = Cache[index].InventoryItemType;
Cache.Remove(index);
CacheBools[index] = false;
_inventoryCount[itemType] -= 1;
if (_inventoryCount[itemType] <= 0)
{
_inventoryCount.Remove(itemType);
}
}
public override int GetItemFromCache(int index)
{
if (Cache.ContainsKey(index))
{
return Cache[index].ItemId;
}
return -1;
}
}
}
定義完了一些小揹包項之後就需要寫一個管理大揹包項的類了,將其定義爲:InventoryModel。這個總的揹包管理類中首先定義幾個小的揹包項字段:
private InventoryBaseData _clothBaseData;
private InventoryBaseData _articleBaseData;
private InventoryBaseData _equipBaseData;
private InventoryBaseData _gunBaseData;
然後初始化的方法,定義爲Load
public static InventoryModel Load()
{
return new InventoryModel(3,5,2);
}
這裏Load將其定義爲靜態的,因爲有時候我們需要從本地讀取數據,所以這裏暫時寫成new一個新的數據實體類了。所以構造函數裏面就是對其進行new 構造而已。
public InventoryModel(int clothCount,int articleCount,int gunCount)
{
_clothBaseData = new InventoryNormalData(clothCount, false, true, InventoryType.ClothInventory);
_articleBaseData = new InventoryNormalData(articleCount, false, true, InventoryType.ArticleInventory);
_equipBaseData = new InventoryNormalData(default(int), true, false, InventoryType.EquipInventory);
_gunBaseData = new InventoryGunData(gunCount, InventoryType.GunInventory);
_currentWeight = 0;
_totalWeight = 120;
}
這個類的職責就是簡單來說就是增刪改查了。所以會存在四個方法。所有的數據類基本都存在這四個方法。AddItem,RemoveItem,GetItem,SwitchGunItem。
public void AddItem(int id)
{
InventoryItem item = new InventoryItem(id);
OnHandlerAddItem(item);
}
Add方法參數是傳進來一個id之後然後對其進行判斷,這個判斷操作在OnHandlerAddItem裏面進行了。
public void RemoveItem(InventoryType inventoryType, int index)
{
OnHandlerDropItem(inventoryType, index);
}
RemoveItem方法第一個參數是小揹包的類型,第二個參數是在小揹包類型中位置的索引。 public int GetItem(InventoryType inventoryType,int index)
{
switch (inventoryType)
{
case InventoryType.ClothInventory:
return _clothBaseData.GetItemFromCache(index);
case InventoryType.ArticleInventory:
return _articleBaseData.GetItemFromCache(index);
case InventoryType.EquipInventory:
return _equipBaseData.GetItemFromCache(index);
}
return -1;
}
GetItem方法主要獲得對應小揹包中索引爲index的揹包項的id。
public void SwitchGunItem(int preIndex, int nextIndex)
{
OnHandlerSwitchGunItem(preIndex,nextIndex);
}
SwitchGunItem方法主要是交換索引爲preindex和nextindex上面的槍械。一些私有方法就不一一贅述了,整個類如下:
using System;
using Assets.Scripts.Tool;
using BaseTable;
using Event;
using Tool;
using UI;
using UnityEngine;
namespace Inventory
{
/// <summary>
/// 揹包模型層
/// </summary>
public class InventoryModel
{
private InventoryBaseData _clothBaseData;
private InventoryBaseData _articleBaseData;
private InventoryBaseData _equipBaseData;
private InventoryBaseData _gunBaseData;
private int _totalWeight;
private int _currentWeight;
public Action<int> TotalWeightCallBack { set; get; }
public Action<int> CurrentWeightCallBack { set; get; }
public static InventoryModel Load()
{
return new InventoryModel(3,5,2);
}
public InventoryModel(int clothCount,int articleCount,int gunCount)
{
_clothBaseData = new InventoryNormalData(clothCount, false, true, InventoryType.ClothInventory);
_articleBaseData = new InventoryNormalData(articleCount, false, true, InventoryType.ArticleInventory);
_equipBaseData = new InventoryNormalData(default(int), true, false, InventoryType.EquipInventory);
_gunBaseData = new InventoryGunData(gunCount, InventoryType.GunInventory);
_currentWeight = 0;
_totalWeight = 120;
}
public void AddItem(int id)
{
InventoryItem item = new InventoryItem(id);
OnHandlerAddItem(item);
}
public void RemoveItem(InventoryType inventoryType, int index)
{
OnHandlerDropItem(inventoryType, index);
}
public int GetItem(InventoryType inventoryType,int index)
{
switch (inventoryType)
{
case InventoryType.ClothInventory:
return _clothBaseData.GetItemFromCache(index);
case InventoryType.ArticleInventory:
return _articleBaseData.GetItemFromCache(index);
case InventoryType.EquipInventory:
return _equipBaseData.GetItemFromCache(index);
}
return -1;
}
public void SwitchGunItem(int preIndex, int nextIndex)
{
OnHandlerSwitchGunItem(preIndex,nextIndex);
}
private void AddTotalLoadCount(int value)
{
_totalWeight += value;
if (TotalWeightCallBack != null)
TotalWeightCallBack.Invoke(_totalWeight);
}
private bool TryAddCurrentLoadCount(int value)
{
if (_currentWeight < _totalWeight)
{
_currentWeight += value;
if (CurrentWeightCallBack != null)
CurrentWeightCallBack.Invoke(_currentWeight);
return true;
}
return false;
}
private void MinusCurrentLoadCount(int value)
{
_currentWeight -= value;
if (CurrentWeightCallBack != null)
CurrentWeightCallBack.Invoke(_currentWeight);
}
public void ShowGui(GUIStyle fontStyle)
{
_articleBaseData.ShowGui(new Vector2(0, 0), fontStyle);
_clothBaseData.ShowGui(new Vector2(400, 0), fontStyle);
_equipBaseData.ShowGui(new Vector2(600, 0), fontStyle);
_gunBaseData.ShowGui(new Vector2(800, 0), fontStyle);
}
private void OnHandlerSwitchGunItem(int preIndex, int nextIndex)
{
var inventoryGunData = _gunBaseData as InventoryGunData;
if (inventoryGunData != null)
inventoryGunData.SwitchItem(preIndex, nextIndex);
EventManager.TriggerEvent(new IGunInventoryUISwitchEvent(preIndex,nextIndex));
EventManager.TriggerEvent(new ICharacterSwapGun(preIndex, nextIndex));
}
private void OnHandlerAddItem(InventoryItem item)
{
var itemtype = item.InventoryItemType;
if (IsCloth(itemtype) && TryAddCurrentLoadCount(item.Weight))
{
_clothBaseData.AddToCache(item, ref _currentWeight);
var value = ToolHelp.GetSkinPairByInventoryItem(item);
EventManager.TriggerEvent(new ICharacterChangeSkin(value.Key,value.Value));
return;
}
if (IsArticle(itemtype))
{
if (IsBag(itemtype))
{
var assetItem = BagDatabase.Instance.GetAssetByBagId(item.ItemId);
if (assetItem != null)
{
_articleBaseData.AddToCache(item, ref _currentWeight);
AddTotalLoadCount(assetItem.Capacity);
EventManager.TriggerEvent(new ICharacterPickUpBag(assetItem.BagId % 10));
}
}
else
{
if (TryAddCurrentLoadCount(item.Weight))
{
_articleBaseData.AddToCache(item, ref _currentWeight);
var value = ToolHelp.GetSkinPairByInventoryItem(item);
EventManager.TriggerEvent(new ICharacterChangeSkin(value.Key, value.Value));
}
}
return;
}
if (IsEquip(itemtype)&& TryAddCurrentLoadCount(item.Weight))
{
_equipBaseData.AddToCache(item, ref _currentWeight);
return;
}
if (IsGun(itemtype) && TryAddCurrentLoadCount(item.Weight))
{
_gunBaseData.AddToCache(item, ref _currentWeight);
EventManager.TriggerEvent(new ICharacterPickupGun(item.ItemId));
}
}
private void OnHandlerDropItem(InventoryType inventoryType,int index)
{
switch (inventoryType)
{
case InventoryType.ClothInventory:
_clothBaseData.RemoveFromCache(index);
break;
case InventoryType.ArticleInventory:
_articleBaseData.RemoveFromCache(index);
break;
case InventoryType.EquipInventory:
_equipBaseData.RemoveFromCache(index);
break;
}
}
private bool IsCloth(InventoryItemType itemtype)
{
return (itemtype == InventoryItemType.Shoes) || (itemtype == InventoryItemType.Waistcoat) ||
(itemtype == InventoryItemType.Pants);
}
private bool IsArticle(InventoryItemType itemtype)
{
return (itemtype == InventoryItemType.Helmet) || (itemtype == InventoryItemType.Bodyarmor)|| (itemtype == InventoryItemType.Bag);
}
private bool IsEquip(InventoryItemType itemtype)
{
return (itemtype == InventoryItemType.Ammo) || (itemtype == InventoryItemType.BloodPack) ||
(itemtype == InventoryItemType.Bandage) || (itemtype == InventoryItemType.Clip);
}
private bool IsGun(InventoryItemType itemType)
{
return (itemType == InventoryItemType.Pistol) || (itemType == InventoryItemType.Rifle);
}
private bool IsBag(InventoryItemType itemType)
{
return itemType == InventoryItemType.Bag;
}
}
}
這個裏面可能存在一些通知事件,在測試數據的時候可以將它註釋掉,因爲數據在發生變化的時候肯定會引起ui或者角色屬性的變化,這是必然的。這就存在2個模塊甚至代碼之間在發生數據的傳輸或者交換。這裏採用消息處理是爲了避免2個模塊之間交互的時候耦合性太強。一般耦合性太強的時候都會想到用第三個類來中間搭橋來同時持有這2個類的引用,從而來減低耦合性。測試這個揹包的邏輯的時候可以直接建一個簡單的類,然後調用這個數據實體類中的方法即可,直接用GUI來測試邏輯的正確性。下一節編寫一個簡單的數據查詢類,這裏以ScriptableObject類爲基礎來編寫編輯器功能。如有疑問可以聯繫我。qq:1850761495