LanderApplet07.java

package com.bozoid.cis370.hw07;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*; // for AffineTransform, Shape2D
import java.awt.font.*; // for Font
import java.text.*; // for NumberFormat
import java.util.Date; // for getTime()


/**
CISC370-011 homework #7: Applet

This applet is a transformed version of the application written 
for assignment #4.  It includes a 'Help' menu, gravity, and
some other goodies.

@author Walt Leipold
*/
public class LanderApplet07 extends JApplet 
{
    public void init()
    {
        JMenuBar jmb = new JMenuBar();
        setJMenuBar(jmb);
        sp = new AppletPanel07((JApplet)this);
        Container contentPane = getContentPane();
        contentPane.add(sp);
    }

    public void start() {  sp.run();  }
    public void stop() {  sp.stop();  }

    private AppletPanel07 sp;
}


class AppletPanel07 extends JPanel
{
    /**
    Constructor for the lander panel.  Note that the parent frame 
    is passed explicitly, so the panel can listen for window events.
    */
    public AppletPanel07(JApplet parentApplet)
    {
        // Allow the user to select the amount of gravity.
        JRadioButtonMenuItem noGrav,lightGrav,heavyGrav;
        AbstractAction noGravAction,lightGravAction,heavyGravAction;

        parent = parentApplet;

        // First, create a ship to simulate.
        ship = new Ship07(200.0,-200.0,Math.PI/2.0);

        // Some actions...
        noGravAction = new GravAction("None",ship,0.0);
        lightGravAction = new GravAction("Some",ship,4.0);
        heavyGravAction = new GravAction("Lots",ship,12.0);

        // Allow the user to control gravity.
        JMenu gravMenu = new JMenu("Gravity");
        ButtonGroup gravGroup = new ButtonGroup();
        noGrav = new JRadioButtonMenuItem(noGravAction);
        lightGrav = new JRadioButtonMenuItem(lightGravAction);
        heavyGrav = new JRadioButtonMenuItem(heavyGravAction);
        gravGroup.add(noGrav);
        gravGroup.add(lightGrav);
        gravGroup.add(heavyGrav);
        gravMenu.add(noGrav);
        gravMenu.add(lightGrav);
        gravMenu.add(heavyGrav);
        JMenuBar mb = parent.getJMenuBar();
        mb.add(gravMenu);
        noGrav.setSelected(true);

        // Add a 'Help' menu.
        JMenu helpMenu = new JMenu("Help");
        JMenuItem aboutItem = new JMenuItem("About");
        helpMenu.add(aboutItem);
        mb.add(helpMenu);
        final JPanel thisPane = this; // so action listener can refocus.
        aboutItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    JOptionPane.showMessageDialog(
                        (Container)parent,
                        (Object)aboutMessage,
                        "About LanderApplet07",
                        JOptionPane.INFORMATION_MESSAGE
                        );
                    }
                catch(Exception ex) {
                    }
                thisPane.requestFocus();
                }
            });

        // Hook up listeners with listenees.
        addMouseListener(new ShipMouse());
        addKeyListener(new ShipKey());

        // Make sure we can 'hear' keyboard events.
        setFocusable(true);

        // Start the simulation timer.
        simTimer = new Timer(25,new ShipTimer());
        simTimer.start();

        // Initialize everything else.
        setBackground(space_color);
        fuel_font = new Font("Monospaced",Font.PLAIN,10);
    }

    /**
    An action that changes the gravity on the spaceship.
    */
    class GravAction extends AbstractAction
    {
        public GravAction(String name,Ship07 ship,double gravity)
        {
            super(name);
            this.ship = ship;
            this.gravity = gravity;
        }

        public void actionPerformed(ActionEvent e)
        {
            ship.setGravity(gravity);
        }

        private Ship07 ship;
        private double gravity;
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        ship.drawShip(g,cmd_main,cmd_cw,cmd_ccw);
        drawFuel(g);
    }

    /**
    Draw the spaceship's fuel consumption in the bottom right
    corner of this panel.

    @param g a graphics context to draw in
    */
    private void drawFuel(Graphics g)
    {
        String s = nf.format(ship.getFuel());
        String s2 = blanks.substring(0,16-s.length()) + s;
        g.setColor(text_color);
        g.setFont(fuel_font);
        g.drawString(s2,5,getHeight()-5);
    }

    /**
    Every tick of the timer, simulate the physics of the ship,
    including fuel flow summation, translation and rotation, and
    accelerations both linear and rotational.
    */
    private class ShipTimer implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            ship.oneTick(cmd_main,cmd_cw,cmd_ccw);
            repaint();
        }
    }

    /**
    To control the main thruster and reaction control thrusters, 
    we watch for presses and releases of three control keys, and
    store their state in three instance variables.
    */
    private class ShipKey extends KeyAdapter
    {
        public void keyPressed(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_J) cmd_cw = true;
            else if (e.getKeyCode() == KeyEvent.VK_L) cmd_ccw = true;
            else if (e.getKeyCode() == KeyEvent.VK_K) cmd_main = true;
        }

        public void keyReleased(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_J) cmd_cw = false;
            else if (e.getKeyCode() == KeyEvent.VK_L) cmd_ccw = false;
            else if (e.getKeyCode() == KeyEvent.VK_K) cmd_main = false;
        }
    }

    /**
    Listen for mouse events and move the ship when a click is detected.
    */
    private class ShipMouse extends MouseAdapter
    {
        public void mousePressed(MouseEvent e)
        {
            ship.setX((double)e.getX());
            ship.setY((double)e.getY() * -1.0);
        }
    }

    public void run() {  simTimer.start();  ship.setActive(true); }
    public void stop() {  simTimer.stop();  ship.setActive(false); }

    private Ship07 ship = null;
    private final JApplet parent;
    static private String aboutMessage =
        "'LanderApplication' by W.S.Leipold\n\n" +
        "Use the 'j', 'k', and 'l' keys to control the rocket.\n" +
        "The 'j' and 'l' keys spin the rocket clockwise and\n" +
        "counterclockwise, respectively.  The 'k' key fires\n" +
        "the main engine.";

    // Which thrusters are thrusting?
    private boolean cmd_cw = false;
    private boolean cmd_ccw = false;
    private boolean cmd_main = false;

    // Timer to trigger each frame of the animation.
    private Timer simTimer = null;

    // Colors of various objects.
    private Color space_color = Color.BLACK;
    private Color text_color = Color.CYAN;

    // Formatter for fuel and (future) coordinate display.
    private static NumberFormat nf = null;
    static {
        nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);
        }

    // Some variables for fuel display.
    private Font fuel_font;
    private static final String blanks = "                   ";
}