1

这次我遇到了虚拟字段的问题。

我的游戏对象有核心类。此类包含带有模型类对象的字段。模型的对象包含位置等值。

现在 - 在绘图时我需要从它的模型中读取每个对象的位置。当我使用派生而不是默认模型类时,问题就开始了。例子:

abstract class GenericGameObject { public DefaultGameObjectModel Model = new DefaultGameObjectModel(); }
class Missile : GenericGameObject { public new MissileModel Model = new MissileModel(); }

class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }

Missile m = new Missile();
m.Model.Position.X = 10;
// NOT OK! ((GenericGameObject)m).Model.Position.X == 0

我试图将模型定义为虚拟属性而不是字段,但这失败了,因为派生属性必须与它们的基础类型相同。铸造是徒劳的,因为会有许多其他模型类型。如果我想从派生类而不是基类中读取值,我该怎么办?

我已经问过这个问题,但答案没有带来任何解决方案。解释:

  • 使用接口 IGameObjectModel

    概念很好,但我必须强制执行字段。接口不能定义字段,所以我必须定义属性。但是我不能做 IGameObjectModel.Position.X=10 因为 Position 不是一个字段。

  • 为了使 GenericGameObject 成为泛型类型,例如 GenericGameObject 和 Missile 派生自 GenericGameObject 的类型, 我无法将导弹投射到 GenericGameObject 并通常将这些对象存储在同一个列表中。当然,我可以制作这两个可以继承的主要基本类型,但是我将无法访问 Model 字段。

  • 使模型成为属性而不是字段。 无法更改派生类中的属性类型。

我能做什么?

4

5 回答 5

2

在这种情况下,您最好的方法是将父字段的值分配为派生类的实例,然后将其转换回派生类或保留派生类的引用(可能更好)。

或者你可以走这条我最喜欢的路...

abstract class GenericGameObject
{
    public DefaultGameObjectModel Model
    {
        get { return ModelInternal; }
    }

    protected abstract DefaultGameObjectModel ModelInternal { get; }
}

class Missile : GenericGameObject
{
    private MissileModel model = new MissileModel();

    public override DefaultGameObjectModel ModelInternal
    {
        get { return model; }
    }

    public new MissileModel Model
    {
        get { return model; }
        set { model = value; }
    }
}

class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }

Missile m = new Missile();
m.Model.Position.X = 10;

此解决方案使您可以从基类的上下文访问您的基本模型实例,同时让您可以从继承的类访问您的具体模型实例。

于 2009-04-07T17:26:26.830 回答
2

没有“虚拟领域”之类的东西。只有属性方法可以是虚拟的。

在 Missle 类中,您似乎使用new 关键字作为修饰符来隐藏名为 Model 的继承成员。

当您以这种方式隐藏继承的成员时,您不会获得多态行为。这很糟糕,因为基类中的代码(如果它引用了 Model 字段)可能无法按预期工作。

最好的选择:使用属性。必要时进行强制转换或泛化(将成员移动到基类)。

于 2009-04-07T18:01:38.523 回答
1

如果您使用接口,我相信您仍然可以调用:

IGameObjectModel.Position.X = 10;

只要您用于 Position 的对象类型有一个名为 X 的读/写属性。您的界面将类似于:

public interface IGameObjectModel
{
    Vector2 Position
    {
        get;
        // only add set if you need to set the Position object outside of your class
        // set;
    }

    // ...other properties
}
于 2009-04-07T17:26:07.750 回答
1

您说过,如果您使用具有“无法执行 IGameObjectModel.Position.X=10”的属性的接口。我认为这是因为 Vector2 是一个结构,因此具有值类型语义。如果这是正确的,您应该简单地将 Position 属性分配给根据原始值计算的新 Vector2。例如:

Missile m = new Missile();
m.Model.Position = new Vector2()
{
    X = m.Model.Position.X + 10,
    Y = m.Model.Position.Y
};
于 2009-04-07T17:42:21.097 回答
0

您是否尝试过使用泛型?使用泛型,您可以将游戏对象模型与游戏对象分开。然后,您可以使用任何游戏对象模型实例化您的游戏对象。游戏对象可以通过标准接口与游戏对象模型通信。

interface IGameObjectModel {
    void Shoot();
        :
}

class GameObject<TModel> where TModel:IGameObjectModel {
    public TModel Model;
    public GameObject(TModel model) {
        Model = model;
    }
    public void Shoot() {
        Model.Shoot();
    }
        :
}

class MissleModel : IGameObjectModel {
    public void Shoot() {
        :
    }   
}

有了以上内容,您就可以使用 Missle 模型实例化您的游戏对象:-

MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
    new GameObject<MissleModel>(model);
于 2009-06-28T17:42:03.800 回答