[英]C# polymorphism with cloning
首先讓我解釋一下我要實現的目標。
我正在制作一款游戲,玩家可以在游戲中拾取道具(由於某種原因,我稱其為“戰利品”)。 所以這是我的Loot類的一個非常基本的形式:
public class Loot : Sprite
{
//Properties and fields...
public Loot(/*parameters...*/)
{
}
public virtual OnPickUp(Player player)
{
}
}
Player和Sprite是我的課程。 這是我的問題:我的Sprite類擁有一個位置(Vector2,它是XNA中表示矢量的結構),並且根據我對C#的工作原理的理解,復制兩個Sprite會復制彼此的引用 ,因此,每當我更改位置時,也會改變另一個。
每當生成戰利品時,我都會擁有一類持有可能生成的戰利品的類,它會隨機返回一個戰利品,並將戰利品復制並顯示在屏幕上,但是一旦我獲得多個同類型的戰利品,它就會由於參考副本問題而混亂(兩者將共享同一位置,並且只有一個位置可見)。
因此,當我需要生成新的戰利品時,我嘗試創建一個新的Loot對象,因此我必須為構造函數提供多個參數,以這種方式輕松復制戰利品:(讓我們假裝為spawn可以是從Loot類派生的任何類型,例如HealthPack或其他任何東西)
Loot spawning = new Loot(toSpawn.Position, toSpawn.Color /*etc...*/);
在我決定實施“ OnPickUp”之前,它看起來一直不錯。 由於我創建了一個新的Loot對象而不是適當的子類,因此toSpawn的OnPickUp函數的功能將消失,拾取贓物最終將無濟於事(它只會調用基類Loot的empty函數)。
顯然,我在這里做錯了。 我沒有太多的編程經驗,甚至沒有C#的經驗,所以我真的不知道如何解決這個問題。 我嘗試使用代表OnPickUp功能的Action <Player>對象,它可以工作,但仍然對我有很多限制(因為我必須將靜態函數作為Action <Player>傳遞,因此限制了我使用播放器的信息參數,並阻止我使用子類的特定信息)。
因此,最后,我的問題確實是: 允許子類具有重載函數,但仍然能夠克隆基類及其屬性的方法是什么更好的設計?
謝謝您的寶貴時間。
如果尚不清楚(我知道還不清楚),請在評論中問我,我將嘗試更詳細地描述我的問題。
讓您的Loot類實現ICloneable
public abstract class Loot : ICloneable
{
public virtual object Clone()
{
Type type = this.GetType();
Loot newLoot = (Loot) Activator.CreateInstance(type);
//do copying here
return newLoot;
}
}
Vector2
是一個struct
而不是一個class
,因此您的原始問題聽起來像是由於持有對同一個Loot對象的兩個引用,而不是擁有對同一個位置的引用的兩個不同的Loot對象。
負責創建Loot對象的類應該創建相關Loot子類的新實例,而不是創建基類。 在您的設計中,Loot可能應該是一個抽象類甚至是一個接口,並且您應該使用抽象工廠模式來創建所需類型的Loot對象。
例如:
class LootFactory
{
const int numLootTypes = 3;
public Loot CreateLoot(Vector2 position)
{
Random rand = new Random();
int lootIndex = rand.Next(numLootTypes);
if (lootIndex == 0)
{
return new HealthPack(position);
}
if (lootIndex == 1)
{
...
}
...
}
}
我認為我一定會對此問題有所遺漏,因為Vector2
是結構而不是類。 將一個Vector2
直接分配給另一個Vector2
會自動創建一個副本。
var v2a = new Vector2(10.0f, 20.0f);
var v2b = v2a; //`v2b` is a new instance of `Vector2` distinct from `v2a`.
您的問題聽起來像PossibleLoots
類沒有在隨機分配每個所創建的Loot
實例的位置。
我假設您的游戲邏輯說的是“每個級別最多可以產生10個掠奪物”,因此您的PossibleLoots
類在啟動時會創建所有可能的Loot
物對象,但是除非被要求“產生一個搶劫”。
所以,如果是的話,這不是您所需要的嗎?
public class PossibleLoots
{
private IList<Loot> _loots = new List<Loot>();
public PossibleLoots(int maxLoots)
{
for (var i = 0; i < maxLoots; i++)
{
_loots.Add(new Loot(this.GetRandomPosition()));
}
}
private Vector2 GetRandomPosition()
{
// Your logic here to create suitable locations for loot to appear
}
// Rest of your `PossibleLoots` code
// to spawn each `Loot` and to deplete the `_loots`
// collection when the player picks up each `Loot`
}
如果我錯過了這個問題的重點,請告訴我。
對我來說,聽起來真的像是您在以錯誤的方式前進。 盡管給出的答案會奏效,但這不是您必須要做的。
如果您想生成一個新的戰利品,並且希望它是可能的各種類型的戰利品,那么您的Loot類的構造函數應該可以完成所有工作。 不需要克隆或ICloneable。
當創建一個新的戰利品對象時,它應該隨機成為它的戰利品類型,而無需在所有地方保留所有可能類型的列表並從中進行克隆。 這樣,新的戰利品對象將具有自己的位置和行為,並且可以完全按您期望的方式工作。
還是我只是誤解了您要完成的工作?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.