The Lightning class

The Lightning class inherits from CCDrawNode because we refrain from using a CCSprite for something as electric and random as a bolt of lightning. Also, the length of the bolt of lightning might change over the course of time with the tower being upgraded.

Thus, the init function of the Lightning class looks like this, from the Lightning.cpp file:

bool Lightning::init(CCPoint from, CCPoint to, 
  ccColor4F color, bool is_animated)
{
  if(!CCDrawNode::init())
  {
    return false;
  }

  color_ = color;
  GenerateKeyPoints(from , to);
  if(!is_animated)
  {
    DrawSegments();
  }
  else
  {
    schedule(schedule_selector(Lightning::DrawNextSegment));
  }

  return true;
}

The init function takes four arguments: the start and end points for the lightning bolt, the color of the bolt, and another parameter named is_animated. If this flag is true, the lightning bolt will be shown shooting out from source to destination and the lightning bolt will appear whole if this flag is false.

After storing the color, we call the GenerateKeyPoints function, passing in the source and destination of the lightning bolt. For a bolt that doesn't need animation, we draw all its constituent segments at once and for a bolt that is not animated, we schedule a function to draw a segment at each tick.

Let's now move on to the GenerateKeyPoints function of Lightning.cpp to define the shape of our lightning bolt:

void Lightning::GenerateKeyPoints(CCPoint from, CCPoint to)
{
  // how many key points do we need?
  float distance = ccpDistance(from, to);
  num_key_points_ = (int)(distance / LIGHTNING_KEY_POINT_DIST);

  CCPoint next_point = CCPointZero;
  // calculate the difference between two key points
  CCPoint delta = ccp( (to.x - from.x) / num_key_points_, (to.y - from.y) / num_key_points_ );
  for(int i = 0; i < num_key_points_; ++i)
  {
    // add the delta
    next_point = ccpAdd(from, ccpMult(delta, i));
    // randomise the delta
    next_point.x += LIGHTNING_KEY_POINT_DIST * CCRANDOM_MINUS1_1();
    next_point.y += LIGHTNING_KEY_POINT_DIST * CCRANDOM_MINUS1_1();
    // save the key point
    key_points_.push_back(next_point);
  }  
}

We first calculate the number of key points the lightning bolt will require to interpolate between the source and destination. We calculate the delta between each key point and run a loop to interpolate. In this loop, we also add a random factor to each segment's vertex in order to get the electric feel of a lightning bolt. Let's now take a quick glance at the DrawSegments and DrawNextSegment functions of Lightning.cpp:

void Lightning::DrawSegments()
{
  // draw all segments at once
  for(int i = 0; i < num_key_points_ - 1; ++i)
  {
    drawSegment(key_points_[i], key_points_[i+1], 6, color_);
  }
}

void Lightning::DrawNextSegment(float dt)
{
  // draw one segment at a time
  if(++ last_key_point_ >= num_key_points_ - 2)
  {
    unschedule(schedule_selector(Lightning::DrawNextSegment));
  }

  drawSegment(key_points_[last_key_point_], 
    key_points_[last_key_point_+1], 6, color_);
}

As you can imagine, both these functions involve calls to the drawSegment function with the appropriate vertices for the segment. With this, we have achieved a simple and effortless lightning bolt effect. It's time now to head back to the Tower class and finish off the remaining functionalities.

With our shiny new bolt of lightning, the ShootLightning function from Tower.cpp looks relatively simple:

void Tower::ShootLightning()
{
  // damage the enemy
  CCActionInterval* damage_enemy = CCSequence::createWithTwoActions(
    CCDelayTime::create(LIGHTNING_DURATION * 0.5f), 
 CCCallFuncO::create(target_, callfuncO_selector(
 Enemy::TakeDamage), this));
  target_->runAction(damage_enemy);

  // create the lightning without animation
  Lightning* lightning = Lightning::create(m_obPosition, 
    target_->getPosition(), ccc4f(0.1098f, 0.87059f, 
    0.92157f, 1.0f), false);
  game_world_->addChild(lightning, E_LAYER_TOWER - 1);

  // animate the lightning
  CCActionInterval* shake = CCSequence::create(
    CCMoveTo::create(0.01f, ccp(3, 0)), CCMoveTo::create(0.01f, 
 ccp(-3, 0)), CCMoveTo::create(0.01f, ccp(0, 3)), 
 CCMoveTo::create(0.01f, ccp(0, -3)), NULL);
  lightning->runAction(CCRepeat::create(shake, 5));

  // remove the lightning
  CCActionInterval* wait_remove = CCSequence::createWithTwoActions(
    CCDelayTime::create(LIGHTNING_DURATION), 
    CCRemoveSelf::create(true));
  lightning->runAction(wait_remove);
}

We begin by creating a sequence of actions so that the enemy is damaged, similar to the ShootBullet function. We then create a Lightning object with the tower's position as the source and the target enemy's position as the destination, before adding the lightning to GameWorld.

We also perform a simple shake effect to make the lightning bolt funkier, while running another action to remove it after a short delay. The last couple of functions in the Tower class are CreateRangeNode and ShowRange, which simply create an object of class CCDrawNode to draw a semi-transparent green circle with a border that signifies the range for this particular tower. Since you already know how to do that, we shall conclude the Tower class and move on to the next big class: Enemy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.198.59