第一章 第四节 接口:整合契约

如我前面所说,这将是一个面向对象的游戏引擎。C++惯例,为引擎的多样的类使用多重继承来提供预先定义的行为集合。

 

虽然这是一个强大的技术,但是有它的危险。如果一个类继承两个定义了同样的属性或者方法的基类,这就会产生问题。同样的名字将会冲突,产生一个编译器错误。C#通过不允许多重继承来解决这个问题,只能继承一个基类。为了取得多重继承的好处而又消除危险,C#使用interface机制。如果你熟悉C++,你可以把interface看作纯虚或者抽象基类。C# interface可以定义方法和属性,但是不包含他们的实现。一个C#类可以继承任意所需的interface。实现接口定义的每一个方法和属性是子类的责任。如果被继承的接口某个方法或者属性没有被提供,编译器会报错。

 

类实例在运行时进行查询,以决定他们是否支持某一个给定的接口。这就允许我们在一个包含不同类型的对象集合中,逐个调用这些对象支持的接口方法。既然每个类可以为接口方法提供自己的实现,那么可以自由的为一个类提供唯一的和恰当的实现。作为一个例子,让我们看看两个类,他们实现一个声明了Render方法的接口IRenderable。这个接口稍后就会详细讨论,眼下暂且认为一个类使用这个方法来把当前的对象恰当的绘制到屏幕上。

 

对于这个例子,我们假设其中一个对象是billboard,由两个三角形组成,表示一棵树;另外一个对象是一个室外游戏的整个地形模型,由成百上千的三角形组成。很容易了解需求,从而这两个类实现这个方法必定是不同的。Billboard仅仅需要绘制两个只是朝向视点的三角形,然后贴上树的纹理。另一方面,地形类首先必须确定哪些三角形是可见的(当前没有硬件可以每一帧都实时的渲染整个世界这么大尺寸的地形),然后变换顶点以适合此视点的纹理,然后再绘制和贴纹理。

 

让我们看看将要使用在这个游戏引擎中的更重要的一些接口。随着这本书的进度,我们将看到这些接口的各种不一样的实现。这些接口的代码如清单1-4所示。

 

第一个接口是前面提到的IRenderable接口。一个类如果实现这个类,则可以使用方法Render绘制自己到屏幕。这个方法的参数是摄像机定义,定义了当前视点,这就是任何需要渲染自己的类实现此接口所需要的所有信息。

 

第二个接口是ICullable,任意不是总是需要绘制自己的类需要实现此接口。这个接口定义了两个属性。这些属性管理了对象(不论对象需要渲染或不需要)的剔除状态。第一个属性是Culled,它负责把剔除状态标志置为不剔除状态。第二个属性定义成只读布尔变量IsCulled,通过Get方法来读写它的值。对于游戏效能很重要,任何图形对象都支持这个接口。前面提到的地形,对象中的三角形数量如果不较少到仅仅可视的三角形属性,就会是图形卡负载过重。

 

下一个接口是ICollidable接口。任何类,它表示的对象需要与其他对象发生物理碰撞,则应该支持这个接口。这个接口的属性和方法支持两个对象之间的碰撞检测。接口定义了几个属性,它们从几个级别上暴露了对象的几何信息。为了这个接口能起作用,肇事的两个对象都需要支持这个接口。第一个属性是CenterOfMass,它是一个Vector3类型。此属性一世界坐标定义了对象的中心位置。第二个属性是BoundingRadius。这个值定义了对象的最小外接球。

 

此接口定义的第一个方法是CollideSphere,它需要一个对象的引用作为参数。此方法在两个对象之间执行球碰撞检测。这是最快速的碰撞检测方法,因为只需要检测对象之间的距离与两个对象包围球半径之和做对比。这是低精度的碰撞检测,因为它有可能会误报,如果两个对象靠近,但是没有任何多边形相交或者接触,而它有可能会检测到已经碰撞。如果这个对象既不是玩家,并且两个都距离视点足够远,或者位于视线之外,那么这个方法就足够了。然而,我通常使用这个接口的第二个方法。CollidePolygon方法,它需要三个Vector3变量作为参数。这个方法被模型里的每个多边形调用,直到检测到碰撞或者所有多边形都返回否定的布尔值。如你所见,这将非常耗费计算。不幸的是,如果我们需要百分之百精确的碰撞检测,我们必须使用这个扩展,即第二个方法。

 

下一个是IDynamic接口。这个接口支持任意的对象随着时间的流逝移动或者改变。此接口只定义了一个方法:Update。此方法只接受一个浮点参数,即记录对象上一次更新到现在的毫秒数。使用这个方法整合对象的位置和角度,以及动画的适当帧,或者两者。此接口的属性都与物理动力学有关,我会在第十章讲解。

 

最后一个我们目前要将的接口是ITerrainInfo。任意需要查询地形信息的类实现这个接口。地形信息对于在地面上移动或者在地形表面之上活动的对象是非常重要的。此接口第一个方法是HeightOfTerrain,它返回指定位置地形的Y坐标值,单位是英尺。防止对象在低于这个值之下移动,对象在表面上,而不是在地下穿行。第二个方法是HeightAboveTerrain,这是第一个方法的扩展,他返回作为坐标位置传入的Y轴值与地形高度之间的差异。此方法对于在地面上飞行而不至于和地表相撞的对象非常重要。下一个方法是InLineOfSight,它返回一个正树值(true),如果在作为参数提供的两个点之间存在不被阻隔的视线。最后一个方法是GetSlope,它被任何对象(例如陆地车辆)来匹配停在斜坡上的角度。如你在清单1-4中看到的,此方法接受对象的位置和运动方向。运动方向使此方法返回一个attitude,旋转这个物体,使得匹配对象运动方向。

 

清单1.4:接口定义

public interface IRenderable

{

   void Render(Camera cam);

}

 

public interface ICullable

{

   bool Culled { set; }

   bool IsCulled { get; }

}

 

public interface ICollidable

{

   Vector3 CenterOfMass { get; }

   float BoundingRadius { get; }

   bool CollideSphere ( Object3D other );

   bool CollidePolygon ( Vector3 Point1, Vector3 Point2, Vector3 Point3 );

}

 

public interface IDynamic

{

   void Update( float DeltaT );

}

 

public interface ITerrainInfo

{

   float HeightOfTerrain( Vector3 Position );

   float HeightAboveTerrain( Vector3 Position );

   bool InLineOfSight( Vector3 Position1, Vector3 Position2 );

   Attitude GetSlope( Vector3 Position, float Heading );

}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值