/*
Copyright 2009 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.app.asteroids;
import sim.engine.*;
import sim.display.*;
import sim.portrayal.continuous.*;
import javax.swing.*;
import java.awt.*;
import sim.portrayal.simple.*;
import sim.portrayal.SimplePortrayal2D;
import java.awt.event.*;
/** AsteroidsWithUI is the GUIState of the game. It holds a single display and its frame; and the
Controller of the game is set to be a SimpleController rather than a SimpleController. AsteroidsWithUI
has a RateAdjuster which it uses to maintain an approximate consistent 60 frames per second.
*/
public class AsteroidsWithUI extends GUIState
{
/** The desired FPS */
public double FRAMES_PER_SECOND = 60;
/** The Display for the game. */
public Display2D display;
/** The window in which the Display resides. */
public JFrame displayFrame;
/** The field portrayal for the asteroids field. */
public ContinuousPortrayal2D fieldPortrayal = new ContinuousPortrayal2D();
/** The text overlay. */
public Overlay overlay = new Overlay(this);
/** Default main() for MASON */
public static void main(String[] args)
{
new AsteroidsWithUI().createController(); // randomizes by currentTimeMillis
}
/** Creates a SimpleController and starts it playing. */
public Controller createController()
{
SimpleController c = new SimpleController(this);
c.pressPlay();
return c;
}
/** Creates a default Asteroids game. */
public AsteroidsWithUI()
{
super(new Asteroids(System.currentTimeMillis()));
}
/** Creates an Asteroids game with the given Asteroids object. */
public AsteroidsWithUI(SimState state)
{
super(state);
}
/** Provides the name of the game. */
public static String getName() { return "Asteroids"; }
/** Starts the game. */
public void start()
{
super.start();
setupPortrayals();
}
/** Loads a game. This is unlikely to occur. */
public void load(SimState state)
{
super.load(state);
setupPortrayals();
}
/** Creates the portrayal and sets it up. The portrayal is set up to display
toroidally to show the asteroids properly. Additionally a RateAdjuster is
added to the GUIState minischedule to maintain an approximate rate of speed. */
public void setupPortrayals()
{
Asteroids asteroids = (Asteroids)state;
fieldPortrayal.setField(asteroids.field);
fieldPortrayal.setDisplayingToroidally(true);
scheduleRepeatingImmediatelyAfter(new RateAdjuster(FRAMES_PER_SECOND));
// reschedule the displayer
display.reset();
// redraw the display
display.repaint();
}
/** Sets up the initial game. Creates a display and sets it to be the only thing
that can be shown, and sans normal decorations. Adds listeners for keystrokes. */
public void init(final Controller c) // make it final so we can use it in the anonymous class
{
super.init(c);
// make the displayer
display = new Display2D(750,750,this)
{
public void quit() // we close our controller when we die
{
super.quit();
((SimpleController) c).doClose();
}
};
display.setBackdrop(Color.black);
displayFrame = display.createFrame();
displayFrame.setTitle("Asteroids");
c.registerFrame(displayFrame); // register the frame so it appears in the "Display" list
displayFrame.setVisible(true);
display.attach( fieldPortrayal, "Asteroids" );
display.attach( overlay, "Overlay" );
// some stuff to make this feel less like MASON:
// delete the header
display.remove(display.header);
// delete all listeners
display.removeListeners();
// delete the scroll bars
display.display.setVerticalScrollBarPolicy(display.display.VERTICAL_SCROLLBAR_NEVER);
display.display.setHorizontalScrollBarPolicy(display.display.HORIZONTAL_SCROLLBAR_NEVER);
// when we close the window, the application quits
displayFrame.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
// can't resize
displayFrame.setResizable(false);
// add antialiasing and interpolation
display.insideDisplay.setupHints(true, false, false);
// the window won't be the right size now -- modify it.
displayFrame.pack();
// Now we add in the listeners we want
addListeners(display);
}
/** Creates key listeners which issue requests to the simulation. */
public void addListeners(final Display2D display)
{
final Asteroids asteroids = (Asteroids)state;
final SimpleController cont = (SimpleController) controller;
// Make us able to take focus -- this is by default true usually anyway
display.setFocusable(true);
// Make us request focus whenever our window comes up
displayFrame.addWindowListener(new WindowAdapter()
{
public void windowActivated(WindowEvent e)
{
display.requestFocusInWindow();
}
});
// the display frame has just been set visible so we need to request focus once
display.requestFocusInWindow();
display.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
int c = e.getKeyCode();
switch(c)
{
case KeyEvent.VK_UP:
asteroids.actions[0] &= ~Ship.FORWARD;
break;
case KeyEvent.VK_DOWN:
asteroids.actions[0] &= ~Ship.HYPERSPACE;
break;
case KeyEvent.VK_LEFT:
asteroids.actions[0] &= ~Ship.LEFT;
break;
case KeyEvent.VK_RIGHT:
asteroids.actions[0] &= ~Ship.RIGHT;
break;
case KeyEvent.VK_SPACE:
asteroids.actions[0] &= ~Ship.FIRE;
break;
/*
case KeyEvent.VK_W:
asteroids.actions[1] &= ~Ship.FORWARD;
break;
case KeyEvent.VK_S:
asteroids.actions[1] &= ~Ship.HYPERSPACE;
break;
case KeyEvent.VK_A:
asteroids.actions[1] &= ~Ship.LEFT;
break;
case KeyEvent.VK_D:
asteroids.actions[1] &= ~Ship.RIGHT;
break;
case KeyEvent.VK_C:
asteroids.actions[0] &= ~Ship.FIRE;
break;
*/
default: // do nothing
break;
}
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
switch(c)
{
case KeyEvent.VK_UP:
asteroids.actions[0] |= Ship.FORWARD;
break;
case KeyEvent.VK_DOWN:
asteroids.actions[0] |= Ship.HYPERSPACE;
break;
case KeyEvent.VK_LEFT:
asteroids.actions[0] |= Ship.LEFT;
break;
case KeyEvent.VK_RIGHT:
asteroids.actions[0] |= Ship.RIGHT;
break;
case KeyEvent.VK_SPACE:
asteroids.actions[0] |= Ship.FIRE;
break;
/*
case KeyEvent.VK_W:
asteroids.actions[1] = Ship.FORWARD;
break;
case KeyEvent.VK_S:
asteroids.actions[1] = Ship.HYPERSPACE;
break;
case KeyEvent.VK_A:
asteroids.actions[1] = Ship.LEFT;
break;
case KeyEvent.VK_D:
asteroids.actions[1] = Ship.RIGHT;
break;
case KeyEvent.VK_C:
asteroids.actions[0] = Ship.FIRE;
break;
*/
case KeyEvent.VK_R: // Reset the board. Easiest way: stop and play, which calls start()
cont.pressStop();
cont.pressPlay();
break;
case KeyEvent.VK_P: // Pause or unpause the game
cont.pressPause();
break;
case KeyEvent.VK_M: // Call forth MASON's new simulation window
if (cont.getPlayState() != cont.PS_PAUSED) // pause it!
cont.pressPause();
cont.doNew();
// the MASON window belongs to our frame, so Java stupidly doesn't send
// us a window activated event when the MASON window is closed and our
// frame comes to the fore again. So we have to manually do request
// focus again here.
display.requestFocusInWindow();
break;
default: // do nothing
break;
}
}
});
}
/** Quits the game. */
public void quit()
{
super.quit();
if (displayFrame!=null) displayFrame.dispose();
displayFrame = null;
display = null;
}
}