diff --git a/trick_sims/Cannon/models/graphics/Makefile b/trick_sims/Cannon/models/graphics/Makefile new file mode 100644 index 00000000..c1756b7c --- /dev/null +++ b/trick_sims/Cannon/models/graphics/Makefile @@ -0,0 +1,36 @@ +SHELL = /bin/sh + +PROJECT_NAME = CannonDisplay +SRC_DIR = src +BUILD_DIR = build +CLASSES_DIR = $(BUILD_DIR)/classes +JAR_DIR = dist +MAIN_CLASS = CannonDisplay + +all: jar + +clean: + rm -rf $(BUILD_DIR) + rm -f manifest + +spotless: clean + rm -rf dist + +$(CLASSES_DIR): + @ mkdir -p $(CLASSES_DIR) + +compile: | $(CLASSES_DIR) + javac -sourcepath $(SRC_DIR) -d $(CLASSES_DIR) $(SRC_DIR)/CannonDisplay.java + +manifest: + @ echo "Main-Class: $(MAIN_CLASS)" > $@ + +$(JAR_DIR): + @ mkdir -p $(JAR_DIR) + +jar: compile manifest | $(JAR_DIR) + jar cvfm $(JAR_DIR)/$(PROJECT_NAME).jar manifest -C $(CLASSES_DIR) . + @ echo "-------------------------------------------------------------------------------" + @ echo " BUILD COMPLETE" + @ echo "The Java jar file (the Java Executable) is located at: $(JAR_DIR)/$(PROJECT_NAME).jar" + @ echo "-------------------------------------------------------------------------------" diff --git a/trick_sims/Cannon/models/graphics/src/CannonDisplay.java b/trick_sims/Cannon/models/graphics/src/CannonDisplay.java new file mode 100644 index 00000000..52c290b7 --- /dev/null +++ b/trick_sims/Cannon/models/graphics/src/CannonDisplay.java @@ -0,0 +1,784 @@ +/* + * Trick + * 2016 (c) National Aeronautics and Space Administration (NASA) + */ + +//package trick; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.*; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * + * @author penn + */ + +class ArenaMap extends JPanel { + + private int scale; + private Color skyColor; + private Color groundColor; + private Color barrelColor; + private Color cannonBallColor; + private Color carriageColor; + private Color wheelColor; + private Color[] explosionColors; + int explosionColors_n; + + // Origin of world coordinates in jpanel coordinates. + int Orig_w_j_x; + int Orig_w_j_y; + + int barrelAngle; + int muzzleVelocity; + double[] cannonBallPos; + + double explosionTime; + double[] barrelPivotPos; + double[] explosionPos; + double[] wheelCenterPos; + double wheelHubRadius; + double cannonBallRadius; + + double[] barrel_x, barrel_y; + int barrel_n; + + double[] carriage_x, carriage_y; + int carriage_n; + + double[] wheel_section_x, wheel_section_y; + int wheel_section_n; + + double[] explosion_poly_x, explosion_poly_y; + int explosion_poly_n; + + int[] poly_x, poly_y; + + public ArenaMap( int mapScale) { + + setScale(mapScale); + + skyColor = new Color(200,200,255); + groundColor = new Color(150,150,100); + barrelColor = new Color(10,10,10); + cannonBallColor = new Color(10,10,10); + carriageColor = new Color(120, 60, 40); + wheelColor = new Color(144, 72, 48); + + explosionColors = new Color[] + { new Color(255, 63, 3), + new Color(255, 127, 15), + new Color(255, 191, 63), + new Color(255, 255, 255) }; + explosionColors_n = 4; + + barrelAngle = 0; + muzzleVelocity = 0; + + explosionTime = 0.0; + cannonBallPos = new double[] + // { -4.00, 37.00}; + {-0.1020, 0.9400}; + barrelPivotPos = new double[] + // { -4.00, 37.00}; + {-0.1020, 0.9400}; + explosionPos = new double[] + { 5.0800, 0.0000}; + wheelCenterPos = new double[] + // { 0.00, 25.00}; + { 0.0000,0.6350,}; + wheelHubRadius = 0.1524; + cannonBallRadius = 0.1524; + + barrel_x = new double[] + //{ 50.00, 3.00,-19.00,-23.00,-25.00,-25.00,-25.00,-23.00,-19.00, 3.00, + // 50.00}; + { 1.2700, 0.0762,-0.4826,-0.5842,-0.6350,-0.6350,-0.6350,-0.5842,-0.4826, 0.0762, + 1.2700}; + + barrel_y = new double[] + // { 4.00, 6.00, 6.00, 5.00, 2.00, 0.00, -2.00, -5.00, -6.00, -6.00, + // -4.00}; + { 0.1016, 0.1524, 0.1524, 0.1270, 0.0508, 0.0000,-0.0508,-0.1270,-0.1524,-0.1524, + -0.1016}; + barrel_n = 11; + + carriage_x = new double[] + // {-49.00, 1.00, 0.00, 6.00, 8.00, 17.00, 14.00, 1.00, 2.00, 2.00, + // 0.00, -1.00, -2.00,-52.00,-55.00,-57.00,-58.00,-58.00,-57.00,-56.00}; + {-1.2446, 0.0254, 0.0000, 0.1524, 0.2032, 0.4318, 0.3556, 0.0254, 0.0508, 0.0508, + 0.0000,-0.0254,-0.0508,-1.3208,-1.3970,-1.4478,-1.4732,-1.4732,-1.4478,-1.4224}; + carriage_y = new double[] + // {-37.00,-13.00,-10.00, -7.00,-10.00, -6.00, 2.00, 2.00, 0.00, -1.00, + // -2.00, -1.00, 0.00,-30.00,-30.00,-31.00,-32.00,-35.00,-36.00,-37.00}; + {-0.9398,-0.3302,-0.2540,-0.1778,-0.2540,-0.1524, 0.0508, 0.0508, 0.0000,-0.0254, + -0.0508,-0.0254, 0.0000,-0.7620,-0.7620,-0.7874,-0.8128,-0.8890,-0.9144,-0.9398}; + carriage_n = 20; + + wheel_section_x = new double[] + // { 1.00, 1.00, 5.69, 6.47, 3.26, 0.00, -3.26, -6.47, -5.69, -1.00, + // -1.00}; + { 0.0254, 0.0254, 0.1445, 0.1643, 0.0828, 0.0000,-0.0828,-0.1643,-0.1445,-0.0254, + -0.0254}; + wheel_section_y = new double[] + // { 3.00, 22.00, 21.25, 24.15, 24.78, 25.00, 24.78, 24.15, 21.25, 22.00, + // 3.00}; + { 0.0762, 0.5588, 0.5398, 0.6134, 0.6294, 0.6350, 0.6294, 0.6134, 0.5398, 0.5588, + 0.0762}; + wheel_section_n = 11; + + explosion_poly_x = new double[] + // { 0.70, 0.97, 0.63, 0.78, 0.44, 0.43, 0.16, 0.00, -0.16, -0.43, + // -0.44, -0.78, -0.63, -0.97, -0.70, -0.97, -0.63, -0.78, -0.44, -0.43, + // -0.16, 0.00, 0.16, 0.43, 0.44, 0.78, 0.63, 0.97, 0.70}; + { 0.0178, 0.0246, 0.0160, 0.0198, 0.0112, 0.0109, 0.0041, 0.0000,-0.0041,-0.0109, + -0.0112,-0.0198,-0.0160,-0.0246,-0.0178,-0.0246,-0.0160,-0.0198,-0.0112,-0.0109, + -0.0041, 0.0000, 0.0041, 0.0109, 0.0112, 0.0198, 0.0160, 0.0246, 0.0178}; + explosion_poly_y = new double[] + // { 0.00, 0.22, 0.30, 0.62, 0.55, 0.90, 0.68, 1.00, 0.68, 0.90, + // 0.55, 0.62, 0.30, 0.22, 0.00, -0.22, -0.30, -0.62, -0.55, -0.90, + // -0.68, -1.00, -0.68, -0.90, -0.55, -0.62, -0.30, -0.22, 0.00}; + { 0.0000, 0.0056, 0.0076, 0.0157, 0.0140, 0.0229, 0.0173, 0.0254, 0.0173, 0.0229, + 0.0140, 0.0157, 0.0076, 0.0056, 0.0000,-0.0056,-0.0076,-0.0157,-0.0140,-0.0229, + -0.0173,-0.0254,-0.0173,-0.0229,-0.0140,-0.0157,-0.0076,-0.0056, 0.0000}; + explosion_poly_n = 29; + + poly_x = new int[30]; + poly_y = new int[30]; + } + + public void initCannonballPos() { + cannonBallPos[0] = -0.1020; + cannonBallPos[1] = 0.9400; + } + + public void setBarrelAngle(int value) { + barrelAngle = value; + repaint(); + } + + public int getBarrelAngle() { + return barrelAngle; + } + + public void setMuzzleVelocity(int value) { + muzzleVelocity = value; + repaint(); + } + + public int getMuzzleVelocity() { + return muzzleVelocity; + } + + public void setCannonBallPos(double x, double y) { + cannonBallPos[0] = x; + cannonBallPos[1] = y; + repaint(); + } + + public void setScale (int mapScale) { + if (mapScale < 4) { + scale = 4; + } else if (mapScale > 128) { + scale = 128; + } else { + scale = mapScale; + } + repaint(); + } + + public int getScale() { + return scale; + } + + public void drawCenteredCircle(Graphics2D g, int x, int y, int r) { + x = x-(r/2); + y = y-(r/2); + g.fillOval(x,y,r,r); + } + + private void doDrawing(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + rh.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + int ii, jj; + int width = getWidth(); + int height = getHeight(); + + // NOTE: is the orig of the world coordinate system expressed in jpanel coords. + // This origin tracks the position of the cannonball. + Orig_w_j_x = (width/2) - (int)(scale * cannonBallPos[0]); + Orig_w_j_y = getHeight()-20; + + // Draw Sky + g2d.setPaint(skyColor); + g2d.fillRect(0, 0, width, Orig_w_j_y); + + // |jpanel_x| = |origin_x| + scale * |1 0| * | cosa -sina| * |world_x| + // |jpanel_y| |origin_y| |0 -1| | sina cosa| |world_y| + + + // Draw cannon ball + g2d.setPaint(cannonBallColor); + int bx = (int)(Orig_w_j_x + scale * cannonBallPos[0]); + int by = (int)(Orig_w_j_y - scale * cannonBallPos[1]); + drawCenteredCircle(g2d, bx, by, (int)(scale * cannonBallRadius)); + + // Draw cannon barrel + double angle = Math.toRadians(barrelAngle); + for (ii = 0; ii 0.0) { + for (jj = 0; jj < explosionColors_n ; jj ++) { + for (ii = 0; ii < explosion_poly_n ; ii ++) { + double ex = explosionTime * explosionTime * 5.0 * (explosionColors_n - jj) * explosion_poly_x[ii]; + double ey = explosionTime * explosionTime * 5.0 * (explosionColors_n - jj) * explosion_poly_y[ii]; + poly_x[ii] = (int)(Orig_w_j_x + scale * (ex + explosionPos[0] )); + poly_y[ii] = (int)(Orig_w_j_y - scale * (ey + explosionPos[1] )); + } + g2d.setPaint(explosionColors[jj]); + g2d.fillPolygon(poly_x, poly_y, explosion_poly_n); + } + } + + // Draw Ground + g2d.setPaint(groundColor); + g2d.fillRect(0, Orig_w_j_y, width, height); + + + // Draw Range Markers + int tickRange = 50; + if (scale >= 8) tickRange =20; + if (scale >= 16) tickRange =10; + if (scale >= 32) tickRange = 5; + if (scale >= 64) tickRange = 1; + + double lower = -Orig_w_j_x / scale; + double upper = (width - Orig_w_j_x) / scale; + + int LL = ((int)(lower/tickRange) + 1) * tickRange; + int UU = ((int)(upper/tickRange) + 1) * tickRange; + + g2d.setPaint(Color.BLACK); + + for (int kk = LL ; kk < UU ; kk += tickRange) { + int mx = (int)(Orig_w_j_x + scale * kk); + g2d.drawLine( mx, Orig_w_j_y, mx, Orig_w_j_y+20); + g2d.drawString ( String.format("%d",kk), mx, Orig_w_j_y+15); + + } + + g2d.drawString ( String.format("SCALE: %d",scale), 20,20); + g2d.drawString ( String.format("Cannon barrel angle: [%d]",barrelAngle), 20,40); + g2d.drawString ( String.format("Cannon muzzle velocity: [%d]",muzzleVelocity), 20,60); + g2d.drawString ( String.format("Cannonball Pos: [%.2f, %.2f]",cannonBallPos[0],cannonBallPos[1]), 20,80); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + doDrawing(g); + } +} + +class ElevationPanel extends JPanel implements ChangeListener { + + static final int ANGLE_MIN = 0; + static final int ANGLE_MAX = 90; + static final int ANGLE_INIT = 45; + + private CannonDisplay cannonDisplay; + private JSlider angleSlider ; + + public ElevationPanel (CannonDisplay cd) { + cannonDisplay = cd; + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JLabel sliderLabel = new JLabel("Elev.", JLabel.CENTER); + sliderLabel.setAlignmentX(CENTER_ALIGNMENT); + + angleSlider = new JSlider(JSlider.VERTICAL, ANGLE_MIN, ANGLE_MAX, ANGLE_INIT); + angleSlider.addChangeListener(this); + angleSlider.setToolTipText("Angle of the Cannon barrel."); + angleSlider.setMajorTickSpacing(10); + angleSlider.setMinorTickSpacing(1); + angleSlider.setPaintTicks(true); + angleSlider.setPaintLabels(true); + + add(sliderLabel); + add(angleSlider); + + } + + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider)e.getSource(); + if (!source.getValueIsAdjusting()) { + cannonDisplay.setBarrelAngle( source.getValue() ); + } + } + + public void setValue(int value) { + if (value > ANGLE_MAX) value = ANGLE_MAX; + if (value < ANGLE_MIN) value = ANGLE_MIN; + angleSlider.setValue(value); + } +} + +class MuzzleVelPanel extends JPanel implements ChangeListener { + + static final int VEL_MIN = 0; + static final int VEL_MAX = 100; + static final int VEL_INIT = 50; + + private CannonDisplay cannonDisplay; + private JSlider velSlider ; + + public MuzzleVelPanel (CannonDisplay cd) { + cannonDisplay = cd; + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JLabel sliderLabel = new JLabel("Vel.", JLabel.CENTER); + sliderLabel.setAlignmentX(CENTER_ALIGNMENT); + + velSlider = new JSlider(JSlider.VERTICAL, VEL_MIN, VEL_MAX, VEL_INIT); + velSlider.addChangeListener(this); + velSlider.setToolTipText("Muzzle Velocity."); + velSlider.setMajorTickSpacing(10); + velSlider.setMinorTickSpacing(1); + velSlider.setPaintTicks(true); + velSlider.setPaintLabels(true); + + add(sliderLabel); + add(velSlider); + } + + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider)e.getSource(); + if (!source.getValueIsAdjusting()) { + cannonDisplay.setMuzzleVelocity( source.getValue() ); + } + } + + public void setValue(int value) { + if (value > VEL_MAX) value = VEL_MAX; + if (value < VEL_MIN) value = VEL_MIN; + velSlider.setValue(value); + } +} + +class ButtonPanel extends JPanel implements ActionListener { + + private CannonDisplay cannonDisplay; + private boolean fireCommand; + private boolean armCommand; + private boolean armAcknowledged; + private JButton fireButton, armButton, zoomOutButton, zoomInButton; + + public ButtonPanel(CannonDisplay cd) { + cannonDisplay = cd; + fireCommand = false; + armCommand = false; + armAcknowledged = false; + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + fireButton = new JButton("FIRE"); + fireButton.addActionListener(this); + fireButton.setActionCommand("fire"); + fireButton.setToolTipText("Fire Cannon"); + add(fireButton); + + armButton = new JButton("ARM"); + armButton.addActionListener(this); + armButton.setActionCommand("arm"); + armButton.setToolTipText("Arm Cannon"); + add(armButton); + + zoomOutButton = new JButton("\u25b2"); + zoomOutButton.addActionListener(this); + zoomOutButton.setActionCommand("zoomout"); + zoomOutButton.setToolTipText("Zoom in"); + add(zoomOutButton); + + zoomInButton = new JButton("\u25bc"); + zoomInButton.addActionListener(this); + zoomInButton.setActionCommand("zoomin"); + zoomInButton.setToolTipText("Zoom Out"); + add(zoomInButton); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + case "fire" : + if (armAcknowledged) { + fireCommand = true; + } + break; + case "arm" : + armCommand = true; + break; + case "zoomin": + cannonDisplay.setScale( cannonDisplay.getScale() / 2 ); + break; + case "zoomout": + cannonDisplay.setScale( cannonDisplay.getScale() * 2 ); + break; + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } + + public void AcknowledgeArmed() { + armCommand = false; + armAcknowledged = true; + fireButton.setForeground(Color.red); + } + + public void AcknowledgeFired() { + fireCommand = false; + fireButton.setForeground(Color.gray); + } + + public boolean getArmCommand() { + return armCommand; + } + public boolean getFireCommand() { + return fireCommand; + } + +} // class ButtonPanel + + +public class CannonDisplay extends JFrame { + + private ArenaMap arenaMap; + private ElevationPanel elevPanel; + private MuzzleVelPanel velPanel; + private BufferedReader in; + private DataOutputStream out; + private JPanel panelGroup0; + private JPanel panelGroup1; + private ButtonPanel buttonPanel; + private JButton b1, b2, b3, b4, b5; + + public CannonDisplay(ArenaMap arena) { + setTitle("Cannon Range"); + + elevPanel = new ElevationPanel(this); + velPanel = new MuzzleVelPanel(this); + arenaMap = arena; + + panelGroup1 = new JPanel(); + panelGroup1.setLayout(new BoxLayout(panelGroup1, BoxLayout.X_AXIS)); + panelGroup1.add(elevPanel); + panelGroup1.add(velPanel); + panelGroup1.add(arenaMap); + + buttonPanel = new ButtonPanel(this); + + panelGroup0 = new JPanel(); + panelGroup0.setLayout(new BoxLayout(panelGroup0, BoxLayout.Y_AXIS)); + panelGroup0.add(panelGroup1); + panelGroup0.add(buttonPanel); + add(panelGroup0); + + setScale(32); + setBarrelAngle(30); + setMuzzleVelocity(500); + setCannonBallPos (-0.1020, 0.9400); + + + setSize(800, 500); + setLocationRelativeTo(null); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + public int getBarrelAngle() { + return arenaMap.getBarrelAngle(); + } + + public void setBarrelAngle(int value) { + arenaMap.setBarrelAngle(value); + elevPanel.setValue(value); + } + + public int getMuzzleVelocity() { + return arenaMap.getMuzzleVelocity(); + } + + public void setMuzzleVelocity(int value) { + arenaMap.setMuzzleVelocity(value); + velPanel.setValue(value); + } + + public void setCannonBallPos(double x, double y) { + arenaMap.setCannonBallPos(x,y); + } + + public void setScale(int value) { + arenaMap.setScale(value); + } + + public int getScale() { + return arenaMap.getScale(); + } + + public void AcknowledgeArmed() { + buttonPanel.AcknowledgeArmed(); + } + + public void AcknowledgeFired() { + buttonPanel.AcknowledgeFired(); + } + + public boolean getArmCommand() { + return buttonPanel.getArmCommand(); + } + + public boolean getFireCommand() { + return buttonPanel.getFireCommand(); + } + + public void connectToServer(String host, int port ) throws IOException { + Socket socket = new Socket(host, port); + in = new BufferedReader( new InputStreamReader( socket.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); + } + + public void drawArenaMap() { + arenaMap.repaint(); + } + + private static void printHelpText() { + System.out.println( + "----------------------------------------------------------------------\n" + + "usage: java jar CannonDisplay.jar \n" + + "----------------------------------------------------------------------\n" + ); + } + + public static void main(String[] args) throws IOException, InterruptedException { + + String host = "localHost"; + int port = 0; + + int ii = 0; + while (ii < args.length) { + switch (args[ii]) { + case "-help" : + case "--help" : { + printHelpText(); + System.exit(0); + } break; + default : { + port = (Integer.parseInt(args[ii])); + } break; + } + ++ii; + } + +// if (port == 0) { +// System.out.println("No variable server port specified."); +// printHelpText(); +// System.exit(0); +// } + + int mapScale = 32 ; // pixels per meter. + ArenaMap arenaMap = new ArenaMap( mapScale); + CannonDisplay evd = new CannonDisplay( arenaMap); + evd.setVisible(true); + +// System.out.println("Connecting to: " + host + ":" + port); +// evd.connectToServer(host, port); +// +// evd.out.writeBytes("trick.var_set_client_tag(\"CannonDisplay\") \n"); +// evd.out.flush(); +// +// evd.out.writeBytes("trick.var_add(\"dyn.cannon.pos[0]\") \n" + +// "trick.var_add(\"dyn.cannon.pos[1]\") \n" + +// "trick.var_add(\"dyn.cannon.pos[1]\") \n"); +// evd.out.flush(); +// +// evd.out.writeBytes("trick.var_ascii() \n" + +// "trick.var_cycle(0.1) \n" + +// "trick.var_send() \n" ); +// evd.out.flush(); + + + boolean fireCommand = false; + boolean armCommand = false; + boolean armed = false; + boolean fired = false; + boolean impact = false; + double impactTime = 0.0; + int ticks = 0; + int cTimeRate = 0; + double cTime = 0.0; + int cticks = 0; + int exTimeRate = 0; // 0 or 1 + double exTime = 0.0; + int exticks = 0; + double posx = 0.0; + double posy = 0.0; + double posx0 = 0.0; + double posy0 = 0.0; + double exposx = 0.0; + double exposy = 0.0; + double speed = 0.0; + double angle = 0.0; + double elev = 0.0; + double simdt = 0.100; + + evd.drawArenaMap(); + + Boolean go = true; + while (go) { + Thread.sleep((int)(1000 * simdt)); + ticks ++; + + // === DATA OUT TO THE SIM === + angle = evd.getBarrelAngle(); + speed = evd.getMuzzleVelocity(); + + armCommand = evd.getArmCommand(); + fireCommand = evd.getFireCommand(); + // ============================= + + if (cTimeRate == 0) { + if (armCommand) { + posx0 = posx = -0.1020; + posy0 = posy = 0.9400; + armed = true; + fired = false; + } + if (fireCommand && armed ) { + elev = angle * (3.14159/180.0); + cticks = 0; + cTimeRate = 1; + armed = false; + fired = true; + } + } else { + cticks ++; + cTime = cticks * cTimeRate * simdt; + + posx = posx0 + cTime * speed * Math.cos(elev) ; + posy = posy0 + cTime * (speed * Math.sin(elev) + 0.5 * -9.81 * cTime); + + if (posy < 0.0) { + impact = true; + impactTime = ((2 * speed * Math.sin(elev)) / 9.81); + posx = impactTime * speed * Math.cos(elev); + posy = 0; + cTimeRate = 0; //Stop Cannonball + } + } + + if (exTimeRate == 0) { + if (impact) { + impact = false; + exposx = posx; + exposy = posy; + + // Start Explosion + exticks = 0; + exTimeRate = 1; + + } + } else { + exticks ++; + exTime = exticks * exTimeRate * simdt; + + if (exTime > 4.0) { + exTimeRate = 0; + exTime = 0.0; + } + } + + System.out.print("cTime = " + String.format("%.5f",cTime) ); + System.out.print(" exTime = " + String.format("%.5f",exTime) ); + System.out.println(" ticks = " + String.format("%d",ticks) ); + + // ==== DATA IN FROM THE SIM ==== + evd.setCannonBallPos(posx, posy); + if (armed) { + evd.AcknowledgeArmed(); + } + if (fired) { + evd.AcknowledgeFired(); + } + arenaMap.explosionTime = exTime; + arenaMap.explosionPos[0] = exposx; + arenaMap.explosionPos[1] = exposy; + + // ============================= + + + evd.drawArenaMap(); + } + } +}