C# 了解我的游戏物品和库存系统自定义类的问题
对不起,没有介绍我不能提问。(如果您不确定是否要全部阅读,我仍会尝试问一个问题,问题是如果我尝试更改我的项目属性,它将应用于所有其他相同的项目,如何解决此问题?) 我有类C# 了解我的游戏物品和库存系统自定义类的问题,c#,unity3d,C#,Unity3d,对不起,没有介绍我不能提问。(如果您不确定是否要全部阅读,我仍会尝试问一个问题,问题是如果我尝试更改我的项目属性,它将应用于所有其他相同的项目,如何解决此问题?) 我有类Item,带有一些属性和变量,比如itemCost,耐久性等等 类武器继承物品 我有一个ItemGenerator类,它初始化一个数组中的所有项。它包含如下功能: private static Weapon CreateUniqueWeaponForItemList(int ID, int itemLevel, ..... s
Item
,带有一些属性和变量,比如itemCost
,耐久性
等等
类武器
继承物品
我有一个ItemGenerator
类,它初始化一个数组中的所有项。它包含如下功能:
private static Weapon CreateUniqueWeaponForItemList(int ID, int itemLevel,
..... string description) {
Weapon item = new Weapon();
item.ID = ID;
item.ItemLevel = itemLevel;
...
...
item.Description = description
return item;
}
差不多吧。
此项目列表在游戏开始时初始化。
我有一个包含所有项目的项目数组
public static Item[] ItemList = new Item[200];
下面是游戏中所有独特项目的列表,由上面的函数创建:
ItemList[1] = CreateUniqueWeaponForItemList(1, 5, ....., "this is item!");
ItemList[2] = ....
就这样。
现在这个效果很好。生成项目时,我只使用项目ID来指定要创建的项目。保存和加载也很容易,只需将项目的ID
存储在PlayerPrefs
中即可
但当我开始添加额外的功能(如物品升级、损坏升级等)时,我意识到这种架构很糟糕
如果玩家有两个或两个以上相同的物品,问题就从这里开始。如果我试图更改项目
属性,它们将应用于项目列表[ID]
,而不是我想要更改的项目
我想我需要把代码粘贴在这里,这样才能清楚。我有库存系统,有
private List_inventory=new List()代码>在Player
类中。我有一个宝箱,可以从ItemList
中获取物品来创建一些
loot.Add(ItemGenerator.CreateUniqueItem(2));
loot
在cost
类中是Item
变量。下面是对CreateUniqueItem
public static Item CreateUniqueItem(int ID) {
if (ID > ItemList.Length) {
return null;
}
if (ItemList[ID] != null) {
return ItemList[ID];
}
else {
return ItemList[0];
}
}
创建物品后,玩家可以将其抓取到库存中。我只是\u库存。添加(项目)代码>,例如项目
是项目列表[2]
Player.Insntance.Inventory.Add(chest.loot[2]);
chest.loot.RemoveAt(2);
战利品是
public List<Item> loot = new List<Item>();
武器等级相同,但有额外的变量,如伤害
public class Weapon : Item
{
private int _maxDamage;
public Weapon() {
_maxDamage = 0;
}
public int MaxDamage {
get { return _maxDamage; }
set { _maxDamage = value; }
}
}
如有必要,我可以在GitHub上提供完整的代码列表。但我想,我贴在上面的代码太多了。我希望我没有忘记任何事情
如果这个问题微不足道,我不会感到惊讶,但出于某种原因,我无法理解它,它会引起头痛
如果文本太多,我很抱歉,但我不能缩短
也为我糟糕的英语拼写感到抱歉
提前感谢。您正在数组中存储引用,因此只有一个项目存在。解决这个问题的方法有很多。本质上,您的“项目列表”几乎就像一个模板列表。有点像柏拉图的完美形式理论。每当你在游戏中携带物品时(无论是在箱子里还是玩家的物品清单中),你都想克隆该物品
将您的剑类物品阵列想象为“剑的概念”,每当胸前有剑时,我们都会“克隆”该模板。箱子现在包含模板的副本。显然,当玩家拿起剑时,我们只是从一个容器转移到另一个容器(我们不会把剑留在箱子里,而是转移到玩家的库存中)
那么,我们如何才能做到这一点呢?我们可以用克隆技术。因此,您的项目基类可以如下所示:
// Not tying ourselves just to weapons here... what about food, clothes, etc..?
public abstract class Item
{
public int ID { get; set; }
public string Name { get; set; }
// Let's have a copy constructor
public Item(Item other)
{
ID = other.ID;
Name = other.Name;
}
// This part is important!
public abstract Item Clone();
}
好。我们有一个项目。它有一些基本性质。让我们做一件武器
public class Weapon : Item
{
public int Damage { get; set; }
// also has a copy constructor
public Weapon(Weapon other) : base(other) // Item copies it's stuff!
{
Damage = other.Damage;
}
// Need to implement this:
public override Item Clone() { return new Weapon(this); }
}
你现在可以得到一大堆其他东西(食物、衣服、脏杂志、柏拉图著作等等)
现在,您可以拥有这些项目
实例的数组,并且无论何时您想要在游戏中将一个实例放在箱子中,您只需执行以下操作:
Item newItem = itemList[index].Clone();
这将有效地创建项目的新实例。食物将被正确地克隆。因此,如果玩家有一把克隆剑,现在可以克隆它,并增加它的伤害-因为它是一把不同的剑(但基于柏拉图的原始剑!)
这不是解决这个问题的唯一方法,当项目有多种不同类型的属性并且可能有数百种细微的变化时,继承树可能会变得非常混乱。在这些情况下,我倾向于基于组件的设计,但这有点超出了这个答案的范围。如果从ScriptableObject派生项,您可能会发现这个问题会变得更简单
ScriptableObject(如GameObject)必须显式实例化,以便在处理实例和ScriptableObject资产时能够清楚地显示。另一件好事是,您可以创建模板资产(“+1剑”、“隐形斗篷”等),手动编辑(设置单个项目属性等)并检查它们。此外,所有枯燥的工作,如管理实例ID和手动序列化,都已为您完成 考虑只使用一个item类。通过使用枚举切换项目类型,我认为这样更灵活。
我正在使用类似以下代码的东西,因为使用继承是一件混乱的事情。。。苏欧^^
嗯。。。此示例适用于unity用户;)
使用UnityEngine;
使用System.Collections.Generic;
使用系统集合;
公共类玩家:单一行为
{
公共列表项=新列表();
void Start()
{
Test();
AddItem(新的ItemGenerator().GetRandomItem());
附加项(新项目生成器(项目类型.武器,“新酷武器项目”,UnityEngine.Random.Range(1100),UnityEngine.Random.Range(1100));
项目=新项目();
item.ItemType=ItemType.Quest;
增编(项目);
附加项(新项());
AddItem(新的ItemGenerator().GetRandomItem(“随机测试项目1 2 3”));
AddItem(item.Clone());
}
公共无效附加项(项目)
{
项目。添加(项目);
}
无效测试()
{
Log(“测试开始”);
//示例灵活性
项目=新项目();
item.ItemType=ItemType.Answare;
if(item.ItemType)==
Item newItem = itemList[index].Clone();
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public class Player : MonoBehaviour
{
public List<Item> Items = new List<Item>();
void Start()
{
Test();
AddItem( new ItemGenerator().GetRandomItem());
AddItem( new ItemGenerator(ItemType.Weapon, "New Cool Weapon Item", UnityEngine.Random.Range(1,100), UnityEngine.Random.Range(1,100)));
Item item = new Item();
item.ItemType = ItemType.Quest;
AddItem(item);
AddItem(new Item());
AddItem( new ItemGenerator().GetRandomItem("Random Test Item 1 2 3"));
AddItem( item.Clone());
}
public void AddItem(Item item)
{
Items.Add(item);
}
void Test()
{
Debug.Log("Test starts");
// example flexibility
Item item = new Item();
item.ItemType = Itemtype.Weapon;
if(item.ItemType == Itemtype.Weapon)
Debug.Log(item.WeaponProperties.GetDps(item));
item.ItemType = Itemtype.Armor;
if(item.ItemType == Itemtype.Armor)
Debug.Log(item.ArmorProperties.Defense);
switch(item.ItemType)
{
case ItemType.Weapon: Debug.Log("Do Weapon Stuff - instantiate at weapon spawnpoint"); break;
case ItemType.Armor: Debug.Log("Do Armor Stuff - instantiate at spawnpoint"); break;
default: Debug.Log("what ever..."); break;
}
// example item generator
Item item2 = new ItemGenerator(ItemType.Weapon);
Debug.Log(item2.Name);
Item item3 = new ItemGenerator(ItemType.Armor, "New Armor Item");
Debug.Log(item3.Name);
item3.ItemType = ItemType.Weapon;
item3.Name = "Ultra Sword";
Debug.Log(item3.Name);
Item item4 = new ItemGenerator(ItemType.Weapon, "New Weapon Item", UnityEngine.Random.Range(1,100), UnityEngine.Random.Range(1,100));
Debug.Log(item3.Name);
Item item5 = new ItemGenerator().GetRandomItem();
Debug.Log(item2.Name);
Debug.Log(item2.ItemType);
// clone item
Item item6 = item5.Clone();
Debug.Log(item2.Name);
Debug.Log("Test ends");
}
}
public enum ItemType
{
Weapon, Armor, Consumable, Quest, Key //...
}
public class Item // :ScriptableObject
{
public string Name = "FooItem";
public ItemType Itemtype;
public Attributes Attributes = new Attributes();
public WeaponProperties WeaponProperties = new WeaponProperties();
public ArmorProperties ArmorProperties = new ArmorProperties();
public Item Clone()
{
return (Item)MemberwiseClone();
}
}
[System.Serializable]
public class WeaponProperties
{
public int MinimalDamage = 10;
public int MaximalDamage= 20;
public float Speed = 1.5f;
public static float GetDps(Item weapon)
{
return Mathf.RoundToInt(((weapon.WeaponProperties.MinimalDamage + weapon.WeaponProperties.MaximalDamage) * 0.5f) / weapon.WeaponProperties.Speed);
}
}
[System.Serializable]
public class ArmorProperties
{
public int Defense = 25;
}
[System.Serializable]
public class Attributes
{
public int Strength = 25;
public int Stamina = 20;
}
public class ItemGenerator : Item
{
public ItemGenerator(ItemType itemType) : this(itemType, "NewNamelessItem")
{
}
public ItemGenerator(ItemType itemType, string name)this(itemType, name, 0, 0)
{
}
public ItemGenerator(ItemType itemType, string name, int strength, int stamina) : this(itemType, name, strength, stamina, 0)
{
}
public ItemGenerator(ItemType itemType, string name, int strength, int stamina, int defense)
{
Name = name;
Attributes.Strength = strength;
Attributes.Stamina = stamina;
switch(item.ItemType)
{
case ItemType.Weapon:
break;
case ItemType.Armor:
ArmorProperties.Defense = defense;
break;
default: Debug.Log("what ever..."); break;
}
}
public Item GetRandomItem()
{
return GetRandomItem( "New Random Item");
}
public Item GetRandomItem(string name)
{
Name = name;
Attributes.Strength = Random.Range(0,100);
Attributes.Stamina = Random.Range(0,100);
var values = Enum.GetValues(typeof(ItemType));
ItemType = (ItemType)values.GetValue(Random.Range(0, values.Length));
switch(item.ItemType)
{
case ItemType.Weapon:
break;
case ItemType.Armor:
ArmorProperties.Defense = Random.Range(0,100);
break;
default: Debug.Log("what ever..."); break;
}
return this;
}
}