The collectibles for this game will be represented by the Collectible
class that inherits from GameObject
and will be used to represent all three types of collectibles: the simple collectible, the rocket, and the balloon. It will possess a score value and a flag that marks whether it has been collected. It will possess functions to manage life events that we will discuss in this section, starting with the SetBody
function:
void Collectible::SetBody(b2Body* body) { b2PolygonShape collectible_shape; // create different box shapes for different collectibles switch(type_) { case E_GAME_OBJECT_COLLECTIBLE: collectible_shape.SetAsBox(SCREEN_TO_WORLD( m_obContentSize.width/2), SCREEN_TO_WORLD( m_obContentSize.height/2)); break; case E_GAME_OBJECT_ROCKET: case E_GAME_OBJECT_BALLOON: collectible_shape.SetAsBox(SCREEN_TO_WORLD( m_obContentSize.width/2), SCREEN_TO_WORLD( m_obContentSize.height/4), b2Vec2(0, SCREEN_TO_WORLD( m_obContentSize.height/4)), 0); break; } // mark the fixture as a sensor b2FixtureDef collectible_fixture_def; collectible_fixture_def.shape = &collectible_shape; collectible_fixture_def.isSensor = true; body->CreateFixture(&collectible_fixture_def); // call parent class' function GameObject::SetBody(body); }
All three collectibles will have a box shape fed into their fixtures but will look different based the value of type_
variable. One important thing to notice is that this time we set a new property of the b2FixtureDef
class—the isSensor
property. A sensor in Box2D, to quote the manual, is a fixture that detects a collision but does not produce a response.
This is exactly what we want in our game since it would look pretty awkward if the clown kept bouncing off every bowling pin, bottle rocket, and balloon. We wind up the function by creating the fixture and passing the body to the SetBody
function of the parent class.
Now, let's define the Init
and Reset
functions, which will enable us to reuse this object throughout our game:
void Collectible::Init(b2Vec2 position) { // initialise position and scale body_->SetTransform(position, 0); setScale(1.0f); } void Collectible::Reset() { // reset position outside boundary of game body_->SetTransform(b2Vec2(SCREEN_TO_WORLD(-1 * WALL_WIDTH), SCREEN_TO_WORLD(-1 * WALL_WIDTH)), 0); removeFromParentAndCleanup(true); is_collected_ = false; }
The Init
function sets the position of the body to the input provided and also resets the scale factor. This function will be called when the collectible has been added on to the game world. The Reset
function—on the other hand—places the body right out of the screen while also removing itself from its parent and setting the is_collected_
flag to false
. This function will be called when the collectible has been removed from the game world. That is all we need to do to make this collectible reusable. We will now define the behavior of the collectibles when they collide with the clown:
void Collectible::OnCollision() { // can be collected only once if(is_collected_) return; is_collected_ = true; // add respective score game_world_->AddScore(score_); // scale down and exit runAction(CCSequence::createWithTwoActions( CCSequence::createWithTwoActions(CCScaleTo::create(0.01f, 1.2f), CCScaleTo::create(0.1f, 0.0f)), CCCallFunc::create(this, callfunc_selector(Collectible::AfterCollision)))); // inform player of respective state change if(type_ == E_GAME_OBJECT_ROCKET) { game_world_->GetClown()->SetState(E_CLOWN_NONE); game_world_->GetClown()->SetState(E_CLOWN_ROCKET); } else if(type_ == E_GAME_OBJECT_BALLOON) { game_world_->GetClown()->SetState(E_CLOWN_NONE); game_world_->GetClown()->SetState(E_CLOWN_BALLOON); } ShowParticle(); SOUND_ENGINE->playEffect("collectible.wav"); }
This function is called from the BeginContact
function we saw in the previous section. A collectible can only be collected once and hence the return statement at the start of the function. Then we inform GameWorld
to add the score for this collectible and also play a simple animation. Based on which type of collectible this is, we need to inform the clown that a change of state has occurred. While doing this, we first set the clown's state to none and then to either the rocket or balloon state. This is done to handle cases like when the clown is already in the rocket state and collides with another rocket. Since our clown's SetState
function only responds to a state change, the preceding scenario won't show any effect. The last thing we do is show a small burst of some particles.
The AfterCollision
function simply informs GameWorld
that this collectible should now be removed. With these functions, we have more or less completed defining the behavior of the collectibles. However, we will need to write the code to implement the reusing and caching of these collectibles.
18.224.68.28