Interfaces: The Integration Contract


As I said earlier, this will be an object-oriented game engine. Traditionally in C++, multiple inheritance would be used to provide a collection of predefined behaviors for the various classes within the engine.

While this is a powerful technique, it does have its dangers. If a class inherits from two base classes that define attributes or methods with the same name , there would be a problem. The duplicated names would collide and produce a compiler error. The C# language addresses this problem by not allowing multiple inheritance. C# classes are allowed to inherit from only a single base class. To provide the benefits of multiple inheritance without the dangers, C# uses a mechanism called an interface. If you are familiar with C++, you can think of an interface as a pure virtual or abstract base class. A C# interface may define methods and properties but does not include the implementation of either. A C# class may inherit from as many interfaces as it needs. It is the responsibility of the inheriting class to implement each method and property defined by the interfaces it inherits. If it fails to provide a method or property defined in an inherited interface, the compiler will flag an error.

Class instances may be queried at run time to determine if they support a given interface. This allows us to have a collection of objects of different types, iterate through the collection, and call interface methods of those objects that support the interface. Since each class provides its own implementation for the interface methods, it is free to provide an implementation that is unique and appropriate for that class. As an example, let s look at two classes that implement an interface called IRenderable declaring a method called Render . This interface will be discussed in detail shortly. For now, accept that a class uses this method in order to draw the object to the screen appropriately for the current view.

For this example, we will assume that one object is a billboard made from two triangles to represent a tree and that the other object is the terrain model, with hundreds of thousands of triangles for an entire outdoors game. It is easy to see how the requirements and implementation of this method must be different for these two classes. The billboard needs only to draw the two triangles oriented toward the point of view and textured to look like a tree. The terrain class, on the other hand, must first determine which triangles are visible (no current hardware can render a world of this size in real time for every frame), transform the vertices for the texture appropriately for the current view, and draw and texture.

Let s look at a view of the more important interfaces that we will use in this game engine. We will get into various implementations of these interfaces as we progress through the book. The code for these interfaces is shown in Listing 1 “4, which appears later in this section.

The first interface is the IRenderable interface mentioned previously. A class that implements this interface is able to render an image of itself to the screen using the Render method. The argument of this method is the camera definition that defines the current view. This is all the information any class implementing this interface requires to render itself.

The second interface, ICullable , is implemented by any class that may not always be rendered to the display. This interface defines two properties. The properties manage the cull state of the object (whether the object should be rendered or not). The first property defined is Culled , which is responsible for clearing the cull state flag to the not culled state. The second property is defined as a read-only Boolean variable that is read with a Get method, IsCulled . It is important for game efficiency that any graphical object support this interface. As mentioned earlier when discussing terrain, the number of triangles in an object would overload the video card if not reduced to only the visible subset.

The next interface is the ICollidable interface. Any class whose object might physically collide with another object should support this interface. The properties and methods of this interface support the testing for collisions between two objects. The interface specifies several properties that expose the object s geometry in several levels of detail. In order for this interface to work, both objects involved must support the interface. The first property is a Vector3 property called CenterOfMass . This property defines the location of the center of the object in world coordinates. The second property of the object is BoundingRadius . This value defines a sphere around the object ”the smallest possible sphere centered on the center of mass that completely encloses the object.

The first method defined by the interface is CollideSphere , which takes an object reference as an argument. This method performs a spherical collision check between the two objects. This is the quickest collision check possible, since it only needs to check the distance between the two objects against the sum of the bounding radii of the two objects. This is a low-fidelity collision check, as it is possible to report a false positive if the two objects are close together without any of the polygonal faces intersecting or coming into contact. If neither of the objects is the player s model, and both are far enough from the viewpoint or otherwise out of view, this might be sufficient. Otherwise , we would normally proceed to using the second method of this interface. This method, CollidePolygon , takes three Vector3 variables as arguments. The method is called for each polygon in one of the models until a collision is detected or all polygons have returned a false Boolean value. As you can see, this is far more computationally expensive. Unfortunately, we must go to this extent if we want 100 percent confidence in the collision test.

The next interface that we will look at is the IDynamic interface. This interface supports any object that moves or changes as time progresses. Only one method is defined for this interface: Update . The only argument to this method is a floating-point variable containing the number of milliseconds since the object was last updated. This uses the method for integration of the position and attitude of the object, the step to the proper frame of an animation, or both. The properties of the interface are related to the physical dynamics, which I will address in detail in Chapter 10.

The final interface that we will discuss for now is ITerrainInfo . Any class that may be queried for information about the terrain implements this interface. This information is vital for any object that moves along or over the surface of the terrain. The first method for this interface is HeightOfTerrain , which returns the Y-axis value of the terrain at the supplied location in meters . By preventing an object from moving below this value, the object stays on the surface rather than dropping through. The second method, HeightAboveTerrain , is an extension of the first method that returns the difference between the Y-axis value passed in as part of the location and the height of the terrain at that point. This method is important for objects that are in flight above the terrain and striving not to collide with the surface. The next method is InLineOfSight , which returns a positive (true) value if there is an unobstructed line of sight between the two points that are supplied as arguments. The final method of the interface, GetSlope , is used by any object (such as a ground vehicle) to match its attitude with that of the slope it is resting upon. As you can see in the code in Listing 1 “4, this method accepts the location in question and the heading of the object making the call. The heading allows the method to return an attitude that is rotated to match the object s heading.

Listing 1.4: Interface Definitions
start example
 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 );  } 
end example
 



Introduction to 3D Game Engine Design Using DirectX 9 and C#
Introduction to 3D Game Engine Design Using DirectX 9 and C#
ISBN: 1590590813
EAN: 2147483647
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net