Package org.gbcpainter.view.draw

Source Code of org.gbcpainter.view.draw.RedrawJobImpl

package org.gbcpainter.view.draw;

import org.gbcpainter.env.GameSettings;
import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.game.levels.Level;
import org.gbcpainter.game.levels.LivesLevel;
import org.gbcpainter.game.levels.ScoreLevel;
import org.gbcpainter.game.model.Monster;
import org.gbcpainter.game.model.Player;
import org.gbcpainter.game.view.animations.AnimatedElement;
import org.gbcpainter.game.view.animations.EntityMovementAnimation;
import org.gbcpainter.game.view.animations.TerminatedAnimationException;
import org.gbcpainter.game.model.grid.Face;
import org.gbcpainter.game.model.grid.Junction;
import org.gbcpainter.game.model.grid.OpaqueRandomFace;
import org.gbcpainter.game.model.grid.Pipe;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jgrapht.Graph;
import org.jgrapht.graph.UnmodifiableUndirectedGraph;

import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;
import java.util.List;

/**
* Implementation of the {@link ComposableRedrawJob}.
* <p/>
* It draws the game, lives and score
*
* @author Lorenzo Pellegrini
*/
public class RedrawJobImpl extends ComposableRedrawJob<RedrawJobImpl.COMPONENTS> {

  private static final double SCORE_WIDTH_DIMENSION = 0.6;

  private static final double SCORE_HEIGHT_DIMENSION = 0.1;

  private static final double LIVES_WIDTH_DIMENSION = 0.4;

  private static final double LIVES_HEIGHT_DIMENSION = 0.1;

  private static final int MAX_LATERAL_SPACE = 2;

  private static final boolean THROW_EXCEPTION_ON_FACES_ERROR = true;


  private static final List<COMPONENTS> COMPONENTS_LIST = Arrays.asList( COMPONENTS.CORE_VIEW, COMPONENTS.LIVES_VIEW, COMPONENTS.SCORE_VIEW );

  @NotNull
  private final Map<Face, Integer> faces;

  @NotNull
  private final Rectangle levelBounds;

  /**
   * Creates a new redraw job given the canvas where to draw to, the level and the initial fps
   *
   * @param whereTo          The canvas where to draw to
   * @param level            The level to be drawn
   * @param refreshPerSecond The FPS
   *
   * @throws java.lang.IllegalArgumentException If FPS is lower than 0
   */
  public RedrawJobImpl( @NotNull final Canvas whereTo, @NotNull final Level level, final int refreshPerSecond ) throws IllegalArgumentException {
    super( whereTo, level, refreshPerSecond, COMPONENTS_LIST );
    if ( refreshPerSecond < 0 ) {
      throw new IllegalArgumentException( "FPS can't be less than 0" );
    }
    Map<Set<Pipe>, Integer> facesMap = level.getFacesMap();
    UnmodifiableUndirectedGraph<Junction, Pipe> levelMap = level.getMap();
    this.faces = new HashMap<>( facesMap.size() );

    for (Map.Entry<Set<Pipe>, Integer> faceAndId : facesMap.entrySet()) {
      /* Per ogni faccia ... */
      Pipe firstPipe = faceAndId.getKey().iterator().next();
      Junction lastJunction = levelMap.getEdgeSource( firstPipe );
      Pipe lastPipe = null;
      GeneralPath faceShape = new GeneralPath();
      faceShape.moveTo( lastJunction.getPosition().x, lastJunction.getPosition().y );
      while ( ! firstPipe.equals( lastPipe ) ) {
        /* Aggiunge la linea*/

        Pipe nextPipe = null;
        final Set<Pipe> connectedSegments = new HashSet<>( levelMap.edgesOf( lastJunction ) );
        if ( lastPipe == null ) {
          /* È il primo loop */
          lastPipe = firstPipe;
        }

        /* Scarta il segmento già percorso */
        connectedSegments.remove( lastPipe );

        for (Pipe perimeterSegment : faceAndId.getKey()) {
          /* Tra tutti i segmenti del perimetro seleziona solo quello che confina con il vertice corrente */
          if ( connectedSegments.contains( perimeterSegment ) ) {
            nextPipe = perimeterSegment;
            break;
          }
        }


        if ( nextPipe == null ) {
          if( THROW_EXCEPTION_ON_FACES_ERROR ) {
            throw new IllegalArgumentException("Invalid faces set");
          } else {
            lastPipe = firstPipe;
            faceShape.closePath();
          }
        } else {

          lastPipe = nextPipe;

          final Junction edgeSource = levelMap.getEdgeSource( nextPipe );
          lastJunction = edgeSource.equals( lastJunction ) ? levelMap
              .getEdgeTarget( nextPipe ) : edgeSource;

          final Point junctionPosition = lastJunction.getPosition();
          faceShape.lineTo( junctionPosition.x, junctionPosition.y );
        }
      }

      faces.put( new OpaqueRandomFace( faceShape ), faceAndId.getValue() );
    }

    this.levelBounds = makeBoundRectangle( level.getMap() );
  }

