[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.2.4.9 Laser Class

The Laser class is responsible for managing the laserbeam that the player can shoot. There is only one instance of this class.

 
class Laser
{
private:
  AppMazing* app;

  /// Our laserbeam mesh.
  csRef<iMeshWrapper> laserbeam;
  // Lifetime of the laserbeam.
  int lasertime;
  // The current laserbeam coordinates.
  csVector3 laserstart, laserend;
  iSector* lasersector;

public:
  Laser (AppMazing* app);

  void SetMeshWrapper (iMeshWrapper* laser)
  {
    laserbeam = laser;
  }

  /// Start the laser.
  void Start ();
  /// Handle life time of the laser.
  void Handle (csTicks ticks);
  /// Check if the laser hits anything.
  void Check ();
};

The three important functions in this class are: Start() which starts the laser (unless it is already in progress), Handle() which takes care of the lifetime of the laser, and Check() which will check if the laser hits anything.

 
Laser::Laser (AppMazing* app)
{
  Laser::app = app;
  lasertime = 0;
}

void Laser::Start ()
{
  if (lasertime > 0) return;	// Laser already in progress.
  lasertime = LASER_LIFETIME;
  const csOrthoTransform& tr = app->GetCamera ()->GetTransform ();
  laserstart = tr.This2Other (LASER_OFFSET);
  laserend = tr.This2Other (csVector3 (0, 0, 20.0));
  lasersector = app->GetCamera ()->GetSector ();

  // Fire up our beam.
  laserbeam->GetMovable ()->SetPosition (lasersector, laserstart);
  laserbeam->GetMovable ()->GetTransform ().LookAt (
  	laserend-tr.GetOrigin (), csVector3 (0, 1, 0));
  laserbeam->GetMovable ()->UpdateMove ();
}

This function starts the laserbeam (unless it is already in progress). Starting the laser means that we basically put it at the same position of the camera but lowered a bit with the `LASER_OFFSET' offset. This offset is calculated in camera space that means that it will always be below the camera as seen from the perspective of the camera. The This2Other() functions transforms the offset (as seen in camera space) to world space by using the camera transformation (iCamera->GetTransform()).

We also transform a point in front of the camera (20 units in front) to world space. So these two world space coordinates give us a starting and a direction for our laserbeam. We place the laserbeam mesh at the starting position and then we use LookAt() to change the transform of that mesh to look at the destination position. Then we place the mesh in the sector of the camera and finally we call UpdateMove() which is required after moving a mesh.

 
void Laser::Handle (csTicks ticks)
{
  if (lasertime <= 0) return;
  lasertime -= ticks;
  if (lasertime <= 0)
  {
    // Time to stop the laser.
    lasertime = 0;
    laserbeam->GetMovable ()->ClearSectors ();
    laserbeam->GetMovable ()->UpdateMove ();
  }
  else
  {
    int flick = (lasertime / LASER_FLICKTIME) & 1;
    Check ();
    csRef<iGeneralMeshState> state = scfQueryInterface<iGeneralMeshState> (
    	laserbeam->GetMeshObject ());
    state->SetColor (flick ? csColor (2.0, 2.0, 2.0) : csColor (.5, .5, .5));
  }
}

This function handles the lifetime of the laser. Again depending on the elapsed ticks since previous frame. This function also makes the beam flicker by changing the color. Additionally, every time the laserbeam changes color it will check if there is an adversary hit by the laser. This happens with the Check() function below:

 
void Laser::Check ()
{
  // Do a beam to check if we hit an adversary.
  csSectorHitBeamResult rc = lasersector->HitBeamPortals (
  	laserstart, laserend);
  if (rc.mesh)
  {
    csRef<Adversary> adv = CS_GET_CHILD_OBJECT (
    	rc.mesh->QueryObject (), Adversary);
    if (adv)
    {
      // Hit!
      app->GetGame ().ExplodeAdversary (adv);
    }
  }
}

Using iSector::HitBeamPortals() we try to find if there is an object in the beam of the laser. We use the start and end position as calculated in the Start() function. If we hit a mesh then we will use CS_GET_CHILD_OBJECT() to get the Adversary instance that is attached to the mesh. This makes use of the fact that we added the adversary to the mesh using the iObject system.

If we hit an adversary then we explode it by calling ExplodeAdversary().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated using texi2html 1.76.