Package org.gbcpainter.view

Source Code of org.gbcpainter.view.GameHolder

package org.gbcpainter.view;

import net.jcip.annotations.GuardedBy;
import org.gbcpainter.env.GameSettings;
import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.env.LanguageDictionary;
import org.gbcpainter.game.levels.CampaignLevel;
import org.gbcpainter.game.levels.Level;
import org.gbcpainter.game.LevelManager;
import org.gbcpainter.game.LevelStopListener;
import org.gbcpainter.game.LevelManagerImpl;
import org.gbcpainter.geom.PERPENDICULAR_DIRECTION;
import org.gbcpainter.view.draw.DrawListener;
import org.gbcpainter.view.draw.RedrawJob;
import org.gbcpainter.view.draw.RedrawJobImpl;
import org.gbcpainter.view.menu.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
* Canvas that holds the game.
* <p/>
* It dispatches keyboard events to a {@link org.gbcpainter.game.LevelManager}. Drawings are made from a {@link org.gbcpainter.view.draw.RedrawJob}.
* <p/>
* These two components notify the game holder via {@link org.gbcpainter.game.LevelStopListener} and {@link org.gbcpainter.view.draw.DrawListener} oberver methods.
*
* @author Lorenzo Pellegrini
*/
public class GameHolder extends Canvas implements LevelStopListener, DrawListener {

  private static final int BEFORE_FADEOUT_END_VIEW_SWITCH = 10;

  private static final int AFTER_REDRAW_MANAGER_DELAY = 100;

  @NotNull
  private final Level level;

  @Nullable
  @GuardedBy( "this" )
  private volatile LevelManager manager = null;

  @Nullable
  @GuardedBy( "this" )
  private volatile RedrawJob redrawer = null;

  @GuardedBy( "this" )
  private volatile boolean closing = false;

  public GameHolder( @NotNull Level level ) {
    super( GraphicsEnv.getInstance().getGraphicsConfiguration() );
    this.level = level;

    this.setFocusable( true );
    this.setBackground( Color.LIGHT_GRAY );
    this.setIgnoreRepaint( true );

    this.createDrawJob();

    this.addKeyListener( new KeyAdapter() {

      @Override
      public void keyPressed( final KeyEvent e ) {

        PERPENDICULAR_DIRECTION direction = getDirection( e.getKeyCode() );
        synchronized (GameHolder.this) {
          if ( direction != null && GameHolder.this.manager != null ) {
            GameHolder.this.manager.setDirectionSelected( direction, true );
          }
        }
      }

      @Override
      public void keyReleased( final KeyEvent e ) {
        PERPENDICULAR_DIRECTION direction = getDirection( e.getKeyCode() );
        synchronized (GameHolder.this) {
          if ( e.getKeyCode() == GameSettings.getInstance()
                                             .getValue( GameSettings.INTEGER_SETTINGS_TYPE.KEY_PAUSE ) ) {
            if ( GameHolder.this.manager != null ) {
              GameHolder.this.manager.pause( true );
            }
            GameHolder.this.startFadeout( new Runnable() {
              @Override
              public void run() {
                ViewManager.getMainView()
                           .swapToMenuView( new PauseMenu( GameHolder.this ) );
              }
            } );
          } else if ( direction != null ) {
            if ( GameHolder.this.manager != null ) {
              GameHolder.this.manager.setDirectionSelected( direction, false );
            }
          }
        }
      }
    } );
  }

  @Nullable
  private static PERPENDICULAR_DIRECTION getDirection( int key ) {
    final GameSettings singleton = GameSettings.getInstance();
    if ( singleton.getValue( GameSettings.INTEGER_SETTINGS_TYPE.KEY_DOWN ) == key ) {
      return PERPENDICULAR_DIRECTION.DOWN;
    }
    if ( singleton.getValue( GameSettings.INTEGER_SETTINGS_TYPE.KEY_UP ) == key ) {
      return PERPENDICULAR_DIRECTION.UP;
    }
    if ( singleton.getValue( GameSettings.INTEGER_SETTINGS_TYPE.KEY_LEFT ) == key ) {
      return PERPENDICULAR_DIRECTION.LEFT;
    }
    if ( singleton.getValue( GameSettings.INTEGER_SETTINGS_TYPE.KEY_RIGHT ) == key ) {
      return PERPENDICULAR_DIRECTION.RIGHT;
    }

    return null;
  }

