HGE扩展库Qaf教程粗略翻译

教程不难,所以我翻译的很粗略:

Basic Qaf Application

It is assumed that you have some experience with the HGE library, and this tutorial will skip some of the more basic stuff.

这里假设你有使用HGE库的一些经验,这个教程会忽略一些基本的HGE技巧。

The first thing to do is to bring the Qaf namespace into the global scope

第一件要做的事情是把Qaf名字空间放到全局作用域里:

using namespace qaf;
     

In the frame function, we'll just invoke Qaf's game loop:

然后在帧函数里,我们需要调用Qaf 的游戏循环:

HGE * hge = NULL;
     
 
     
// The frame function:
      
bool frameFunction () {
     
    // Perform Qaf's game loop:
      
    Environment::update( hge->Timer_GetDelta() );
     
    
     
    if ( hge->Input_GetKeyState( HGEK_ESCAPE ) )
     
        return true;
     
    
     
    return false;
     
}
     

The "prologue function" is a callback used to notify your program that Qaf is about to begin its rendering operations. Here, we're just going to clear the screen and print some text with the debug console:

“序言函数”是一个回调函数,它在Qaf将要开始渲染的时候被调用。这里,我们只是简单地清除屏幕并利用调试控制台打印一些字符信息:

void prologueFunc () {
     
    // Clear the screen:
      
    hge->Gfx_Clear( 0 );
     
    
     
    // Output text:
      
    Environment::cout << "Hello, world!/n";
     
    Environment::cout << hge->Timer_GetFPS() << " FPS/n";
     
}
     

In the main function, you must first set up HGE...

在主函数里,你需要首先设置HGE

