[ < ] | [ > ] |  | [ << ] | [ 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.