
// AlienSprite.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Předpokládáme, že vetřelec je natočen ve směru kldané osy z
   a na začátku se nachází v bodě (0, ??, 0). Rotace se specifikují
   vzhledem k počáteční orientaci.

   Jeho chování specifikujeme v metodě headTowardsTourist(),
   která se volá z metody update(), kterou každých 100 milisekund
   volá objekt typu TimeBehavior.

   Chování je podobné třídě AlienQuadSprite v adresáři Code/Tiles/
*/

import java.text.DecimalFormat;
import javax.vecmath.*;


public class AlienSprite extends TourSprite
{
  private static final double CLOSE_DIST = 0.2;

  private TourSprite ts;
  private double currAngle;   // aktuální úhel otočení spritu kolem osy y
  private DecimalFormat df;   // pro jednodušší ladící výstup


  public AlienSprite(String fnm, Obstacles obs, TourSprite ts)
  { 
    super(fnm, obs);
    df = new DecimalFormat("0.###");  // 3 dm
    this.ts = ts;
    currAngle = 0.0;
  }  // konec metody: AlienSprite()


  public void update()
  // volá se ze třídy TimeBehaviour pro aktualizaci vetřelce
  {
    if (isActive()) {
      headTowardsTourist();
      if (closeTogether(getCurrLoc(), ts.getCurrLoc()))
        System.out.println("Vetřelec a turista jsou blízko sebe");
    }
  }  // konec metody: updateSprite()


  private void headTowardsTourist()
  /* Otočí vetřelce tak, aby směřoval k turistovi, pokud se
     však na požadované pozici nenachází překážka. V tom případě
     jej zkouší natočit jiným směrem.

     Proměnná rotAngle je úhel, který svírá původní orientace s
     kládnou z-ovou poloosou. Pro posun vetřelce používáme proměnnou 
     angleChg, což je rozdíl oproti aktuálnímu úhůu vetřelce.
  */
  { 
    double rotAngle = calcTurn( getCurrLoc(), ts.getCurrLoc());
    double angleChg = rotAngle - currAngle;
    // System.out.println("angleChg: " + df.format(angleChg));
    doRotateY(angleChg);
    currAngle = rotAngle;  // ulož nový úhel pro příště

    // je-li to možné, jdi vpřed, nebo vlevo, nebo vpravo nebo vzad
    // toto pevně dané pořadí může vést k zaseknutí vetřelce
    // v případě, že překážky jsou v jistém vzájemném uskupení
    if (moveForward())
      ;
    else if (moveLeft())
      ;
    else if (moveRight())
      ;
    else if (moveBackward())
      ;
    else
      System.out.println("Vetřelec se zasekl!");

  }  // konec metody: headTowardsTourist()

				

  private double calcTurn(Point3d alienLoc, Point3d touristLoc)
  /* Vypočítá úhel, o který je třeba otočit vetřelce kolem osy y,
     aby směřoval k turistovi. 
     Tento úhel je vztažen k původní orientaci, která směřovala
     ve směru kladné poloosy z.
  */
  {  // printTuple(alienLoc, "alienLoc");
     // printTuple(touristLoc, "touristLoc");
     double zDiff = touristLoc.z - alienLoc.z;
     double xDiff = touristLoc.x - alienLoc.x;
     //System.out.println("xDiff: " + df.format(xDiff) + 
     //                    "; zDiff: " + df.format(zDiff) );

     double turnAngle = 0.0;   // úhel, o který je třeba vetřelce otočit
     if (zDiff != 0.0) {
       double angle = Math.atan( xDiff/zDiff);
       // úhel od alienLoc k touristLoc
       // System.out.println("úhel: " + df.format(angle));
       if ((xDiff > 0) && (zDiff > 0))    // trochu nadbytečnosti pro lepší čitelnost
         turnAngle = angle;
       else if ((xDiff > 0) && (zDiff < 0))
         turnAngle = Math.PI + angle;    // poněvadž úhel je záporný
       else if ((xDiff < 0) && (zDiff < 0))
         turnAngle = Math.PI + angle;
       else if ((xDiff < 0) && (zDiff > 0))
         turnAngle = angle;    // poněvadž úhel je záporný
     }
     else {    // zDiff == 0.0, což je v případě použití typů double nepravděpodobné
       if (xDiff > 0)
         turnAngle = Math.PI/2;
       else if (xDiff < 0)
         turnAngle = -Math.PI/2;
       else    // vetřelec a sprite jsou přesně na stejném místě
          turnAngle = 0.0;
     }
     // System.out.println("turnAngle: " + df.format(turnAngle));
     return turnAngle;
  } // konec metody: calcAngle()


  private boolean closeTogether(Point3d alienLoc, Point3d touristLoc)
  // Jsou vetřelec a turista dostatečně blízko?
  {
    double distApart = alienLoc.distance( touristLoc );
    if (distApart < CLOSE_DIST)
      return true;
    return false;
  }  // konec metody: closeTogether()

}  // konec třídy: AlienSprite
