#define MINE_ROTSPEED 2.0f
class SpaceMineObj : public GameObj { private: hgeSprite * m_sprite; // Mine sprite Vector2D m_pos; // Mine position float m_size; // Mine scaling public: SpaceMineObj ( Vector2D pos, float size ) { m_pos = pos; m_size = size; m_sprite = pResManager->GetSprite( "sprMine" ); } void render ( int objLayer, float scrollX, float scrollY ) { // Render the mine, slowly rotating... m_sprite->RenderEx( m_pos.x - scrollX, m_pos.y - scrollY, MINE_ROTSPEED * Environment::time, m_size, m_size ); } };
It is possible to simply insert space mines into the playfield by using Environment::addGameObj()
, but that's tedious and error-prone. Instead, we will use the Room Editor to tell Qaf where it should create mines; that way, we'll know exactly where they will appear.
Type "SpaceMineObj" in the Object ID field, then double-click on (New value...) in the attribute table. Type "size" as the key and "1.0" as the value, then click OK.
Click OK in the New game object dialog, and you'll see a small red square appeared at the center of the screen. You've determined the first mine's spawn point!
To move the object, use the Game Object Selection tool (just left-click and drag the red square).
Make a duplicate of the object by selecting it, copying it with Ctrl + C and pasting it with Ctrl + V. Now, click on the Edit game object button in the window's lower right. Double-click on the "size" attribute and change its value to "2.5" so the second mine will appear bigger than the first.
Repeat the process as many times as you want, changing the value of "size" so the playfield will have lots of mines with different sizes.
Now, go to Room -> New game object again, but this time type "ShipObj" as the object's ID. Click OK and place the ship at the center of the room.
Save it as tut04.qr and close the Room Editor.
Everything we've written so far is just a bunch of strings, which are meaningless to Qaf. We'll have to somehow translate this data into actual GameObj
instances.
qaf::GameObjFactory
is an abstract class with just one method:
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
.
// 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; } };
Environment::addGameObj()
, we will now let our factory take care of object creation. In 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 ); }
See the full source code for this tutorial in the file: tutorials/tutorial04.cpp