views:

740

answers:

5

Hello, This time I have problem with virtual fields.

I have core class for my game objects. This class contains a field with Model class object. Model's object contains values such as position etc.

Now - while drawing I need to read position of each object from it's model. The problem starts when instead of default model class I'm using derived. Example:

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

I tried to make Model defined as virtual property instead of field, but this fails because derived properties have to be of same type as their base. Casting is futile because there will be many other model types. What can I do if I want to read a value from derived class, not from base?

I asked this question already but the answer didn't brought any solution. Explaination:

  • to use interface IGameObjectModel

    Concept is good, but I have to enforce fields. Interfaces can't define fields so I have to define property. But then I can't do IGameObjectModel.Position.X=10 because Position is not a field.

  • to make GenericGameObject a generic type such as GenericGameObject and Missile a type derived from GenericGameObject I couldn't then cast a missile to GenericGameObject and generally store those object on same list. Of course I could make main base type which those two could inherit from, but then I wouldn't have access to Model field.

  • to make model a property instead of field. It is impossible to change property type in derived class.

Whad can I do?

+1  A: 

If you used an interface, I believe you'd still be able to call:

IGameObjectModel.Position.X = 10;

As long as the object type you used for Position has a read/write property called X. Your interface would look something like:

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

    // ...other properties
}
Justin Niessner
In fact I am not able even using both get and set accessors :/
Ziell
This won't work. XNA's Vector2 is a struct, not a class. You'd need a set accessor, and have to set the entire struct.
Reed Copsey
+2  A: 

In this case your best approach would be to assign the value of your parent field to be an instance of your derived class, then either cast it back to your derived class or hold on to a reference of your derived class (probably better).

Or you could go down this road, which I like the best...

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;

This solution gives you access to your base model instance from the context of the base class, while giving you access to your concrete model instance from the inherited class.

Adam Robinson
And that's good answer, thanks! I've just checked this out and it works just as it should! Thanks once more :)
Ziell
+1  A: 

You said that if you used an interface with a property that you "can't do IGameObjectModel.Position.X=10". I assume this is because Vector2 is a struct and therefore has value-type semantics. If this is correct, you should simply assign the Position property to a new Vector2 calculated from the original value. For example:

Missile m = new Missile();
m.Model.Position = new Vector2()
{
    X = m.Model.Position.X + 10,
    Y = m.Model.Position.Y
};
Daniel Pratt
+2  A: 

There's no such thing as 'virtual fields'. Only properties and methods can be virtual.

In your Missle class, you appear to be using the new keyword as a modifier to hide the inherited member named Model.

When you hide an inherited member this way, you don't get polymorphic behavior. This is bad because the code in your base class (if it references the Model field) may not work as you expect.

Best bet: Use a property. Cast or generalize (move members to base class) as necessary.

Matt Brunell
A: 

Did you try using generics? Using generics you can separate your game object model from your game object. You can then instantiate your game object with any game object model. The game object can communicate with the game object model thru standard interfaces.

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() {
     :
    } 
}

With the above, you can then instantiate your game object with the missle model :-

MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
    new GameObject<MissleModel>(model);
anonymous