  /**
   * {@inheritDoc}
   * <p/>
   * When this method is called, the level (manager + drawer) is started.
   */
  @Override
  public synchronized void addNotify() {
    super.addNotify();
    try {
      this.closing = false;

      this.requestFocus();
      this.requestFocusInWindow();

      this.createDrawJobIfNeeded();
      startDrawJob();
    } catch ( Exception e ) {
      this.closing = true;
      new ErrorDialog( ViewManager.getMainView().getFrame(), LanguageDictionary.ERROR_STRING,
                       LanguageDictionary.ERROR_DRAW_LEVEL, e );
      EventQueue.invokeLater( new Runnable() {
        @Override
        public void run() {
          ViewManager.getMainView().swapToMenuView( new MainMenu() );
        }
      } );
    }

    if(!closing) {
      new Thread( new Runnable() {
        @Override
        public void run() {
          try {
            Thread.sleep( AFTER_REDRAW_MANAGER_DELAY );
          } catch ( InterruptedException ignored ) {
          }

          synchronized (GameHolder.this) {
            if ( ! closing ) {
              /*manager = new LevelManagerImpl( level );
              manager.pauseOnDeath( true );
              manager.setInterval( GameSettings.getInstance()
                                               .getValue( GameSettings.INTEGER_SETTINGS_TYPE.MOVE_MILLIS_TIMEOUT ) );
              manager.addLevelStopListener( GameHolder.this );
              manager.pause( false );*/

              createLevelJob();
              startLevelJob();

            }
          }
        }
      } ).start();
    }



  }

  /**
   * {@inheritDoc}
   * <p/>
   * When this method is called, the level (manager + drawer) is stopped.
   */
  @Override
  public synchronized void removeNotify() {
    this.closing = true;

    removeDrawJob();

    super.removeNotify();

    removeLevelJob();
  }

  /**
   * Implementation for the {@link org.gbcpainter.game.LevelStopListener}, manages the lifetime of the level.
   *
   * @param stoppedLevel The stopped level.
   */
  @Override
  public synchronized void levelStopped( @NotNull final LevelManager ignored, @NotNull final Level stoppedLevel ) {
    if( this.closing || this.manager == null || this.redrawer == null) {
      return;
    }

    final Level level = getLevel();

    @Nullable
    final Runnable fadeoutAction;

    if ( this.manager.hasFailed() ) {
      /* Errore nel manager del livello */
      this.closing = true;
      fadeoutAction = null;
      stopDrawJob();
      new ErrorDialog( ViewManager.getMainView().getFrame(), LanguageDictionary.ERROR_STRING, LanguageDictionary.ERROR_UPDATING_LEVEL, this.manager.getError() );

      EventQueue.invokeLater( new Runnable() {
        @Override
        public void run() {
          ViewManager.getMainView().swapToMenuView( new MainMenu() );
        }
      } );
    } else if ( level.isWin() ) {
      /* Il giocatore ha vinto il livello */
      this.closing = true;
      final String nextLevel;
      if ( level instanceof CampaignLevel ) {
        nextLevel = ( (CampaignLevel) level ).getNextLevel();
      } else {
        nextLevel = null;
      }

      fadeoutAction = new Runnable() {
        @Override
        public void run() {
          ViewManager.getMainView().swapToMenuView( new LevelWinMenu( nextLevel ) );
        }
      };

    } else if ( ! level.isAlive() && level.isEnded() ) {
      /* Il giocatore ha perso tutte le vite */
      this.closing = true;
      fadeoutAction = new Runnable() {
        @Override
        public void run() {
          ViewManager.getMainView().swapToMenuView( new GameOverMenu( GameHolder.this ) );
        }
      };

    } else if ( ! level.isAlive() ) {
      /* Il giocatore ha perso una vita ma non tutte */
      this.closing = true;
      fadeoutAction = new Runnable() {
        @Override
        public void run() {
          level.restart();
          ViewManager.getMainView().swapToMenuView( new LevelLostMenu( GameHolder.this ) );
        }
      };
    } else {
      fadeoutAction = null;
    }

    if ( fadeoutAction != null ) {
      startFadeout( fadeoutAction );
    }
  }


