Package org.gbcpainter.game.model.monsters

Source Code of org.gbcpainter.game.model.monsters.Bomber

package org.gbcpainter.game.model.monsters;

import net.jcip.annotations.GuardedBy;

import org.gbcpainter.game.model.Monster;
import org.gbcpainter.game.view.animations.AnimatedSingleSlotMonster;
import org.gbcpainter.geom.PERPENDICULAR_DIRECTION;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.Collections;

/**
* Implementation of the monster named "Bomber"
* <p/>
* The Bomber moves randomly in the game grid at high speed, drops a bomb, travels a little more and then stops, activating the bomb countdown. After the bomb exploded it waits a
* little then restarts this cycle
*
* @author Lorenzo Pellegrini
*/
public class Bomber extends AnimatedSingleSlotMonster implements Monster {

  /* Start steps waiting times */
  private static final int RUNNING_BOMBER_SPEED = 4;

  private static final int BOMB_TIMER = 5;

  private static final int AFTER_BOMB_EXPLOSION = 12;

  private static final int RUN_STEPS_BEFORE_PLANT = 7;

  private static final int RUN_STEPS_AFTER_PLANT = 1;

  private static final int BOMB_EXPLOSION_TIME = 3;
  /* End steps waiting times */

  //Bomber has only one texture
  private static final Iterable<String> BOMBER_TEXTURES_ROTATION = Collections.singletonList( "Bomber" );
  private static final double HALF_POINT = 0.5;

  /* Start bomber state variables */
  @GuardedBy ("this")
  private BOMBER_STATE state = BOMBER_STATE.WAIT_AFTER_BOMB_EXPLOSION;

  @GuardedBy ("this")
  private int remainingStateSteps;

  @Nullable
  @GuardedBy ("this")
  private Point bombPosition = null;

  @Nullable
  @GuardedBy ("this")
  private Bomb placedBomb = null;

  /* End bomber state variables */

  /**
   * Creates a bomber at the given initial position, initially waiting as if its bomb just exploded
   *
   * @param initialPosition The initial position of the bomber
   *
   * @throws Exception If an error occurs while loading textures
   */
  public Bomber( @NotNull final Point initialPosition ) throws Exception {
    super( initialPosition, BOMBER_TEXTURES_ROTATION );
    this.remainingStateSteps = getRequiredSteps( this.state );
    /*final Bomb loadTexturesTrick =*/ new BombImpl( 1, 2, 3, new Point( 1, 1 ) );
  }

  @NotNull
  @Override
  public PERPENDICULAR_DIRECTION getNewDirection( @Nullable final PERPENDICULAR_DIRECTION previousDirection, final boolean shouldReset ) {
    final PERPENDICULAR_DIRECTION exclude;
    if ( shouldReset ) {
      exclude = previousDirection;
    } else if ( previousDirection != null ) {
      exclude = previousDirection.getOpposite();
    } else {
      exclude = null;
    }

    synchronized (this) {
      final PERPENDICULAR_DIRECTION direction = utilGetFilteredDirection( exclude );
      setDirection( direction );
      return direction;
    }
  }

  @Override
  public synchronized void draw( @NotNull Graphics2D g2d ) throws Exception {
    super.draw( g2d );
    drawBomb( g2d );
  }

  @Override
  public synchronized void setPosition( @NotNull Point position ) {
    super.setPosition( position );
    checkBombHit();
  }

  @Override
  public synchronized int getSpeed() {
    return this.state.isRunning() ? RUNNING_BOMBER_SPEED : 0;
  }

  @Override
  public boolean modifiesColor() {
    return false;
  }

  @Override
  public boolean isColoring() throws UnsupportedOperationException {
    throw new UnsupportedOperationException();
  }

  @Override
  public synchronized void resetState() {
    this.applyAnimation( null );
    this.state = BOMBER_STATE.WAIT_AFTER_BOMB_EXPLOSION;
    this.bombPosition = null;
    this.placedBomb = null;
  }

  @Override
  public synchronized String toString() {
    return "Bomber{" +
           "state=" + this.state +
           ", remainingStateSteps=" + this.remainingStateSteps +
           ", bombPosition=" + this.bombPosition +
           ", placedBomb=" + this.placedBomb +
           "} " + super.toString();
  }