  @NotNull
  private static Rectangle makeBoundRectangle( @NotNull Graph<Junction, Pipe> levelGraph ) {
    int minY = Integer.MAX_VALUE;
    int maxY = 0;
    int minX = Integer.MAX_VALUE;
    int maxX = 0;
    for (Junction vertex : levelGraph.vertexSet()) {
      final Point vertexPosition = vertex.getPosition();
      minX = Math.min( vertexPosition.x, minX );
      maxX = Math.max( vertexPosition.x, maxX );
      minY = Math.min( vertexPosition.y, minY );
      maxY = Math.max( vertexPosition.y, maxY );
    }

    return new Rectangle( minX, minY, maxX - minX, maxY - minY );
  }

  @Override
  protected final void drawComponent( @NotNull final COMPONENTS component, @NotNull final Graphics2D g2d ) throws Exception {
    if ( GameSettings.getInstance().getInstanceValue( GameSettings.INTEGER_SETTINGS_TYPE.ANTIALIAS ) != 0 ) {
      g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
    }

    switch ( component ) {
      case CORE_VIEW:
        drawCore( g2d );
        break;
      case SCORE_VIEW:
        if ( getLevel() instanceof ScoreLevel ) {
          drawScore( g2d );
        }
        break;
      case LIVES_VIEW:
        if ( getLevel() instanceof LivesLevel ) {
          drawLives( g2d );
        }
        break;
    }


  }

  @Nullable
  @Override
  protected final Rectangle getComponentRect( @NotNull final COMPONENTS component ) {
    final Dimension windowSize = GraphicsEnv.getInstance().getWindowSize();

    switch ( component ) {

      case CORE_VIEW:

        return new Rectangle( windowSize );
      case SCORE_VIEW:
        if ( getLevel() instanceof ScoreLevel ) {

          final int yPosition = (int) Math.ceil( windowSize.height * ( 1.0 - SCORE_HEIGHT_DIMENSION ) );

          return new Rectangle( 0,
                                yPosition,
                                (int) Math.floor( windowSize.width * SCORE_WIDTH_DIMENSION ),
                                windowSize.height - yPosition );
        }

      case LIVES_VIEW:
        if ( getLevel() instanceof LivesLevel ) {
          final int yPosition = (int) Math.ceil( windowSize.height * ( 1.0 - LIVES_HEIGHT_DIMENSION ) );
          return new Rectangle( (int) Math.floor( windowSize.width * SCORE_WIDTH_DIMENSION ) + 1,
                                yPosition,
                                (int) Math.ceil( windowSize.width * LIVES_WIDTH_DIMENSION ),
                                windowSize.height - yPosition );
        }
    }

    return null;

  }