// Application entry point:
      
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
     
    hge = hgeCreate( HGE_VERSION );
     
    
     
    hge->System_SetState( HGE_FRAMEFUNC,     frameFunction );
     
    hge->System_SetState( HGE_FPS,           HGEFPS_UNLIMITED );
     
    hge->System_SetState( HGE_SCREENWIDTH,   640 );
     
    hge->System_SetState( HGE_SCREENHEIGHT,  480 );
     
    hge->System_SetState( HGE_WINDOWED,      true );
     
    
     
    if ( !hge->System_Initiate() )
     
        MessageBox( NULL, hge->System_GetErrorMessage(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
     

...And then initialize Qaf:

然后初始化Qaf

    Environment::initialize( false, true );
     

Here, we're telling Qaf not to create a backbuffer (the first parameter) and that we need to use the debug facilities (the second parameter). Don't worry too much about these; they will be explained in more detail in other tutorials.

这里,第一个参数告诉Qaf不要创建一个后台缓存,第二个参数使我们可以使用Qaf的调试工具。这里不需要太担心这些参数,稍侯我们会再讲到。

Then we tell Qaf which function it should use as the prologue callback:

然后我们告诉 Qaf 哪个函数被作为“序言函数”:

    // Set the prologue function:
      
    Environment::setPrologueCallback( prologueFunc );
     

When that's done, just start the game loop:

完成那一切之后,就可以开始游戏循环了:

    if ( !hge->System_Start() ) {
     
        MessageBox( NULL, hge->System_GetErrorMessage(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
     
    }
     

After the game loop is finished, you simply shut down Qaf and HGE:

游戏循环结束后,你只需要简单地关闭QafHGE:

    Environment::shutdown();
     
    hge->System_Shutdown();
     
    hge->Release();
     
    
     
    return 0;
     
}
     

 

Tutorial 2 - Creating and Loading a Room File

只需要用QafRoomEditor编辑好Room文件,然后程序里一次载入,Qaf会自动地显示这个房间。

This is actually the easiest part. After initializing Qaf, you just need to tell it which room to load:

初始化Qaf后,你只需要告诉Qaf你要载入哪个房间即可:

    // Set up the environment:
      
    Environment::initialize( false, true );
     
    
     
    // Load the room:
      
    Environment::loadRoom( "tut02.qr" );
     

Tutorial 3 - Game Objects, Sprites and Scrolling

Every game object needs to have qaf::GameObj as its base class, so the missile class declaration should look like this:

游戏里所有的物体都需要从qaf::GameObj继承。--这样方便Qaf来控制所有物体,即把大部分逻辑问题交给游戏框架做,而不是客户程序员。

Finally, it's time to program the behavior of our missiles. The qaf::GameObj class doesn't do anything on its own, but it defines a set of methods you can override to implement objects' actions. In this tutorial, we will use two of them: update() and render().

我们需要为游戏里的物体加入具体的行为。Qaf::GameObj这个类本身没有加入任何有用的行为,但是它定义了一些你可以重载的接口。在这个教程里,我们将使用其中两个这样的接口:UpdateRender

显然,update是用来更新物体逻辑的,而render是用来渲染该物体的。

we're calling Environment::removeGameObj() with its second parameter set to true. This instructs the Environment to automatically delete the object at the end of the frame function.

当我们给Environment::removeGameObj()的第二个参数为TRUE时,Qaf会在帧结尾自动删除不需要的物体。

 

Tutorial 4 - Spawn Points and Factories

我们可以直接使用RoomEditor往房间文件里加入各种物体。当房间文件里有了物体数据后,我们需要在程序里来创建它们。

  The Game Object Factory

qaf::GameObjFactory is an abstract class with just one method:

qaf::GameObjFactory是一个只有一个方法的抽象类:

qaf::GameObj* qaf::GameObjFactory::createObject ( std::string & objID,
     
                                                  int objX,
     
                                                  int objY,
     
                                                  qaf::AttributeTable & attributes );
     

Its parameters include everything you defined in the Room Editor: ID, position, and attributes. There's nothing Qaf can do with these values, so it's up to us to decode them and create a GameObj.

它的参数包含了你在RoomEditor里定义的所有参数:ID,位置,以及其他属性。Qaf并不能用那些值做什么,因此我们需要处理它们并创建游戏物体。

// Game object factory implementation:
      
class GameObjFactoryImpl : public GameObjFactory {
     
    public:
     
        GameObj * createObject ( std::string & objID, int objX, int objY, AttributeTable & attributes ) {
     
            // Which object ID?
      
            if ( objID == "ShipObj" ) {
     
                // Create ship at (objX, objY) coordinates, facing up:
      
                return new ShipObj( Vector2D(objX, objY), Vector2D(0, -1) );
     
            }
     
            else
      
            if ( objID == "SpaceMineObj" ) {
     
                // Get "size" attribute, and convert it to a floating point
      
                // number:
      
                float fSize = (float) atof( attributes["size"].c_str() );
     
                
     
                // Could not convert?
      
                if ( fSize == 0.0f )
     
                    fSize = 1.0f;
     
                
     
                // Create mine at (objX, objY), scaled by fSize:
      
                return new SpaceMineObj( Vector2D(objX, objY), fSize );
     
            }
     
            else
      
                // Unknown ID:
      
                return NULL;
     
        }
     
};
     

Rather than creating the space ship through Environment::addGameObj(), we will now let our factory take care of object creation. In WinMain:

现在我们不用Environment::addGameObj()来创建物体,我们只需要让我们的工厂来负责一切物体的创建,在WinMain里:

    // Load the room:
      
    Environment::loadRoom( "tut04.qr" );
     
    
     
    // "Hey, Qaf, this is what you should use to create game objects":
      
    Environment::setGameObjFactory( new GameObjFactoryImpl() );
     
    
     
    // Start the game loop:
      
    if ( !hge->System_Start() ) {
     
        MessageBox( NULL, hge->System_GetErrorMessage(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
     
    }
     

 

       看起来,我们只需要那么一个抽象工厂类,以及一个保存有物体数据的房间文件,我们就可以轻松地创建所有的游戏物体。

 

Tutorial 5 - Iterators and Collision Handlers

Collision Structures

In order to detect object-to-object collisions, each object will be assigned an instance of qaf::CollisionStruct. This is an abstract class; check out its documentation for a list of collision structure subclasses you can use. For this tutorial, we'll use qaf::CollisionStruct::Circle and qaf::CollisionStruct::Polygon.

为了检测物体与物体之间的碰撞,每一个物体都必须分配一个qaf::CollisionStruct对象。

Qaf::CollisionStruct是一个抽象类,你可以查阅它的文档来知道它的子类。在这个教程里,我们会使用qaf::CollisionStruct::Circleqaf::CollisionStruct::Polygon。(实际上,qaf::CollisionStruct::Circleqaf::CollisionStruct::Polygon是两个类名,并不包含名字空间。作者在定义这两个类时,就直接class CollisionStruct::Circle : public CollisionStruct

Next, we need to associate collision structures with our objects. This is done with another method inherited from qaf::GameObj:

qaf::CollisionStruct * qaf::GameObj::getCollisionStruct ();
     

       然后,我们需要给我们的物体分配碰撞检测结构体。这可以使用从qaf::GameObj继承来的另一个方法:

qaf::CollisionStruct * qaf::GameObj::getCollisionStruct ();
     

By default, GameObj's implementation of this method returns NULL (which means "do not test this object for collisions"). To detect object-to-object collision, we're going to override this behavior in our classes and return a collision structure for each object.

       qaf在处理碰撞检测时,需要物体拥有这个方法,如果这个物体需要得到碰撞检测,就让这个函数返回其内部的碰撞检测结构体,否则可以返回NULL

The Collision Handler

This is just a callback function. It will be invoked when a collision occurs, and the two colliding objects will be passed as arguments to the function. We're interested in collisions between MissileObjs and SpaceMineObjs, so the declaration looks like this:

// The collision handler:
      
void handleCollision_Missile_SpaceMine ( MissileObj * pMissile, SpaceMineObj * pMine ) {
     

 

       碰撞检测函数:它是一个回调函数。当碰撞发生时,它会被调用,并且把两个发生碰撞的物体作为参数传进来。

Finally, we register our handler. In WinMain:

最后,我们需要注册这个碰撞检测函数,在WinMain 里:

    // "Hey, Qaf, this is what you should use to handle collisions between
      
    // Missiles and SpaceMines":
      
    Environment::registerCollisionHandler<MissileObj, SpaceMineObj>( handleCollision_Missile_SpaceMine );   
     

The syntax is a bit heavy there, so let's look at that line little by little.

·   qaf::Environment::registerCollisionHandler is a template method. It accepts two type parameters.

·   <MissileObj, SpaceMineObj> are the type parameters. Collision detection is class-based, so we actually tell Qaf the class, or type, of object that we want to handle.

·   handleCollision_Missile_SpaceMine is a pointer to the function that should be called when a collision between a MissileObj and a SpaceMineObj is detected.(即碰撞检测回调函数,当碰撞发生时,这个函数被调用)

 

注意:要编译基于Qaf的程序,需要将编译器的运行时类型识别打开(否则在虽然可以通过链接,但是程序在运行时会出错 ),并且还需要加入很多DX8的库,例如:

#pragma comment( lib, "d3dx8.lib" )

#pragma comment( lib, "dinput8.lib" )

#pragma comment( lib, "dxguid.lib" )

#pragma comment( lib, "dxerr8.lib" )

 

 

你可能感兴趣的:(object,function,Class,扩展,callback,attributes)