  @Override
  public synchronized void endStep() throws Exception {
    super.endStep();
    this.checkBombHit();
    this.remainingStateSteps--;
    if ( this.remainingStateSteps <= 0 ) {
      switch ( this.state ) {
        case WAIT_BOMB:
          this.state = BOMBER_STATE.WAIT_EXPLOSION;
          break;
        case WAIT_EXPLOSION:
          this.setDirection( this.utilGetFilteredDirection( null ) );
          this.state = BOMBER_STATE.WAIT_AFTER_BOMB_EXPLOSION;
          this.bombPosition = null;
          this.placedBomb = null;
          break;
        case WAIT_AFTER_BOMB_EXPLOSION:
          this.setDirection( this.utilGetFilteredDirection( null ) );
          this.state = BOMBER_STATE.RUN_BEFORE_PLACE;
          break;
        case RUN_BEFORE_PLACE:
          this.setDirection( this.utilGetFilteredDirection( null ) );
          this.state = BOMBER_STATE.RUN_AFTER_PLACE;
          this.bombPosition = this.getPosition();
          final int runAfterPlaceSteps = this.getRequiredSteps( BOMBER_STATE.RUN_AFTER_PLACE );
          final int bombTimerSteps = this.getRequiredSteps( BOMBER_STATE.WAIT_BOMB );
          final int bombExplosionSteps = this.getRequiredSteps( BOMBER_STATE.WAIT_EXPLOSION );
          this.placedBomb = new BombImpl( this.getOwner().getNextStepTime( runAfterPlaceSteps ),
                                          this.getOwner().getNextStepTime( runAfterPlaceSteps + bombTimerSteps ),
                                          this.getOwner().getNextStepTime( runAfterPlaceSteps + bombTimerSteps + bombExplosionSteps ),
                                          this.bombPosition );
          break;
        case RUN_AFTER_PLACE:
          this.state = BOMBER_STATE.WAIT_BOMB;

          break;
        default:
          throw new AssertionError( "Invalid enum constant: " + this.state );
      }

      this.remainingStateSteps = this.getRequiredSteps( this.state );
    }
  }

  @GuardedBy ("this")
  private void drawBomb( @NotNull Graphics2D g2d ) throws Exception {
    if ( this.placedBomb != null ) {
      this.placedBomb.draw( g2d );
    }
  }

  /**
   * Utility methods for mapping a state to the steps required to complete.
   *
   * @param state A bomber state
   *
   * @return The required steps for this state
   */
  private int getRequiredSteps( @NotNull BOMBER_STATE state ) {
    switch ( state ) {
      case WAIT_BOMB:
        return BOMB_TIMER;
      case WAIT_EXPLOSION:
        return BOMB_EXPLOSION_TIME;
      case WAIT_AFTER_BOMB_EXPLOSION:
        return AFTER_BOMB_EXPLOSION;
      case RUN_BEFORE_PLACE:
        return RUN_STEPS_BEFORE_PLANT;
      case RUN_AFTER_PLACE:
        return RUN_STEPS_AFTER_PLANT;

      default:
        throw new AssertionError( "Invalid enum constant: " + state );
    }
  }

  private boolean checkBombHit() {
    boolean hit = false;
    final Point actualBombPosition;
    final BOMBER_STATE actualState;
    final Bomb actualBomb;

    synchronized (this) {
      actualState = this.state;
      actualBombPosition = this.bombPosition;
      actualBomb = this.placedBomb;
    }

    if ( actualState == BOMBER_STATE.RUN_AFTER_PLACE || actualState == BOMBER_STATE.WAIT_BOMB || actualState == BOMBER_STATE.WAIT_EXPLOSION ) {
      //Check collision with the bomb
      assert actualBomb != null;
      assert actualBombPosition != null;

      final Point playerPosition = this.getOwner().getPlayerPosition();
      if ( actualState == BOMBER_STATE.RUN_AFTER_PLACE || actualState == BOMBER_STATE.WAIT_BOMB ) {
        if ( playerPosition.equals( actualBombPosition ) ) {
          hit = true;
        }
      } else {
        //Bisogna tenere conto del raggio dell'esplosione
        Shape explosionArea = actualBomb.getExplosion( actualBombPosition );
        if ( explosionArea != null ) {
          final Rectangle2D playerBox = new Rectangle2D.Double( playerPosition.getX() - HALF_POINT, playerPosition.getY() - HALF_POINT, 1.0, 1.0 );

          if ( explosionArea.intersects( playerBox ) || explosionArea.contains( playerBox ) ) {
            hit = true;
          }
        }

      }

      if ( hit ) {
        synchronized (this) {
          this.getOwner().hitPlayer();
          this.placedBomb.lockAnimation( this.getOwner().getStepTime() );
        }
      }
    }
    return hit;

  }

  private enum BOMBER_STATE {
    WAIT_BOMB, WAIT_EXPLOSION, WAIT_AFTER_BOMB_EXPLOSION, RUN_BEFORE_PLACE, RUN_AFTER_PLACE;

    public boolean isRunning() {
      return ( this == RUN_AFTER_PLACE ) || ( this == RUN_BEFORE_PLACE );
    }
  }
}
TOP

Related Classes of org.gbcpainter.game.model.monsters.Bomber

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.