Ship04.java

package com.bozoid.cis370.hw04;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*; // for AffineTransform
import javax.swing.*;
import java.util.Date; // for getTime()


/**
A simple spaceship for CISC370-011 homework #4.

@author Walt Leipold
*/
public class Ship04
{
    /**
    Create a <code>Ship04</code> at the specified location and angle.

    @param x initial x-location of the Ship04
    @param y initial y-location of the Ship04
    @param theta initial angle of the Ship04 (vertical==PI/2)
    */
    public Ship04(double x,double y,double theta)
    {
        ship_x = x;
        ship_y = y;
        ship_theta = theta;
        fuel_used = 0.0;
        lastTime = (new Date()).getTime();
    }

    /**
    Draw the ship on the specified graphics context.

    @param g <code>Graphics</code> context to draw on
    @param cmd_main is the main thruster firing?
    @param cmd_cw is the clockwise thruster firing?
    @param cmd_ccw is the counterclockwise firing?
    */
    public void drawShip(Graphics g,
        boolean cmd_main,
        boolean cmd_cw,
        boolean cmd_ccw)
    {
        AffineTransform af = new AffineTransform();
        af.scale(1.0,-1.0); // To get a right-handed coord system.
        af.translate(ship_x,ship_y);
        af.rotate(ship_theta);
        vplot(g,hull,ship_color,af);
        if (cmd_main)
            vplot(g,flame,flame_color,af);
        if (cmd_cw)
            vplot(g,rcs_cw,flame_color,af);
        if (cmd_ccw)
            vplot(g,rcs_ccw,flame_color,af);
    }

    /**
    Plot a list of point lists in the given color, with coordinates
    transformed according the the given AffineTransform.

    @param g The graphics context.
    @param v An array of arrays of doubles, each of which stores 
        a list of points in [x,y,x,y,...] order.  For each array 
        of doubles, the method plots a line of the specified color 
        between each adjacent pair of points.
    @param c <code>Color</code> to draw with.
    @param af An <code>AffineTransform</code> to transform each (x,y) 
        pair from simulation space to window coordinates before 
        plotting.
    */
    public static void vplot(Graphics g,
        double[][] v,Color c,AffineTransform af)
    {
        int i,j;

        Graphics2D g2 = (Graphics2D)g;
        g2.setPaint(c);
        for (i=0; i<v.length; i++) {
            double temp[] = new double[v[i].length];
            af.transform(v[i],0,temp,0,v[i].length/2);
            for (j=0; j<v[i].length-3; j+=2)
                g2.drawLine(
                    (int)(temp[j]),  (int)(temp[j+1]),
                    (int)(temp[j+2]),(int)(temp[j+3]));
            }
    }

    /**
    Every tick of the timer, simulate the fuel consumption and
    constant-speed rotation of the ship.

    @param cmd_main is the main thruster firing?
    @param cmd_cw is the clockwise thruster firing?
    @param cmd_ccw is the counterclockwise thruster firing?
    */
    public void oneTick(
        boolean cmd_main,
        boolean cmd_cw,
        boolean cmd_ccw)
    {
        long tstamp = (new Date()).getTime();
        double time_increment = // Time (secs) since last frame.
            (double)(tstamp - lastTime)/1000.0;
        if (active) {
            double v_theta = 0.0;
            if (cmd_cw) { // Clockwise thruster.
                fuel_used += CW_FLOW * time_increment;
                v_theta -= ANG_VEL;
                }
            if (cmd_ccw) { // Counterclockwise thruster.
                fuel_used += CCW_FLOW * time_increment;
                v_theta += ANG_VEL;
                }
            if (cmd_main) { // Main thruster.
                fuel_used += MAIN_FLOW * time_increment;
                }
            ship_theta += v_theta * time_increment;
            }
        lastTime = tstamp;
    }

    // Accessors.
    public boolean getActive() { return active; }
    public double getX() { return ship_x; }
    public double getY() { return ship_y; }
    public double getTheta() { return ship_theta; }
    public double getFuel() { return fuel_used; }

    // Mutators.
    public void setActive(boolean flag) { active = flag; }
    public void setX(double x) { ship_x = x; }
    public void setY(double y) { ship_y = y; }

    // Where is the ship?
    private double ship_x = 0.0;
    private double ship_y = 0.0;
    private double ship_theta = Math.PI/2.0; 

    private double fuel_used = 0.0; // Fuel accumulator.
    private long lastTime = 0; // Real time of last sim step.
    private boolean active = true; // Is the simulation active?
    private double ANG_VEL = Math.PI/10.0; // 18 deg/sec

    // Flow rates in kg/s.
    static final double CW_FLOW = 5.0;
    static final double CCW_FLOW = 5.0;
    static final double MAIN_FLOW = 50.0;

    // Colors and point lists for the ship and flame shapes.
    private Color ship_color = Color.WHITE;
    private Color flame_color = Color.RED;
    private static double[][] hull,flame,rcs_ccw,rcs_cw;
    static {
        hull = new double[][] { // The ship.
            { 78.0,   0.0, // hull
              40.0,   9.0,
              26.0,  10.0,
              -8.0,  10.0,
             -50.0,   6.0,
             -50.0,  -6.0,
              -8.0, -10.0,
              26.0, -10.0,
              40.0,  -9.0,
              78.0,   0.0},
            { 35.0,   3.0, // window 1
              32.0,   0.0,
              35.0,  -3.0,
              38.0,   0.0,
              35.0,   3.0},
            { 22.0,   3.0, // window 2
              19.0,   0.0,
              22.0,  -3.0,
              25.0,   0.0,
              22.0,   3.0},
            {  9.0,   3.0, // window 3
               6.0,   0.0,
               9.0,  -3.0,
              12.0,   0.0,
               9.0,   3.0},
            {-50.0,   6.0, // right fin
              -8.0,  10.0,
             -70.0,  34.0,
             -50.0,   6.0},
            {-50.0,  -6.0, // left fin
              -8.0, -10.0,
             -70.0, -34.0,
             -50.0,  -6.0},
            {-70.0,   2.0, // center fin
              -8.0,   0.0,
             -70.0,  -2.0,
             -70.0,   2.0}};
        flame = new double[][] { // Main thruster flame.
            { -50.0, -6.0, -96.0,  0.0, -50.0,  6.0}};
        rcs_ccw = new double[][] { // Counterclockwise thruster flame.
            {  26.0, -10.0,  26.0, -34.0},
            {  26.0, -10.0,  36.0, -26.0},
            {  26.0, -10.0,  16.0, -26.0},
            {  -8.0,  10.0,  -8.0,  34.0},
            {  -8.0,  10.0,   0.0,  26.0},
            {  -8.0,  10.0, -16.0,  26.0}};
        rcs_cw = new double[][] { // Clockwise thruster flame.
            {  26.0,  10.0,  26.0,  34.0},
            {  26.0,  10.0,  36.0,  26.0},
            {  26.0,  10.0,  16.0,  26.0},
            {  -8.0, -10.0,  -8.0, -34.0},
            {  -8.0, -10.0,   0.0, -26.0},
            {  -8.0, -10.0, -16.0, -26.0}};
        }
}