  private void drawCore( @NotNull Graphics2D g2d ) throws Exception {
    final Level level = getLevel();
    final Player player = level.getPlayer();
    final Point2D screenPlayerPosition;

    if ( player instanceof AnimatedElement ) {
      final EntityMovementAnimation animation = ( (AnimatedElement) player ).getAnimation();
      Point2D animationPosition;
      if ( animation != null ) {
        try {
          animationPosition = animation.getActualPosition();
        } catch ( TerminatedAnimationException e ) {
          animationPosition = player.getPosition();
        }

      } else {
        animationPosition = player.getPosition();
      }


      screenPlayerPosition = GraphicsEnv.getInstance().centeredGamePointToScreen( animationPosition );


    } else {
      screenPlayerPosition = GraphicsEnv.getInstance().centeredGamePointToScreen( player.getPosition() );
    }

    int actualGamePointSize = GraphicsEnv.getInstance().getScaledPointDimension();
    double screenMaxLateralSize = actualGamePointSize * MAX_LATERAL_SPACE;
    final Rectangle2D gameScreenBounds = new Rectangle2D.Double( ( this.levelBounds.x * actualGamePointSize ) - screenMaxLateralSize,
                                                                 ( this.levelBounds.y * actualGamePointSize ) - screenMaxLateralSize,
                                                                 ( this.levelBounds.width * actualGamePointSize ) + ( screenMaxLateralSize * 2 ),
                                                                 ( this.levelBounds.height * actualGamePointSize ) + ( screenMaxLateralSize * 2 ) );
    final Rectangle clipBounds = g2d.getClipBounds();
    final Rectangle2D gameScreen = new Rectangle2D.Double( screenPlayerPosition.getX() - ( clipBounds.width / 2 ),
                                                           screenPlayerPosition.getY() - ( clipBounds.height / 2 ),
                                                           clipBounds.width, clipBounds.height );

    if ( ! gameScreenBounds.contains( gameScreen ) ) {

      if ( gameScreen.getWidth() < gameScreenBounds.getWidth() ) {
        if ( gameScreen.getMaxX() > gameScreenBounds.getMaxX() ) {
          gameScreen.setFrame( gameScreen.getX() - ( gameScreen.getMaxX() - gameScreenBounds.getMaxX() ),
                               gameScreen.getY(),
                               gameScreen.getWidth(),
                               gameScreen.getHeight() );
        }

        if ( gameScreen.getMinX() < gameScreenBounds.getMinX() ) {
          gameScreen.setFrame( gameScreenBounds.getMinX(), gameScreen.getMinY(), gameScreen.getWidth(), gameScreen.getHeight() );
        }
      } else {
        gameScreen.setFrame( gameScreenBounds.getCenterX() - ( gameScreen.getWidth() / 2 ), gameScreen.getMinY(),
                             gameScreen.getWidth(), gameScreen.getHeight() );
      }

      if ( gameScreen.getHeight() < gameScreenBounds.getHeight() ) {
        if ( gameScreen.getMaxY() > gameScreenBounds.getMaxY() ) {
          gameScreen.setFrame( gameScreen.getX(),
                               gameScreen.getY() - ( gameScreen.getMaxY() - gameScreenBounds.getMaxY() ),
                               gameScreen.getWidth(),
                               gameScreen.getHeight() );
        }

        if ( gameScreen.getMinY() < gameScreenBounds.getMinY() ) {
          gameScreen.setFrame( gameScreen.getMinX(), gameScreenBounds.getMinY(), gameScreen.getWidth(), gameScreen.getHeight() );
        }
      } else {
        gameScreen.setFrame( gameScreenBounds.getMinX(), gameScreenBounds.getCenterY() - ( gameScreen.getHeight() / 2 ),
                             gameScreen.getWidth(), gameScreen.getHeight() );
      }

    }
    g2d.translate( - gameScreen.getX(), - gameScreen.getY() );


    for (Map.Entry<Face, Integer> faceEntry : this.faces.entrySet()) {
      final Face face = faceEntry.getKey();
      face.setColored( level.isFaceColored( faceEntry.getValue() ) );
      face.draw( g2d );
    }

    for (Pipe pipe : level.getMap().edgeSet()) {
      pipe.draw( g2d );
    }

    for (Junction junction : level.getMap().vertexSet()) {
      junction.draw( g2d );
    }

    for (Monster mob : level.getMonsters()) {
      mob.draw( g2d );
    }

    player.draw( g2d ) ;
  }

  private void drawScore( @NotNull Graphics2D g2d ) throws Exception {
    final Rectangle clipBounds = getComponentRect( COMPONENTS.SCORE_VIEW );
    assert clipBounds != null;
    final Level level = getLevel();
    assert level instanceof ScoreLevel;

    g2d.setFont( GraphicsEnv.getInstance().getScoreFont() );
    g2d.setColor( Color.GREEN );
    g2d.drawString( "" + ( (ScoreLevel) level ).getScore(), clipBounds.x, clipBounds.y + clipBounds.height - 1 );
  }

  private void drawLives( @NotNull Graphics2D g2d ) throws Exception {
    final Rectangle clipBounds = getComponentRect( COMPONENTS.LIVES_VIEW );
    assert clipBounds != null;
    final Level level = getLevel();
    assert level instanceof LivesLevel;

    g2d.setFont( GraphicsEnv.getInstance().getScoreFont() );
    g2d.setColor( Color.RED );
    g2d.drawString( "" + ( (LivesLevel) level ).getActualLives(), clipBounds.x, clipBounds.y + clipBounds.height - 1 );
  }

  public static enum COMPONENTS {
    CORE_VIEW, SCORE_VIEW, LIVES_VIEW
  }

  @Override
  @NonNls
  public String toString() {
    return "CoreRedrawJob{" +
           "faces=" + faces +
           ", levelBounds=" + levelBounds +
           "} " + super.toString();
  }
}
TOP

Related Classes of org.gbcpainter.view.draw.RedrawJobImpl

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.