  private void startFadeout( @NotNull final Runnable delayedAction ) {
    new Thread( new Runnable() {
      @Override
      public void run() {
        final RedrawJob drawJob;
        synchronized (GameHolder.this) {
          drawJob = GameHolder.this.redrawer;
        }
        if ( drawJob != null ) {
          final long time = drawJob.startFadeOut();
          try {
            Thread.sleep( Math.max( 0, time - BEFORE_FADEOUT_END_VIEW_SWITCH ) );
          } catch ( InterruptedException ignored ) {}
        }

        EventQueue.invokeLater( delayedAction );
      }

    } ).start();
  }

  /**
   * Informs the observer that an error occurred when in the draw job
   *
   * @param job          The drawing manager
   * @param stoppedLevel The managed level
   */
  @Override
  public synchronized void drawStopped( @NotNull final RedrawJob job, @NotNull final Level stoppedLevel ) {
    if( (!this.closing) && this.redrawer != null && this.redrawer.hasFailed()) {
      this.closing = true;
      this.removeLevelJob();

      new ErrorDialog( ViewManager.getMainView().getFrame(), LanguageDictionary.ERROR_STRING, LanguageDictionary.ERROR_DRAW_LEVEL, this.redrawer.getError() );
      EventQueue.invokeLater( new Runnable() {
        @Override
        public void run() {
          ViewManager.getMainView().swapToMenuView( new MainMenu() );
        }
      } );
    }
  }

  @NotNull
  public Level getLevel() {
    return this.level;
  }

  @GuardedBy( "this" )
  private void createDrawJob() throws IllegalArgumentException {
    final int FPS = GameSettings.getInstance()
                                .getValue( GameSettings.INTEGER_SETTINGS_TYPE.REDRAW_FPS );
    if(this.redrawer != null) {
      this.redrawer.terminate();
    }

    this.redrawer = new RedrawJobImpl( this, this.getLevel(), FPS );
    this.redrawer.addLevelStopListener( this );
  }

  @GuardedBy( "this" )
  private void createDrawJobIfNeeded() throws IllegalArgumentException {
    if( this.redrawer == null || this.redrawer.isTerminated() ) {
      this.createDrawJob();
    }
  }

  @GuardedBy( "this" )
  private void removeDrawJob() {
    if ( this.redrawer != null ) {
      this.redrawer.terminate();
      this.redrawer = null;
    }
  }

  @GuardedBy( "this" )
  private boolean startDrawJob() {
    if( this.redrawer != null && !this.redrawer.isTerminated()) {
      this.redrawer.pauseDraw( false );
      return true;
    } else {
      return false;
    }
  }

  @GuardedBy( "this" )
  private boolean stopDrawJob() {
    if( this.redrawer != null) {
      this.redrawer.terminate();
      return true;
    } else {
      return false;
    }
  }

  @GuardedBy( "this" )
  private void createLevelJob() throws IllegalArgumentException {
    if(this.manager != null) {
      this.manager.terminate();
    }

    this.manager = new LevelManagerImpl( getLevel() );
    this.manager.pauseOnDeath( true );
    this.manager.setInterval( GameSettings.getInstance()
                                     .getValue( GameSettings.INTEGER_SETTINGS_TYPE.MOVE_MILLIS_TIMEOUT ) );
    this.manager.addLevelStopListener( GameHolder.this );
  }

  @GuardedBy( "this" )
  private void createLevelJobIfNeeded() throws IllegalArgumentException {
    if( this.manager == null || this.manager.isTerminated()) {
      this.createDrawJob();
    }
  }

  @GuardedBy( "this" )
  private void removeLevelJob() {
    if ( this.manager != null ) {
      this.manager.terminate();
      this.manager = null;
    }
  }

  @GuardedBy( "this" )
  private boolean startLevelJob() {
    if( this.manager != null && !this.manager.isTerminated()) {
      this.manager.pause( false );
      return true;
    } else {
      return false;
    }
  }

  @GuardedBy( "this" )
  private boolean stopLevelJob() {
    if( this.manager != null) {
      this.manager.terminate();
      return true;
    } else {
      return false;
    }
  }
}
TOP

Related Classes of org.gbcpainter.view.GameHolder

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.