这次我遇到虚拟字段问题。
我的游戏对象有核心课程。此类包含具有Model类对象的字段。模型的对象包含诸如位置等的值。
现在 - 在绘图时我需要从它的模型中读取每个对象的位置。当我使用派生而不是默认模型类时,问题就开始了。例如:
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
我尝试将模型定义为虚拟属性而不是字段,但这会失败,因为 派生属性必须与其基础类型相同。铸造是徒劳的,因为会有许多其他模型类型。如果我想从派生类中读取值而不是从base中读取值,我该怎么办?
我已经问了这个问题,但答案没有带来任何解决方案。释:
使用界面IGameObjectModel
概念很好,但我必须强制执行字段。接口无法定义字段,因此我必须定义属性。但是我不能做IGameObjectModel.Position.X = 10,因为Position不是一个字段。
使GenericGameObject成为通用类型,例如GenericGameObject,Missile是从GenericGameObject派生的类型 然后我无法将导弹投射到GenericGameObject,并且通常将这些对象存储在同一列表中。当然我可以创建这两个可以继承的主要基类型,但是后来我无法访问模型字段。
使模型成为属性而不是字段。 在派生类中更改属性类型是不可能的。
我可以做什么?
答案 0 :(得分: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;
此解决方案使您可以从基类的上下文访问基本模型实例,同时允许您从继承的类访问具体的模型实例。
答案 1 :(得分:2)
没有“虚拟领域”这样的东西。只有properties和methods可以是虚拟的。
在您的Missle类中,您似乎正在使用new keyword as a modifier来隐藏名为Model的继承成员。
当您以这种方式隐藏继承的成员时,您不会获得多态行为。这很糟糕,因为基类中的代码(如果它引用了Model字段)可能无法按预期工作。
最好的选择:使用房产。根据需要强制转换或概括(将成员移动到基类)。
答案 2 :(得分: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
}
答案 3 :(得分: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
};
答案 4 :(得分: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);