Created
May 19, 2015 08:24
-
-
Save minhoolee/d74946457e674f9f265b to your computer and use it in GitHub Desktop.
Code for the game "Arcus Coelestis"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Author: Min Hoo Lee | |
* Date: March 20, 2015 - May 19, 2015 (start to end) | |
* | |
* Description: | |
* ColorShooter.java is the program containing the game "Arcus Coelestis". | |
* This game was created and designed for the Game-In-5-Weeks Project. | |
* It involves the user controlling a cannon to shoot colored balls | |
* (specified by HSV sliders) at randomly colored balls | |
* located in the top of the screen. If the ball hits a ball of the same color, | |
* the user scores a point. Otherwise, the user loses a life (one out of five). | |
* The user has 5 lives and every two points that the user scores, | |
* the amount of balls decreases by 4. | |
*/ | |
/** | |
* TESTING PLAN | |
* should work: click on buttons, change values of sliders, mouse click | |
* should not work: keys typed, keys pressed, clicking outside of box | |
*/ | |
// import libraries | |
import java.awt.*; | |
import java.awt.event.*; | |
import javax.swing.*; | |
import javax.swing.event.*; | |
import java.awt.geom.AffineTransform; | |
public class ColorShooter extends JFrame { // ColorShooter class header; holds the game 'Arcus Coelestis' | |
private CardHolder ch; // CardHolder panel | |
public static void main(String[]args) { // main method header, instantiate constructor | |
try { | |
new ColorShooter(); | |
} catch (NullPointerException npe) { // catch null pointer exception meaning an error in nested classes | |
System.out.println("Error: " + npe); | |
} | |
} | |
public ColorShooter() { // constructor header that instantiates the JFrame | |
super("Arcus Coelestis");// title JFrame 'Arcus Coelestis' | |
setSize(1350, 700);// JFrame size = 1350 (w) by 700 (h) | |
setDefaultCloseOperation(DISPOSE_ON_CLOSE); // respond to 'X' on JFrame | |
setLocation(30, 130); // set location on monitor to (30, 130) | |
setResizable(false); // cannot be resized | |
ch = new CardHolder(); // CardHolder panel holds the instructions panel and game panel | |
add(ch); | |
setVisible(true); // make JFrame show up | |
} | |
public class CardHolder extends JPanel { // CardHolder class header; panel that holds the instructions and game panels | |
private MainPanel main; // Main Panel | |
private InstructionsPanel1 instruct1; // Instructions Panel about gameplay (Part 1) | |
private InstructionsPanel2 instruct2; // Instructions Panel about gameplay (Part 2) | |
private InstructionsPanel3 instruct3; // Instructions Panel about HSV | |
private SeeMore1 more1; // see more about hue | |
private SeeMore2 more2; // see more about saturation | |
private SeeMore3 more3; // see more about value | |
private GameMode mode; // Panel for user to select game mode in | |
private GamePanel game; // Game Panel | |
private GameLose lose; // Panel to display if user wins or loses | |
private JButton instructButton; // button that redirects to first instructions panel | |
private JButton modeButton; // button that redirects to game mode panel | |
private JButton back; // back button | |
private CardLayout cards; // card layout | |
// create some colors to use for layout | |
private Color lightBlue = new Color(100, 255, 255); // light blue color for the backgrounds | |
private Color lighterBlue = new Color(200, 255, 255); // lighter blue for the box inside the backgrounds (border) | |
private Color lightGray = new Color (220, 220, 220); // light gray | |
private Color lightestGray = new Color(240, 240, 240); // lighter gray than light gray | |
private Color darkGray = new Color(100, 100, 100); // dark gray | |
private Color darkestGray = new Color(75, 75, 75); // darker gray; best gray shade for titles | |
private Color top = new Color(120, 120, 120); // same gray as one surrounding cannon (for top border) | |
private final int FAR_LEFT = 220; // furthest left that any graphics will go | |
private final int FAR_TOP = 150; // furthest top that any graphics will go (aside from title) | |
private final int TEXT_LEFT = 535; // furthest left that text instructions will go | |
private int topButton = 200; // highest place any button will go | |
private int topText = 220; // highest place any text will go | |
private boolean fromMain = false; // boolean that determines if skipped instructions and went to game mode panel (i.e. need to go back now) | |
// booleans for determining which game mode user selected | |
private boolean hueMode = true; // default mode is hueMode | |
private boolean satMode = false; | |
private boolean valMode = false; | |
private boolean allMode = false; | |
public CardHolder() {// constructor header | |
// set card layout | |
cards = new CardLayout(); | |
setLayout(cards); | |
// add the panels to the card layout | |
main = new MainPanel(); // landing panel for user to see name of game clearly | |
instruct1 = new InstructionsPanel1(); // instruct user how to play | |
instruct2 = new InstructionsPanel2(); // instruct user about how to play (cont.) | |
instruct3 = new InstructionsPanel3(); // instruct user about HSV | |
more1 = new SeeMore1(); // see more about hue | |
more2 = new SeeMore2(); // see more about saturation | |
more3 = new SeeMore3(); // see more about value | |
mode = new GameMode(); // user selects game mode first | |
game = new GamePanel(); // user actually plays game here | |
lose = new GameLose(); // depending on if user wins or loses, redirect to this panel | |
// add panels to card layout in order to swap | |
add(main, "main"); | |
add(instruct1, "instruct1"); | |
add(instruct2, "instruct2"); | |
add(instruct3, "instruct3"); | |
add(more1, "see more1"); | |
add(more2, "see more2"); | |
add(more3, "see more3"); | |
add(mode, "mode"); | |
add(game, "game"); | |
add(lose, "lose"); | |
} | |
public class MainPanel extends JPanel implements ActionListener { // MainPanel class header, implements Action Listener; Landing page for user, contains title | |
public MainPanel() { | |
setLayout(null); // set the layout as null (need to draw two buttons, but have the background remain the picture) | |
modeButton = new JButton("Game Mode"); // JButton with predefined text | |
modeButton.addActionListener(this); // add action listener | |
modeButton.setSize(675, 30); // position sizes and location in the same way as a panel with two column gridlayout would be | |
modeButton.setLocation(0, 648); | |
add(modeButton); // add button to first column | |
instructButton = new JButton("How To Play"); // JButton that says "How To Play" | |
instructButton.addActionListener(this); // add action listener and button to panel (South) | |
instructButton.setSize(675, 30); // position sizes and location in the same way as a panel with two column gridlayout would be | |
instructButton.setLocation(0, 648); | |
instructButton.setLocation(675, 648); | |
add(instructButton); // add button to second column | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
Image blurredGame = Toolkit.getDefaultToolkit().getImage("background.png"); // import background image | |
g.drawImage(blurredGame, 0, 0, 1350, 700, this); | |
// title = Bolded, Italicized, Helvetica, 48, white | |
Font title = new Font("helvetica", Font.BOLD, 140); | |
g.setFont(title); | |
g.setColor(darkGray); | |
g.drawString("ARCUS COELISTIS", 57, 337); | |
g.drawString("RAINBOW", 347, 487); | |
g.setColor(Color.WHITE); | |
g.drawString("ARCUS COELISTIS", 50, 330); | |
g.drawString("RAINBOW", 340, 480); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
JButton source = (JButton) e.getSource(); // find source of the button being clicked | |
if (source == instructButton) | |
cards.show(ch, "instruct1"); // show the instructions panel when button is pressed | |
else if (source == modeButton) { | |
fromMain = true; | |
cards.show(ch, "mode"); // show the game mode panel when button is pressed | |
} | |
} | |
} | |
public class InstructionsPanel1 extends JPanel { // instructions panel header; Teaches Gameplay Part 1 | |
public InstructionsPanel1() { // constructor header | |
setLayout(new BorderLayout()); // set the layout as Border Layout | |
TwoButtonPanel buttons = new TwoButtonPanel("Back", "main", "How To Play (Part 2)", "instruct2"); // two buttons: one to move back, one to move on | |
add(buttons, BorderLayout.SOUTH); | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(Color.GRAY); | |
g.fillRect(180, 98, 992, 532); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
Image background_text = Toolkit.getDefaultToolkit().getImage("background_text.png"); // import image of game screen with descriptions | |
// draw images | |
g.drawImage(background_text, 180, 100, 990, 530, this); // instruct how to score points | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("How To Play", 535, 70); | |
} | |
} | |
public class InstructionsPanel2 extends JPanel { // instructions panel header; Teaches Gameplay Part 2 | |
public InstructionsPanel2() { // constructor header | |
setLayout(new BorderLayout()); // set the layout as Border Layout | |
TwoButtonPanel buttons = new TwoButtonPanel("Back", "instruct1", "HSV Explanation", "instruct3"); // two buttons: one to move back, one to move on | |
add(buttons, BorderLayout.SOUTH); | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(FAR_LEFT - 40, FAR_TOP - 50, 1350 - (2 * (FAR_LEFT - 40)), 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// extract images | |
Image aim = Toolkit.getDefaultToolkit().getImage("screenshot_aim.png"); // import image of aiming screenshot | |
Image sliders = Toolkit.getDefaultToolkit().getImage("screenshot_sliders.png"); // import image of arrow | |
// draw images | |
g.drawImage(aim, FAR_LEFT, FAR_TOP + 55, 280, 230, this); // instruct how to score points | |
g.drawImage(sliders, 220, 470, 910, 130, this); | |
// draw 1 pixel sized borders around images | |
g.setColor(Color.GRAY); | |
g.drawRect(FAR_LEFT - 1, FAR_TOP + 54, 282, 232); | |
g.drawRect(219, 469, 912, 132); | |
// title = Bolded, Palatino, 48 | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("How To Play (Part 2)", 445, 70); | |
// subtitle = Bolded, Italicised, Serif, 14 | |
g.setColor(Color.BLACK); | |
Font subtitle = new Font("serif", Font.BOLD | Font.ITALIC, 24); | |
g.setFont(subtitle); | |
g.drawString("Game Elements:", FAR_LEFT, FAR_TOP + 10); | |
g.drawLine(FAR_LEFT, FAR_TOP + 15, FAR_LEFT + 166, FAR_TOP + 15); // hack way of underlining | |
// text instructions to right of pictures = unbolded, Sans Serif, 18 | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
// basic summary of gameplay | |
g.drawString("In order to win, you must use your spectacular knowledge of HSV.", TEXT_LEFT, FAR_TOP + 100); | |
g.drawString("Control the HSV Sliders and use the shooter to fire away!", TEXT_LEFT, FAR_TOP + 140); | |
g.drawString("Hit a ball (same color) with your shooter ball, and your score will go up!", TEXT_LEFT, FAR_TOP + 180); | |
g.drawString("Score 300 points to move on until you hit the final round.", TEXT_LEFT, FAR_TOP + 220); | |
g.drawString("WARNING!! If you miss a shot, you will lose a life!", TEXT_LEFT, FAR_TOP + 260); | |
} | |
} | |
public class InstructionsPanel3 extends JPanel implements ActionListener { // InstructionsPanel3 class header, implements ActionListener; Teaches HSV | |
// see more buttons | |
private JButton seeMore1; | |
private JButton seeMore2; | |
private JButton seeMore3; | |
public InstructionsPanel3() { // constructor header | |
setLayout(null); // null layout | |
// create buttons that link to other panels | |
seeMore1 = new JButton("See More (Hue)"); | |
seeMore2 = new JButton("See More (Saturation)"); | |
seeMore3 = new JButton("See More (Value)"); | |
// set sizes of buttons | |
int width = 270; // width and height of butttons | |
int height = 50; | |
seeMore1.setSize(width, height); | |
seeMore2.setSize(width, height); | |
seeMore3.setSize(width, height); | |
// set color of buttons to be transparent | |
Color transparent = new Color (200, 255, 255, 0); // alpha value (last param) is 0 = transparent | |
seeMore1.setBackground(transparent); | |
seeMore2.setBackground(transparent); | |
seeMore3.setBackground(transparent); | |
// do not color border | |
seeMore1.setBorderPainted(false); | |
seeMore2.setBorderPainted(false); | |
seeMore3.setBorderPainted(false); | |
// set the font of the texts on the buttons as sansserif, plain, 18, white | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
seeMore1.setForeground(Color.BLUE); | |
seeMore2.setForeground(Color.BLUE); | |
seeMore3.setForeground(Color.BLUE); | |
seeMore1.setFont(instruct); | |
seeMore2.setFont(instruct); | |
seeMore3.setFont(instruct); | |
// set locations of buttons | |
seeMore1.setLocation(TEXT_LEFT + 224, FAR_TOP + 320); | |
seeMore2.setLocation(TEXT_LEFT + 250, FAR_TOP + 355); | |
seeMore3.setLocation(TEXT_LEFT + 230, FAR_TOP + 390); | |
// add action listeners | |
seeMore1.addActionListener(this); | |
seeMore2.addActionListener(this); | |
seeMore3.addActionListener(this); | |
// add buttons | |
add(seeMore1); | |
add(seeMore2); | |
add(seeMore3); | |
setLayout(new BorderLayout()); // set the layout as Border Layout | |
TwoButtonPanel buttons = new TwoButtonPanel("Back", "instruct2", "Game Modes", "mode"); // two buttons: one to move back, one to move on | |
add(buttons, BorderLayout.SOUTH); | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(180, 100, 990, 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// draw rectangle around the buttons for visualization | |
Color lightRed = new Color (255, 150, 150); | |
g.setColor(lightRed); | |
g.fillRect(800, 460, 240, 140); | |
// extract images | |
Image flat_hsv = Toolkit.getDefaultToolkit().getImage("2D_hsv.gif"); // import image of aiming screenshot | |
Image cylinder_hsv = Toolkit.getDefaultToolkit().getImage("3D_hsv.png"); // import image of five hearts screenshot | |
// draw images | |
g.drawImage(flat_hsv, FAR_LEFT + 120, FAR_TOP + 35, 330, 220, this); // demonstrate how hsv looks in a 2-D shape | |
g.drawImage(cylinder_hsv, FAR_LEFT + 570, FAR_TOP + 35, 260, 220, this); // demonstrate how hsv looks in a 3-D shape | |
// draw 1 pixel sized borders around images | |
g.setColor(Color.GRAY); | |
g.drawRect(FAR_LEFT + 119, FAR_TOP + 34, 332, 222); // border around flat_hsv | |
g.drawRect(FAR_LEFT + 569, FAR_TOP + 34, 262, 222); // border around cylinder_hsv | |
// subtitle = Bolded, Italicised, Serif, 14 | |
g.setColor(Color.BLACK); | |
Font subtitle = new Font("serif", Font.BOLD | Font.ITALIC, 24); | |
g.setFont(subtitle); | |
g.drawString("Hue, Saturation, Value:", FAR_LEFT + 60, FAR_TOP); | |
g.drawLine(FAR_LEFT + 60, FAR_TOP + 5, FAR_LEFT + 300, FAR_TOP + 5); // hack way of underlining | |
// text to explain what HSV means = bolded, Sans Serif, 18, black | |
Font define = new Font("sansserif", Font.BOLD, 18); | |
g.setFont(define); | |
g.setColor(Color.BLACK); | |
g.drawString("HSV stands for hue, saturation, and value.", FAR_LEFT + 60, FAR_TOP + 315); // HSV summary | |
// label above the buttons for identification | |
g.setColor(Color.RED); | |
g.drawString("Click below for more information!", 765, 450); | |
// text for hue, Sat, Val summary pictures = unbolded, Sans Serif, 18 | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
g.setColor(Color.BLACK); | |
g.drawString("Hue refers to a pure color - one without tint or shade. ", FAR_LEFT + 60, FAR_TOP + 350); // 35 spacing apart | |
g.drawString("Saturation refers to how how tinted a color is (faded).", FAR_LEFT + 60, FAR_TOP + 385); | |
g.drawString("Value refers to how shaded a color is (dark).", FAR_LEFT + 60, FAR_TOP + 420); | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("What is HSV?", 535, 70); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
JButton source = (JButton) e.getSource(); // find source of the button being clicked | |
if (source == seeMore1) { | |
cards.show(ch, "see more1"); | |
} else if (source == seeMore2) { | |
cards.show(ch, "see more2"); | |
} else if (source == seeMore3) { | |
cards.show(ch, "see more3"); | |
} | |
} | |
} | |
public class SeeMore1 extends JPanel implements ActionListener { // SeeMore1 class header, implements Action Listener; See more for hue | |
private JButton back; | |
public SeeMore1() { | |
setLayout(new BorderLayout()); | |
back = new JButton("Back"); // button to go back to previous panel | |
back.addActionListener(this); // add action listener | |
add(back, BorderLayout.SOUTH); // add button | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(180, 100, 990, 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// extract images | |
Image hue_sat = Toolkit.getDefaultToolkit().getImage("hue_sat.png"); // import chart that has hue as x axis and sat as y axis | |
Image hue_val = Toolkit.getDefaultToolkit().getImage("hue_val.png"); // import chart that has hue as x axis and val as y axis | |
Image flat_hsv = Toolkit.getDefaultToolkit().getImage("2D_hsv.gif"); // import image of aiming screenshot | |
Image cylinder_hsv = Toolkit.getDefaultToolkit().getImage("3D_hsv.png"); // import image of five hearts screenshot | |
// draw images | |
g.drawImage(hue_sat, FAR_LEFT + 10, FAR_TOP, 200, 200, this); // chart that has hue as x axis and sat as y axis | |
g.drawImage(hue_val, FAR_LEFT + 10, FAR_TOP + 230, 200, 200, this); // chart that has hue as x axis and val as y axis | |
g.drawImage(flat_hsv, FAR_LEFT + 260, FAR_TOP, 330, 220, this); // demonstrate how hsv looks in a 2-D shape | |
g.drawImage(cylinder_hsv, FAR_LEFT + 640, FAR_TOP, 260, 220, this); // demonstrate how hsv looks in a 3-D shape | |
// draw 1 pixel sized borders around images | |
g.setColor(Color.GRAY); | |
g.drawRect(FAR_LEFT + 9, FAR_TOP - 1, 202, 202); // border around hue_sat | |
g.drawRect(FAR_LEFT + 9, FAR_TOP + 229, 202, 202); // border around hue_val | |
g.drawRect(FAR_LEFT + 259, FAR_TOP - 1, 332, 222); // border around flat_hsv | |
g.drawRect(FAR_LEFT + 639, FAR_TOP - 1, 262, 222); // border around cylinder_hsv | |
// text instructions to right of pictures = unbolded, Sans Serif, 18 | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
int init_pos = FAR_LEFT + 245; // initial position of the line | |
g.setColor(Color.BLACK); | |
g.drawString("There are 6 main hues:", init_pos, FAR_TOP + 270); | |
// shift between the colors of the words | |
g.setColor(Color.RED); | |
g.drawString("'red, ", init_pos + 206, FAR_TOP + 270); | |
g.setColor(Color.ORANGE); | |
g.drawString("orange, ", init_pos + 250, FAR_TOP + 270); | |
g.setColor(Color.YELLOW); | |
g.drawString("yellow, ", init_pos + 325, FAR_TOP + 270); | |
g.setColor(Color.GREEN); | |
g.drawString("green, ", init_pos + 390, FAR_TOP + 270); | |
g.setColor(Color.BLUE); | |
g.drawString("blue, ", init_pos + 450, FAR_TOP + 270); | |
g.setColor(new Color(127, 0, 255)); // Violet Color | |
g.drawString("violet.'", init_pos + 498, FAR_TOP + 270); | |
g.setColor(Color.BLACK); | |
g.drawString("Hue ranges from 0 - 360 because it is represented by a circle.", init_pos, FAR_TOP + 315); // 45 spacing | |
g.setColor(Color.RED); // important for gameplay | |
g.drawString("This means that red is approximately 0-20 and also 340-360!", init_pos, FAR_TOP + 360); | |
g.setColor(Color.BLACK); | |
g.drawString("Hue is always referred to as 'hue'.", init_pos, FAR_TOP + 405); | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("Hue", 625, 70); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
cards.show(ch, "instruct3"); // redirect to game after selecting choice | |
} | |
} | |
public class SeeMore2 extends JPanel implements ActionListener { // SeeMore2 class header, implements Action Listener; See more for Sat | |
private JButton back; | |
public SeeMore2() { | |
setLayout(new BorderLayout()); | |
back = new JButton("Back"); // button to go back to previous panel | |
back.addActionListener(this); // add action listener | |
add(back, BorderLayout.SOUTH); // add button | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(180, 100, 990, 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// extract images | |
Image hue_sat = Toolkit.getDefaultToolkit().getImage("hue_sat.png"); // import chart that has hue as x axis and sat as y axis | |
Image sat_val = Toolkit.getDefaultToolkit().getImage("sat_val.png"); // import chart that has hue as x axis and val as y axis | |
Image flat_hsv = Toolkit.getDefaultToolkit().getImage("2D_hsv.gif"); // import image of aiming screenshot | |
Image cylinder_hsv = Toolkit.getDefaultToolkit().getImage("3D_hsv.png"); // import image of five hearts screenshot | |
// draw images | |
g.drawImage(hue_sat, FAR_LEFT + 10, FAR_TOP, 200, 200, this); // chart that has hue as x axis and sat as y axis | |
g.drawImage(sat_val, FAR_LEFT + 10, FAR_TOP + 230, 200, 200, this); // chart that has hue as x axis and val as y axis | |
g.drawImage(flat_hsv, FAR_LEFT + 260, FAR_TOP, 330, 220, this); // demonstrate how hsv looks in a 2-D shape | |
g.drawImage(cylinder_hsv, FAR_LEFT + 640, FAR_TOP, 260, 220, this); // demonstrate how hsv looks in a 3-D shape | |
// draw 1 pixel sized borders around images | |
g.setColor(Color.GRAY); | |
g.drawRect(FAR_LEFT + 9, FAR_TOP - 1, 202, 202); // border around hue_sat | |
g.drawRect(FAR_LEFT + 9, FAR_TOP + 229, 202, 202); // border around hue_val | |
g.drawRect(FAR_LEFT + 259, FAR_TOP - 1, 332, 222); // border around flat_hsv | |
g.drawRect(FAR_LEFT + 639, FAR_TOP - 1, 262, 222); // border around cylinder_hsv | |
// text instructions to right of pictures = unbolded, Sans Serif, 18 | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
int init_pos = FAR_LEFT + 245; // left most side of text | |
g.setColor(Color.BLACK); | |
g.drawString("Saturation ranges from 0 - 100 because it is a percentage of the hue.", init_pos, FAR_TOP + 270); // 45 spacing | |
g.drawString("It goes from a shade of gray to the most pure form of the hue.", init_pos, FAR_TOP + 315); | |
g.setColor(Color.RED); // important for gameplay | |
g.drawString("When saturation is 0, the color is always 0 (for all hues)!", init_pos, FAR_TOP + 360); | |
g.setColor(Color.BLACK); | |
g.drawString("Saturation is also referred to (not completely the same) as chroma.", init_pos, FAR_TOP + 405); | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("Saturation", 560, 70); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
cards.show(ch, "instruct3"); // redirect to game after selecting choice | |
} | |
} | |
public class SeeMore3 extends JPanel implements ActionListener { // SeeMore3 class header, implements Action Listener; See more for Val | |
private JButton back; | |
public SeeMore3() { | |
setLayout(new BorderLayout()); | |
back = new JButton("Back"); // button to go back to previous panel | |
back.addActionListener(this); // add action listener | |
add(back, BorderLayout.SOUTH); // add button | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(180, 100, 990, 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// extract images | |
Image hue_val = Toolkit.getDefaultToolkit().getImage("hue_val.png"); // import chart that has hue as x axis and sat as y axis | |
Image sat_val = Toolkit.getDefaultToolkit().getImage("sat_val.png"); // import chart that has hue as x axis and val as y axis | |
Image flat_hsv = Toolkit.getDefaultToolkit().getImage("2D_hsv.gif"); // import image of aiming screenshot | |
Image cylinder_hsv = Toolkit.getDefaultToolkit().getImage("3D_hsv.png"); // import image of five hearts screenshot | |
// draw images | |
g.drawImage(hue_val, FAR_LEFT + 10, FAR_TOP, 200, 200, this); // chart that has hue as x axis and sat as y axis | |
g.drawImage(sat_val, FAR_LEFT + 10, FAR_TOP + 230, 200, 200, this); // chart that has hue as x axis and val as y axis | |
g.drawImage(flat_hsv, FAR_LEFT + 260, FAR_TOP, 330, 220, this); // demonstrate how hsv looks in a 2-D shape | |
g.drawImage(cylinder_hsv, FAR_LEFT + 640, FAR_TOP, 260, 220, this); // demonstrate how hsv looks in a 3-D shape | |
// draw 1 pixel sized borders around images | |
g.setColor(Color.GRAY); | |
g.drawRect(FAR_LEFT + 9, FAR_TOP - 1, 202, 202); // border around hue_sat | |
g.drawRect(FAR_LEFT + 9, FAR_TOP + 229, 202, 202); // border around hue_val | |
g.drawRect(FAR_LEFT + 259, FAR_TOP - 1, 332, 222); // border around flat_hsv | |
g.drawRect(FAR_LEFT + 639, FAR_TOP - 1, 262, 222); // border around cylinder_hsv | |
// text instructions to right of pictures = unbolded, Sans Serif, 18 | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
int init_pos = FAR_LEFT + 245; // left most side of text | |
g.setColor(Color.BLACK); | |
g.drawString("Value ranges from 0 - 100 because it is a percentage of the hue.", init_pos, FAR_TOP + 270); // 45 spacing | |
g.drawString("Value goes from black to the most saturated form of the hue.", init_pos, FAR_TOP + 315); | |
g.setColor(Color.RED); // important for gameplay | |
g.drawString("When sat is 0, the color is always black to white (for all hues)!", init_pos, FAR_TOP + 360); | |
g.setColor(Color.BLACK); | |
g.drawString("Value is also referred to (although not completely the same) as: ", init_pos, FAR_TOP + 405); | |
g.drawString("'Lightness, Intensity, Luminance, or Brightness.'", init_pos, FAR_TOP + 450); | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("Value", 613, 70); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
cards.show(ch, "instruct3"); // redirect to game after selecting choice | |
} | |
} | |
public class GameMode extends JPanel implements ActionListener { // GameModePanel header; panel that user arrives to and then selects game mode (after selecting, game mode just advances to next level) | |
// game mode buttons | |
private JButton hueButton; | |
private JButton satButton; | |
private JButton valButton; | |
private JButton allButton; | |
private int buttonWidth = 200; // dimensions of the button | |
private int buttonHeight = 70; | |
public GameMode() { | |
setLayout(null); | |
// create buttons that choose the game mode | |
hueButton = new JButton("Hue Mode (easy)"); | |
satButton = new JButton("Saturation Mode (medium)"); | |
valButton = new JButton("Value Mode (medium)"); | |
allButton = new JButton("All Three Mode (hard)"); | |
// set sizes of buttons | |
hueButton.setSize(buttonWidth, buttonHeight); | |
hueButton.setLocation(FAR_LEFT + 150, topButton); | |
satButton.setSize(buttonWidth, buttonHeight); | |
satButton.setLocation(FAR_LEFT + 150, topButton + 110); | |
valButton.setSize(buttonWidth, buttonHeight); | |
valButton.setLocation(FAR_LEFT + 150, topButton + 220); | |
allButton.setSize(buttonWidth, buttonHeight); | |
allButton.setLocation(FAR_LEFT + 150, topButton + 330); | |
// add action listeners | |
hueButton.addActionListener(this); | |
satButton.addActionListener(this); | |
valButton.addActionListener(this); | |
allButton.addActionListener(this); | |
// add buttons | |
add(hueButton); | |
add(satButton); | |
add(valButton); | |
add(allButton); | |
setLayout(new BorderLayout()); // switch from null to border layout | |
TwoButtonPanel buttons = new TwoButtonPanel("Back", "instruct3", "Continue (Hue Mode)", "game"); // two buttons: one to move back, one to move on | |
add(buttons, BorderLayout.SOUTH); | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
// draw one big rectangle | |
g.setColor(lighterBlue); | |
g.fillRect(180, 100, 990, 530); // give 40 by 50 border in which no graphics exist (text will be inside, however) | |
// title = Bolded, Palatino, 48, gray | |
g.setColor(darkestGray); | |
Font title = new Font("palatino", Font.BOLD, 48); | |
g.setFont(title); | |
g.drawString("Select Game Mode", 470, 70); | |
// text to describe modes = unbolded, Sans Serif, 18, black | |
Font instruct = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(instruct); | |
g.setColor(Color.GRAY); | |
g.drawString("In these game modes, the name of the mode is the only feature that is in the game.", 310, 140); // instruct to choose wisely | |
g.drawString("Choose wisely, you cannot go back!", 520, 165); // instruct to choose wisely | |
g.setColor(darkestGray); | |
g.drawString("Hue Mode (easy): ", 650, topText); // instruct about hue only mode (i.e. what features it presents) | |
g.drawString("You can only use the hue slider!", 650, topText + 25); | |
g.drawString("Saturation Mode (medium): ", 650, topText + 110); // instruct about hue only mode (i.e. what features it presents) | |
g.drawString("You can only use the saturation slider!", 650, topText + 135); | |
g.drawString("Value Mode (medium): ", 650, topText + 220); // instruct about hue only mode (i.e. what features it presents) | |
g.drawString("You can only use the value slider!", 650, topText + 245); | |
g.drawString("All Mode (hard): ", 650, topText + 330); // instruct about hue only mode (i.e. what features it presents) | |
g.drawString("You can use all three sliders!", 650, topText + 355); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
JButton source = (JButton) e.getSource(); // find source of the button being clicked | |
if (source == hueButton) { // hue only mode | |
hueMode = true; // hue mode boolean | |
} else if (source == satButton) { // saturation only mode | |
hueMode = false; // set default false | |
satMode = true; | |
} else if (source == valButton) { // value only mode | |
hueMode = false; // set default false | |
valMode = true; | |
} else if (source == allButton) { // all three mode | |
hueMode = false; // set default false | |
allMode = true; | |
} | |
cards.show(ch, "game"); // redirect to game after selecting choice | |
if (source == back) { // overrides the previous card show | |
if (fromMain) { | |
cards.show(ch, "main"); | |
fromMain = false; // reset boolean | |
} else | |
cards.show(ch, "instruct3"); // move back to previous panel | |
} | |
} | |
} | |
public class TwoButtonPanel extends JPanel implements ActionListener { // TwoButtonPanel header; panel that holds two buttons side by side (button for going back and going forward in cards) | |
private JButton button1; // left button | |
private JButton button2; // right button | |
// panels to redirect to | |
private String panel1; | |
private String panel2; | |
public TwoButtonPanel(String buttonText1, String panelName1, String buttonText2, String panelName2) { // pass values of text displayed on buttons and also panels to redirect to | |
panel1 = panelName1; // panels to redirect to | |
panel2 = panelName2; | |
setLayout(new GridLayout(1, 2)); // one row, two column layout | |
button1 = new JButton(buttonText1); // JButton with predefined text | |
button1.addActionListener(this); // add action listener | |
add(button1); // add button to first column | |
button2 = new JButton(buttonText2); // JButton with predefined text | |
button2.addActionListener(this); // add action listener | |
add(button2); // add button to second column | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(lightBlue); // set background color as light blue | |
super.paintComponent(g); | |
} | |
public void actionPerformed(ActionEvent e) { // actionPerformed header | |
JButton source = (JButton) e.getSource(); // find source of the button being clicked | |
if (source == button1) | |
cards.show(ch, panel1); // show the instructions panel when button is pressed | |
else if (source == button2) | |
cards.show(ch, panel2); // show the instructions panel when button is pressed | |
} | |
} | |
public class GameLose extends JPanel implements ActionListener { // GameLose header, implements ActionListener; user has lost game, allow them to restart | |
private JButton restart; // restart button, redirects to main panel | |
public GameLose() { | |
setLayout(null); // set layout as null | |
restart = new JButton("Restart?"); | |
restart.setBackground(Color.BLACK); // black colored button | |
restart.setBorderPainted(false); // do not color the border | |
restart.setOpaque(true); // show background color of button | |
restart.setForeground(Color.WHITE); // text is white | |
restart.setSize(100, 50); | |
restart.setLocation(625, 430); | |
restart.addActionListener(this); | |
add(restart); | |
} | |
public void paintComponent(Graphics g) { | |
setBackground(Color.BLACK); // set background color as black | |
super.paintComponent(g); | |
// title = Bolded, Palatino, 48, gray | |
Font title = new Font("sansserif", Font.BOLD, 100); | |
g.setFont(title); | |
g.setColor(Color.RED); | |
g.drawString("GAME OVER", 370, 370); | |
} | |
public void actionPerformed(ActionEvent e){ | |
cards.show(ch, "main"); | |
} | |
} | |
public class GamePanel extends JPanel { // GamePanel header; holds the two game panels | |
private GameScreen screen; // Panel that user actually plays game in | |
private GameInput input; // Panel that user uses sliders to change ball colors | |
private float h = 0; // hue color param | |
private float s = 1; // sat color param | |
private float v = 1; // val color param | |
private Color shootColor = Color.getHSBColor(h, s, v); // color of the ball that is being shot by the user | |
private int presetHue = 0; // come up with a random value of hue (for satMode and valMode of red, blue, or yellow | |
private boolean fromInput = false; // screen repaint is called from the input panel | |
private boolean ballChanged = false; // boolean for determining whether shooting ball has changed color | |
private boolean firstTime = false; // boolean for whether repaint input panel once or not | |
public GamePanel() { // constructor header | |
setLayout(new BorderLayout()); // set layout as Border Layout | |
// two panels, one is GameScreen, other is GameInput | |
screen = new GameScreen(); | |
input = new GameInput(); | |
add(screen, BorderLayout.CENTER); // add GameScreen to Center | |
add(input, BorderLayout.SOUTH); // add GameInput panel to South | |
} | |
public class GameScreen extends JPanel implements MouseListener, MouseMotionListener { // GameScreen panel header, implements MouseListener, MouseMotionListener | |
private final int CENTER = 675; // center of the screen | |
private int roundNum = 0; // number of the round | |
private int mouse_x = 0; // x position of the mouse | |
private int mouse_y = 0; // y position of the mouse | |
private int start_x = CENTER - 25; // x-y starting positions of shooting ball | |
private int start_y = 455; | |
private int ball_x = CENTER - 25; // x-y position of shooting ball while moving | |
private int ball_y = 455; | |
private int cannon_x = CENTER; // point where the aiming line ends (nearest to cannon) | |
private int cannon_y = 475; | |
private int shoot_col = 0; // counter for the shooting ball method | |
private int ballNum = 17; // number of random balls | |
private int lifeNum = 5; // number of lives | |
private int randCount = 0; // counter for random ball coordinates and colors | |
private int correct = 0; // correct index after cycling through loop | |
private int score = 0; // number of points that user earned, factor of 100 | |
private int presetFeedback = 0; // come up with a random value from 0-2 to decide what positive feedback to display after user scores a point | |
private double theta = 0; // angle is the angle between the mouse coordinates and a certain point (uses arctan) | |
private double angle = 0; // angle is the angle between the mouse coordinates and a certain point (uses arctan) | |
private double speed = 30.0; // speed shooting ball is moving at | |
private String currentMode; // displays current mode | |
private boolean ballMoving = false; // boolean for determining whether shooting ball is moving | |
private boolean cannonChanged = false; // boolean for determining whether cannon has rotated | |
private boolean ballHit = false; // boolean for determining whether the shooting ball has hit another ball | |
private boolean found = false; // boolean for determining if y coordinate of shooting ball matches one of random balls | |
private boolean stop = false; // boolean for determining if x coordinate of shooting ball hit left or right side | |
private boolean ballStop = false; // boolean for determining if ball has stopped, but cannon has moved | |
private boolean firstGen = true; // first time of generating presetHue | |
private boolean feedback = false; // user receives positive feedback | |
private int[][] ballCoord; // 2D array of random ball x-y coordinates | |
private int[][] shootingArr = new int[2][27]; // array containing x and y values of the shooting ball position | |
private float[] arrayHSV = new float[3]; // array containing the randomly generated HSV values for the top balls | |
private float[] randHSV = new float[3]; // check if HSV of random ball matches the shooter ball's HSV | |
private float[] shootHSV = new float[3]; | |
private Color[] randomColor; // array holding color of random balls | |
public GameScreen() { // opened up for initializing statistics | |
shootHSV[0] = 0; // initialize so that the strings are not null | |
shootHSV[1] = 100; | |
shootHSV[2] = 100; | |
randHSV[0] = 0; | |
randHSV[1] = 0; | |
randHSV[2] = 0; | |
addMouseListener(this); // add listeners for mouse and mouse motion | |
addMouseMotionListener(this); | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightBlue); // background color is light blue | |
super.paintComponent(g); | |
g.setColor(darkGray); // draw the boundary of where user can use mouse to change cannon angle | |
g.drawRect(300, 200, 750, 275); | |
// text to show color stats = unbolded, Sans Serif, 18, black | |
Font stats = new Font("sansserif", Font.PLAIN, 18); | |
g.setFont(stats); | |
g.setColor(Color.BLACK); | |
g.drawString("Shooter Ball Hue:", 350, 365); | |
g.drawString("Shooter Ball Saturation: ", 350, 390); | |
g.drawString("Shooter Ball Value:", 350, 415); | |
g.drawString((int) shootHSV[0] + "", 580, 365); | |
g.drawString((int) shootHSV[1] + "", 580, 390); | |
g.drawString((int) shootHSV[2] + "", 580, 415); | |
g.drawString("Target Ball Hue:", 738, 365); | |
g.drawString("Target Ball Saturation:", 738, 390); | |
g.drawString("Target Ball Value:", 738, 415); | |
g.drawString((int) randHSV[0] + "", 968, 365); | |
g.drawString((int) randHSV[1] + "", 968, 390); | |
g.drawString((int) randHSV[2] + "", 968, 415); | |
g.setColor(top); // draw a solid rectangle around the randomly drawn circles at the top | |
g.fillRect(150, 0, 1050, 85); | |
cannon(cannon_x - 50, cannon_y - 55, g); // draw the cannon at a certain position (based on height/width of cannon) | |
lifeBar(lifeNum, g); // draw the lifebars with the number of rounds | |
scoreBoard(score, g); // draw the scoreboard | |
if (lifeNum == 0) { // user has lost the game | |
cards.show(ch, "lose"); | |
lifeNum = 5; // reset for after user restarts | |
allMode = false; | |
hueMode = true; | |
score = 0; | |
} | |
// change modes based on score and reset score/round number each time | |
if (!fromInput) { // changing color doesn't change round | |
if (hueMode) { // hue only mode | |
currentMode = "Hue Mode"; | |
roundNum = 6; // only have 5 balls | |
firstTime = true; | |
if (score == 3) { // user has scored 3 balls (300 points), next game mode | |
hueMode = false; // set current mode false | |
satMode = true; // set next mode true | |
score = 0; // reset score | |
firstGen = true; // first time generating presetHue for sat mode and val mode | |
input.repaint(); // repaint the labels and sliders | |
} | |
} else if (satMode) { // saturation only mode | |
currentMode = "Saturation Mode"; | |
roundNum = 6; // only have 5 balls | |
firstTime = true; | |
if (score == 3) { // user has scored 3 balls (300 points), next game mode | |
satMode = false; // set current mode false | |
valMode = true; // set next mode true | |
score = 0; // reset score | |
firstGen = true; // first time generating presetHue for sat mode and val mode | |
input.repaint(); // repaint the labels and sliders | |
} | |
} else if (valMode) { // value only mode | |
currentMode = "Value Mode"; | |
roundNum = 6; // only have 5 balls | |
firstTime = true; | |
if (score == 3) { // user has scored 3 balls (300 points), next game mode | |
valMode = false; // set current mode false | |
allMode = true; // set next mode true | |
score = 0; // reset score | |
roundNum = 0; // 17 balls | |
input.repaint(); // repaint the labels and sliders | |
} | |
} else if (allMode) { // all three modes | |
currentMode = "All Mode"; | |
if (score >= 9) { // user has scored 9 balls (900 points) | |
g.drawString("YOU WIN! CONGRATULATIONS!", 484, 160); | |
roundNum = 0; // from now on, constantly 17 balls | |
} | |
} | |
} | |
fromInput = false; // if next time is from input, fromInput = true. Otherwise, fromInput = false | |
// display current game mode, font = Bolded, SansSerif, 24, gray | |
g.setColor(darkestGray); | |
Font title = new Font("sansserif", Font.BOLD, 24); | |
g.setFont(title); | |
g.drawString("Current Mode: ", 30, 160); | |
// change color to red and output the game mode | |
Color darkRed = new Color (200, 0, 0); | |
g.setColor(darkRed); | |
g.drawString(currentMode, 220, 160); | |
if (score == 0) // beginning of round | |
g.drawString("New Round", 604, 271); // alert user that round has changed | |
if (feedback) { // present positive feedback to user | |
if (presetFeedback == 0) // returns the greatest integer less than or greater than the random values from 0 (inclusive) - 3 (exclusive) | |
g.drawString("Nice Shot!", 614, 160); // give positive feedback to user | |
else if (presetFeedback == 1) // returns the greatest integer less than or greater than the random values from 0 (inclusive) - 3 (exclusive) | |
g.drawString("Amazing!", 614, 160); // give positive feedback to user | |
else if (presetFeedback == 2) // returns the greatest integer less than or greater than the random values from 0 (inclusive) - 3 (exclusive) | |
g.drawString("Wow! You are good!", 551, 160); // give positive feedback to user | |
} else | |
g.drawString("DO NOT CLICK OUTSIDE THE BOX", 465, 160); // alert user that they must click inside the box | |
g.setColor(shootColor); // set color of the shooting ball | |
if (ballMoving) { // ball has been shot | |
ballShoot(angle, g); // draw the shooting ball | |
redraw_randomBall(g); // redraw the random balls at the top | |
} else if ((ballChanged) || (cannonChanged && !ballStop)) { // color of ball is being changed or ball is moving and cannon is being changed | |
ballGenerate(g, start_x, start_y); // draw the shooting ball | |
redraw_randomBall(g); // redraw the random balls at the top | |
cannonChanged = false; // cannon is not being altered | |
ballChanged = false; // ball color is not being altered | |
} else { // first round, default conditions | |
ballStop = false; // necessary instead of ballMoving because needs to only happen once (i.e. right after ball has stopped, if cannon is moved, then it doesn't regenerate random balls) | |
ballGenerate(g, start_x, start_y); // draw the shooting ball | |
randomBall(roundNum, g); // draw the random balls at the top, round 0 | |
} | |
} | |
/** | |
* randomBall method | |
* parameters are the round number and graphics | |
* starts with 17, goes down by 4 every 2 points | |
* until 8 points is scored, and then stays at 1 | |
*/ | |
public void randomBall(int roundNum, Graphics g) { | |
if (roundNum % 2 != 0) { // round number is odd | |
roundNum -= 1; | |
} | |
if (roundNum <= 8) { // round number until 8 | |
ballNum = 17 - (roundNum * 2); // number of balls starts by 17 and goes down by 4 each round | |
} else { | |
ballNum = 1; | |
} | |
int x = 165 + (roundNum * 60); // starting x and y coordinates depends on round number | |
int y = 20; | |
ballCoord = new int[2][ballNum]; // array with 17 indexes for the 17 ball coordinates | |
randomColor = new Color[ballNum]; | |
for (int col = 0; col < ballNum; col++) { // 17 columns | |
for (int row = 0; row < 2; row++) { // 2 rows | |
if (row == 0) { // x coordinates | |
ballCoord[0][col] = x; | |
x += 60; // width of the ball | |
} else if (row == 1) { // y coordinates | |
ballCoord[1][col] = y; | |
} | |
} | |
} | |
// generate random hsv colors and store them in an array | |
for (int index = 0; index < ballNum; index++) { | |
randomHSV(); // randomHSV generates random H, S, and V values and stores them in arrayHSV | |
Color randomBall = Color.getHSBColor(arrayHSV[0], arrayHSV[1], arrayHSV[2]); // generate a new color that is based on completely random RGB values | |
randomColor[index] = randomBall; | |
} | |
// draw the balls with the correct color and x-y positions | |
for (int counter = 0; counter < ballNum; counter++) { | |
x = ballCoord[0][counter]; // set the x and y coordinates of the balls so that they are placed in a line | |
y = ballCoord[1][counter]; | |
g.setColor(randomColor[counter]); | |
ballGenerate(g, x, y); // draw the ball with the right colors and coordinates | |
} | |
} | |
/** | |
* redraw_randomBall method | |
* parameters are the round number and Graphics | |
* necessary when ball is moving because the balls need to possess the same colors | |
*/ | |
public void redraw_randomBall(Graphics g) { | |
int redraw_x = 0; | |
int redraw_y = 0; | |
for (int col = 0; col < ballNum; col++) { // 17 columns | |
Color redrawColor; | |
redrawColor = randomColor[col]; // take the color of the ball from the array used to construct the colors | |
for (int row = 0; row < 2; row++) { // 2 rows | |
if (row == 0) { | |
redraw_x = ballCoord[0][col]; | |
} else if (row == 1) { | |
redraw_y = ballCoord[1][col]; | |
} | |
} | |
g.setColor(redrawColor); | |
ballGenerate(g, redraw_x, redraw_y); | |
} | |
} | |
/** | |
* randomHSV method | |
* no parameters | |
* generates an array of HSV values | |
* 0th index = hue, 1th index = saturation, 2th = value | |
*/ | |
public void randomHSV() { | |
if (satMode || valMode) { // only generate the hue if satMode or valMode | |
if (firstGen) { // only make presetHue once | |
firstGen = false; | |
// cycle through random ints 1 - 3 to determine if hue will be red, yellow, or blue | |
presetHue = (int) (Math.floor(Math.random() * 3)); // returns the greatest integer less than or greater than the random values from 0 (inclusive) - 3 (exclusive) | |
if (presetHue == 0) | |
arrayHSV[0] = 0; // hue value of red | |
else if (presetHue == 1) | |
arrayHSV[0] = (float)(60) / 360; // hue value of yellow | |
else if (presetHue == 2) | |
arrayHSV[0] = (float)(240) / 360; // hue value of blue | |
shootColor = Color.getHSBColor(arrayHSV[0], 1, 1); // repaint the shooter ball so that it has the correct hue values | |
repaint(); // repaint screen so that the shooter ball has correct color | |
} | |
} | |
if (hueMode) { // user can only change hue. sat and val = 1 (max) | |
arrayHSV[0] = (float)(Math.random()); // returns a random integer from 0 (inclusive) - 1 (exclusive) | |
arrayHSV[1] = 1; // saturation and value are constant (max) | |
arrayHSV[2] = 1; | |
} else if (satMode) { // user can only change sat. hue and val are constants | |
arrayHSV[1] = (float)(Math.random()); // returns a random integer from 0 (inclusive) - 1 (exclusive) | |
arrayHSV[2] = 1; // value is constant (max) | |
} else if (valMode) { // user can only change val. hue and sat are constants | |
arrayHSV[1] = 1; // saturation is constant (max) | |
arrayHSV[2] = (float)(Math.random()); // returns a random integer from 0 (inclusive) - 1 (exclusive) | |
} else if (allMode) { // user can change all three values | |
arrayHSV[0] = (float)(Math.random()); // returns a random integer from 0 (inclusive) - 1 (exclusive) | |
arrayHSV[1] = (float)(Math.random() * (1 - 0.15f) + 0.15f); // returns a random integer from 0.15 (inclusive) - 1 (exclusive). Necessary because 0-0.15 looks too white | |
arrayHSV[2] = (float)(Math.random() * (1 - 0.2f) + 0.2f); // returns a random integer from 0.2 (inclusive) - 1 (exclusive). Necessary because 0-0.2 looks too black | |
} | |
} | |
/** | |
* ballShoot method | |
* parameters are angle, x, y starting coord, and Graphics | |
*/ | |
public void ballShoot(double angle, Graphics g) { | |
// put the x-y coordinates into an array | |
shootingArr[0][shoot_col] = ball_x; | |
shootingArr[1][shoot_col] = ball_y; | |
double shoot_width = speed * Math.sin(angle); // the x distance that the ball travels is cosine of the angle multiplied by the speed | |
double shoot_height = speed * Math.cos(angle); // the y distance that the ball travels is sine of the angle multiplied by the speed | |
if (angle > Math.PI / 2) { // mouse is in second quadrant | |
shoot_width = -1 * shoot_width; // in second quadrant, sine is positive, but should be negative | |
shoot_height = Math.abs(shoot_height); // in second quadrant, cosine is negative, but should be positive | |
} | |
// change the coordinates of the ball appropriately | |
ball_x += shoot_width; | |
ball_y -= shoot_height; | |
ballGenerate(g, ball_x, ball_y); // draw the ball | |
try { // slow down the rate that the balls move by 50 milliseconds | |
Thread.sleep(50); | |
} catch (InterruptedException ex) { | |
System.out.println("Error: " + ex); | |
} | |
if (shoot_col < 26) { // array (possible movement of ball) is only 50 spaces big | |
shoot_col++; // iterate through the 2D array | |
repaint(); // stops repainting when loop has ended | |
} else { // ball has stopped | |
ball_x = start_x; // reset shooting ball positions | |
ball_y = start_y; | |
ballCheck(g); // check if the shooting ball has hit a random ball | |
shoot_col = 0; // reset loop counter | |
ballMoving = false; // ball has stopped moving | |
ballStop = true; // ball has stopped | |
found = false; // ball has stopped, reset boolean that determines if ball hit top | |
stop = false; // ball has stopped, reset boolean that determines if ball has hit sides | |
ballHit = false; // set boolean to false for next shot | |
repaint(); | |
} | |
} | |
/** | |
* ballGenerate method | |
* parameters are Graphics, and x-y positions | |
*/ | |
public void ballGenerate(Graphics g, int x, int y) { | |
g.fillOval(x, y, 50, 50); // draw the 50 by 50 ball | |
Color outline = new Color(150, 150, 150); | |
g.setColor(outline); // draw a gray outline | |
g.drawOval(x, y, 50, 50); | |
} | |
/** | |
* ballCheck method | |
* parameter is Graphics | |
*/ | |
public void ballCheck(Graphics g) { | |
for (int col = 0; col < shoot_col; col++) { // all the coordinates of the shot ball | |
if ((shootingArr[1][col] > 0 && shootingArr[1][col] < 40) || (found)) { // y coordinate of shooting ball must match the random ball y coordinate (20) | |
if (!found) { | |
correct = col; // correct index is col | |
found = true; // found the index containing the correct y coordinate | |
} | |
for (randCount = 0; randCount < ballNum; randCount++) { | |
if ((shootingArr[0][correct] > ballCoord[0][randCount] - 25) && (shootingArr[0][correct] < ballCoord[0][randCount] + 25)) { // check if shooting ball matches x coordinates of each random ball | |
getHSVComponents(randomColor[randCount], randHSV); // get the HSV values of the shooting ball color and the random ball color | |
getHSVComponents(shootColor, shootHSV); | |
if ((randHSV[0] >= 340) && (randHSV[0] <= 360)) | |
randHSV[0] = 360 - randHSV[0]; // scale of 20 - 0 from 340 - 360, necessary because 340-360 look same as 0-20 | |
// check if ball that was hit and the shooting ball have similar colors (depends on mode) | |
if (hueMode) { | |
if (shootHSV[0] > randHSV[0] - 10 && shootHSV[0] < randHSV[0] + 10) { // hue threshold of plus or minus 10 | |
ballHit = true; | |
} | |
} else if (satMode) { | |
if (shootHSV[1] > randHSV[1] - 10 && shootHSV[1] < randHSV[1] + 10) { // sat threshold of plus or minus 10 | |
ballHit = true; | |
} | |
} else if (valMode) { | |
if (shootHSV[2] > randHSV[2] - 10 && shootHSV[2] < randHSV[2] + 10) { // val threshold of plus or minus 10 | |
ballHit = true; | |
} | |
} else if (allMode) { | |
if (shootHSV[0] > randHSV[0] - 15 && shootHSV[0] < randHSV[0] + 15) { // hue threshold of plus or minus 15 | |
if (shootHSV[1] > randHSV[1] - 25 && shootHSV[1] < randHSV[1] + 25) { // sat threshold of plus or minus 25 | |
if (shootHSV[2] > randHSV[2] - 25 && shootHSV[2] < randHSV[2] + 25) { // val threshold of plus or minus 25 | |
ballHit = true; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (ballHit && (!stop)) { // ball has hit and has same color as the one it hit | |
stop = true; // stop checking if ball has missed | |
presetFeedback = (int) (Math.floor(Math.random() * 3)); // set the presetFeedback here | |
feedback = true; // user receives positive feedback | |
score++; // increase score | |
if (allMode) // other modes have constant number of balls | |
roundNum++; // increase the round to next round | |
} | |
} | |
if ((col == (shoot_col - 1)) && (!ballHit) && (!stop)) { // end of loop, shooting ball has not hit other balls | |
stop = true; // stop checking if ball has missed | |
lifeNum--; // decrease the amount of lives by one because user missed | |
} | |
} | |
} | |
/** | |
* getHSVComponents method | |
* parameters are the color and the float array with 3 indices that will hold the hsv values | |
*/ | |
public void getHSVComponents(Color input, float[] array) { | |
int valueR; | |
int valueG; | |
int valueB; | |
valueR = input.getRed(); // get the RGB values of the random ball | |
valueG = input.getGreen(); | |
valueB = input.getBlue(); | |
Color.RGBtoHSB(valueR, valueG, valueB, array); // turn the RGB values into an array with HSV values | |
// scale them appropriately | |
array[0] *= 360; // hue: 0 to 360 | |
array[1] *= 100; // sat: 0 to 100 | |
array[2] *= 100; // val: 0 to 100 | |
} | |
/** | |
* cannon method | |
* parameters are x, y coordinates and Graphics | |
* includes the line of sight projecting from shooter | |
*/ | |
public void cannon(int can_x, int can_y, Graphics g) { | |
Image cannon = Toolkit.getDefaultToolkit().getImage("cannon_pointer.png"); // import image of cannon | |
// use AffineTransform to rotate images | |
Graphics2D g2 = (Graphics2D) g; // cast previous graphics into a new graphics | |
AffineTransform saveG = g2.getTransform(); | |
AffineTransform at = AffineTransform.getRotateInstance(theta - Math.PI / 2, cannon_x, cannon_y); // last two parameters control position of anchor point | |
g2.setTransform(at); // set the graphic as the rotated instance | |
g2.drawImage(cannon, can_x, can_y, 1000, 100, this); // draw the cannon image at specified coordinates w:133, h:110 1.21 ratio | |
g2.setTransform(saveG); // reset the graphic as the one before rotating | |
} | |
/** | |
* lifeBar method | |
* parameters are lifeNum (# of lives) and graphics | |
* lives do not replenish, user starts with 5 | |
* loses 1 life per miss | |
*/ | |
public void lifeBar(int lifeNum, Graphics g) { | |
Image full = Toolkit.getDefaultToolkit().getImage("heart_full.png"); // import image of full heart | |
Image empty = Toolkit.getDefaultToolkit().getImage("heart_empty.png"); // import image of empty heart | |
lifeNum -= 5; // range of -5 to 0 | |
int fullHeart = 0; // number of full hearts | |
for (int xpos = 812; xpos < 912 + lifeNum * 20; xpos += 20) { // 5 hearts, number of hearts goes down when lifeNum goes down | |
g.drawImage(full, xpos, 250, 20, 20, this); // draw the hearts to depict lifebars | |
fullHeart++; | |
} | |
for (int xpos = 892; xpos > 792 + fullHeart * 20; xpos -= 20) { | |
g.drawImage(empty, xpos, 250, 20, 20, this); // draw the hearts to depict lifebars | |
} | |
} | |
/** | |
* scoreBoard method | |
* parameters are the score and graphics | |
*/ | |
public void scoreBoard(int score, Graphics g) { | |
score *= 100; // make score multiples of 100 | |
// score font = Dialog, Bold, 24, gray | |
Font scoreFont = new Font("dialog", Font.BOLD, 24); | |
g.setFont(scoreFont); | |
g.setColor(darkestGray); | |
g.drawString("Score: " + score, 417, 271); // draw the score | |
if (score == 0) // score is default 0 | |
g.drawRect(397, 240, 140, 45); // smaller rectangle otherwise it looks awkward | |
else if (score < 10000) // score is 3-4 digits | |
g.drawRect(397, 240, 185, 45); | |
else // score is 5 digits | |
g.drawRect(397, 240, 195, 45); | |
} | |
// mouse motion methods for when user controls the angle of the cannon | |
public void mouseDragged(MouseEvent e) { // allow user to shoot in mouse drag as well to make it faster | |
requestFocus(); | |
mouse_x = e.getX(); // get the mouse x-y coordinates | |
mouse_y = e.getY(); | |
if (!ballMoving) { // ball should not be moving while clicking, otherwise ball will change direction | |
if ((mouse_x >= 300) && (mouse_x <= 1050)) { // do not do anything unless the mouse is inside these coordinates | |
if ((mouse_y >= 200) && (mouse_y <= 475)) { | |
double shoot_x = mouse_x - cannon_x; // x distance between mouse point and cannon rotating point | |
double shoot_y = cannon_y - mouse_y; // y distance between mouse point and cannon rotating point | |
angle = Math.atan(shoot_x / shoot_y); // find the angle needed for shooting the ball. Add 0.09 radians because cannon is always offset by that amount | |
if (angle < 0) { | |
angle += Math.PI; // add pi radians (180 deg) to make angle positive | |
} | |
ballMoving = true; | |
shoot_col = 0; // reset loop counter | |
repaint(); | |
} | |
} | |
} | |
} | |
public void mouseMoved(MouseEvent e) { | |
requestFocus(); | |
mouse_x = e.getX(); // get the mouse x-y coordinates | |
mouse_y = e.getY(); | |
if ((mouse_x >= 300) && (mouse_x <= 1050)) { // do not do anything unless the mouse is inside these coordinates | |
if ((mouse_y >= 200) && (mouse_y <= 475)) { | |
double shoot_x = mouse_x - cannon_x; // x distance between mouse point and cannon rotating point | |
double shoot_y = cannon_y - mouse_y; // y distance between mouse point and cannon rotating point | |
theta = Math.atan(shoot_x / shoot_y); // find the angle needed to rotate cannon. | |
cannonChanged = true; | |
repaint(); | |
} | |
} | |
} | |
// mouse() methods for when user clicks to shoot the ball | |
public void mousePressed(MouseEvent e) {} // mousePressed method | |
public void mouseReleased(MouseEvent e) {} // mouseReleased method | |
public void mouseClicked(MouseEvent e) { // mouseClicked method | |
requestFocus(); | |
feedback = false; // make the positive feedback from the previous shot disappear | |
mouse_x = e.getX(); // get the mouse x-y coordinates | |
mouse_y = e.getY(); | |
if (!ballMoving) { // ball should not be moving while clicking, otherwise ball will change direction | |
if ((mouse_x >= 300) && (mouse_x <= 1050)) { // do not do anything unless the mouse is inside these coordinates | |
if ((mouse_y >= 200) && (mouse_y <= 475)) { | |
double shoot_x = mouse_x - cannon_x; // x distance between mouse point and cannon rotating point | |
double shoot_y = cannon_y - mouse_y; // y distance between mouse point and cannon rotating point | |
angle = Math.atan(shoot_x / shoot_y); // find the angle needed for shooting the ball. Add 0.09 radians because cannon is always offset by that amount | |
if (angle < 0) { | |
angle += Math.PI; // add pi radians (180 deg) to make angle positive | |
} | |
ballMoving = true; | |
repaint(); | |
} | |
} | |
} | |
} | |
public void mouseEntered(MouseEvent e) {} // mouseEntered method | |
public void mouseExited(MouseEvent e) {} // mouseExited method | |
} | |
public class GameInput extends JPanel implements ChangeListener { // GameInput panel header, implements ChangeListener | |
// three JSliders that user can use to change color (HSV) | |
private JSlider hue; | |
private JSlider sat; | |
private JSlider val; | |
// three JLabels so that user can identify which slider is which | |
private JLabel hueLabel; | |
private JLabel satLabel; | |
private JLabel valLabel; | |
// placeholder buttons that just color the backgrounds for the input section | |
private JButton labelPlaceH; | |
private JButton labelPlaceS; | |
private JButton labelPlaceV; | |
private JButton sliderPlaceH; | |
private JButton sliderPlaceS; | |
private JButton sliderPlaceV; | |
public GameInput() { // constructor header | |
setLayout(new GridLayout(3, 2, 0, 5)); // set layout as Grid Layout | |
// create 3 JSliders that control HSV input | |
hue = new JSlider(JSlider.HORIZONTAL, 0, 360, 0); // hue is scale 0-255 | |
sat = new JSlider(JSlider.HORIZONTAL, 0, 100, 100); // sat is scale 0-100 | |
val = new JSlider(JSlider.HORIZONTAL, 0, 100, 100); // val is scale 0-100 | |
// sliders have big ticks and small ticks | |
hue.setMajorTickSpacing(25); // ticks are at multiples of 25 | |
sat.setMajorTickSpacing(10); // ticks are at multiples of 10 | |
val.setMajorTickSpacing(10); | |
hue.setMinorTickSpacing(5); // ticks are at multiples of 5 | |
sat.setMinorTickSpacing(1); // ticks are at multiples of 1 | |
val.setMinorTickSpacing(1); | |
// knob snaps to nearest tick | |
hue.setSnapToTicks(true); | |
sat.setSnapToTicks(true); | |
val.setSnapToTicks(true); | |
// paints the ticks onto the slider | |
hue.setPaintTicks(true); | |
sat.setPaintTicks(true); | |
val.setPaintTicks(true); | |
// paints the number labels onto the slider | |
hue.setPaintLabels(true); | |
sat.setPaintLabels(true); | |
val.setPaintLabels(true); | |
// create 6 placeholder buttons that color the backgrounds for the input section | |
labelPlaceH = new JButton(); | |
labelPlaceS = new JButton(); | |
labelPlaceV = new JButton(); | |
sliderPlaceH = new JButton(); | |
sliderPlaceS = new JButton(); | |
sliderPlaceV = new JButton(); | |
// do not paint the borders of the buttons | |
labelPlaceH.setBorderPainted(false); | |
labelPlaceS.setBorderPainted(false); | |
labelPlaceV.setBorderPainted(false); | |
sliderPlaceH.setBorderPainted(false); | |
sliderPlaceS.setBorderPainted(false); | |
sliderPlaceV.setBorderPainted(false); | |
// set the colors of the buttons in order to make them look like placeholders | |
labelPlaceH.setBackground(lightGray); | |
labelPlaceS.setBackground(lightGray); | |
labelPlaceV.setBackground(lightGray); | |
sliderPlaceH.setBackground(lightGray); | |
sliderPlaceS.setBackground(lightGray); | |
sliderPlaceV.setBackground(lightGray); | |
// set placeholders opaque so that the background colors are visible | |
labelPlaceH.setOpaque(true); | |
labelPlaceS.setOpaque(true); | |
labelPlaceV.setOpaque(true); | |
sliderPlaceH.setOpaque(true); | |
sliderPlaceS.setOpaque(true); | |
sliderPlaceV.setOpaque(true); | |
// create 3 JLabels that label each slider | |
hueLabel = new JLabel("Hue: " + (int) h); | |
satLabel = new JLabel("Saturation: " + (int) s * 100); | |
valLabel = new JLabel("Value: " + (int) v * 100); | |
// set horizontal alignment for the 3 labels | |
hueLabel.setHorizontalAlignment(SwingConstants.CENTER); | |
satLabel.setHorizontalAlignment(SwingConstants.CENTER); | |
valLabel.setHorizontalAlignment(SwingConstants.CENTER); | |
// add sliders and labels to panel | |
add(hueLabel); | |
add(hue); | |
add(satLabel); | |
add(sat); | |
add(valLabel); | |
add(val); | |
// add change listeners to sliders | |
hue.addChangeListener(this); | |
sat.addChangeListener(this); | |
val.addChangeListener(this); | |
} | |
public void paintComponent(Graphics g) { // paintComponent header | |
setBackground(lightestGray); | |
super.paintComponent(g); | |
if (firstTime) { | |
firstTime = false; | |
if (hueMode) { // hue only mode, show hue label and slider in center | |
updateUI(); // need to update the UI before moving on | |
removeAll(); // remove all the components | |
// add the components | |
add(labelPlaceH); | |
add(sliderPlaceH); | |
add(hueLabel); // ones that the user sees | |
add(hue); | |
add(labelPlaceV); | |
add(sliderPlaceV); | |
} else if (satMode) { // saturation only mode, show sat label and slider in center | |
updateUI(); // need to update the UI before moving on | |
removeAll(); // remove all the components | |
// add the components | |
add(labelPlaceH); | |
add(sliderPlaceH); | |
add(satLabel); // ones that the user sees | |
add(sat); | |
add(labelPlaceV); | |
add(sliderPlaceV); | |
} else if (valMode) { // value only mode, show value label and slider in center | |
updateUI(); // need to update the UI before moving on | |
removeAll(); // remove all the component | |
// add the components | |
add(labelPlaceH); | |
add(sliderPlaceH); | |
add(valLabel); // one that the user sees | |
add(val); | |
add(labelPlaceV); | |
add(sliderPlaceV); | |
} else if (allMode) { // show all three sliders and labels | |
updateUI(); // need to update the UI before moving on | |
removeAll(); // remove all the components | |
// add the components | |
add(hueLabel); | |
add(hue); | |
add(satLabel); | |
add(sat); | |
add(valLabel); | |
add(val); | |
} | |
} | |
} | |
public void stateChanged(ChangeEvent e) { // stateChanged header; change the color of the ball being shot in the cannon by using the three HSV sliders | |
ballChanged = true; // shooting ball is being changed | |
fromInput = true; // dont change the round if screen is being repainted from this class | |
JSlider source = (JSlider) e.getSource(); // find source of the slider being changed, change color based on source | |
if (source == hue) { // hue slider | |
h = hue.getValue(); // h is the value of hue slider | |
if (hueMode) { // if hue mode, set saturation and value to max (least influenced) | |
s = 1; | |
v = 1; | |
} | |
hueLabel.setText("hue: " + (int) h); // rewrite the label | |
h = h / 360; // h must be between 0-1 not 0-360 | |
} else if (source == sat) { // sat slider | |
s = sat.getValue(); // s is the value of sat slider | |
if (satMode) { // if saturation mode, need to match the hue value to the ones of the random balls | |
if (presetHue == 0) | |
h = 0; // hue value of red | |
else if (presetHue == 1) | |
h = (float) (60) / 360; // hue value of yellow | |
else if (presetHue == 2) | |
h = (float) (240) / 360; // hue value of blue | |
} | |
satLabel.setText("Sat: " + (int) s); // rewrite the label | |
s = s / 100; // s must be between 0-1 not 0-100 | |
} else if (source == val) { // val slider | |
v = val.getValue(); // v is the value of val slider | |
if (valMode) { // if value mode, need to match the hue value to the ones of the random balls | |
if (presetHue == 0) | |
h = 0; // hue value of red | |
else if (presetHue == 1) | |
h = (float)(60) / 360; // hue value of yellow | |
else if (presetHue == 2) | |
h = (float)(240) / 360; // hue value of blue | |
} | |
valLabel.setText("Val: " + (int) v); // rewrite the label | |
v = v / 100; // v must be between 0-1 not 0-100 | |
} | |
shootColor = Color.getHSBColor(h, s, v); // change color of the ball based on sliders | |
screen.repaint(); // repaint the game screen in order to change color of the shooter ball | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment