繁体   English   中英

C#多态性与克隆

[英]C# polymorphism with cloning

首先让我解释一下我要实现的目标。

我正在制作一款游戏,玩家可以在游戏中拾取道具(由于某种原因,我称其为“战利品”)。 所以这是我的Loot类的一个非常基本的形式:

public class Loot : Sprite
{
    //Properties and fields...

    public Loot(/*parameters...*/)
    {
    }

    public virtual OnPickUp(Player player)
    {
    }
}

PlayerSprite是我的课程。 这是我的问题:我的Sprite类拥有一个位置(Vector2,它是XNA中表示矢量的结构),并且根据我对C#的工作原理的理解,复制两个Sprite会复制彼此的引用 ,因此,每当我更改位置时,也会改变另一个。

每当生成战利品时,我都会拥有一类持有可能生成的战利品的类,它会随机返回一个战利品,并将战利品复制并显示在屏幕上,但是一旦我获得多个同类型的战利品,它就会由于参考副本问题而混乱(两者将共享同一位置,并且只有一个位置可见)。

因此,当我需要生成新的战利品时,我尝试创建一个新的Loot对象,因此我必须为构造函数提供多个参数,以这种方式轻松复制战利品:(让我们假装为spawn可以是从Loot类派生的任何类型,例如HealthPack或其他任何东西)

Loot spawning = new Loot(toSpawn.Position, toSpawn.Color /*etc...*/);

在我决定实施“ OnPickUp”之前,它看起来一直不错。 由于我创建了一个新的Loot对象而不是适当的子类,因此toSpawnOnPickUp函数的功能将消失,拾取赃物最终将无济于事(它只会调用基类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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM