Redo main menu
parent
424e71eb74
commit
ad6ccaa032
|
@ -13,32 +13,21 @@ public class GameFrame extends JFrame{
|
||||||
|
|
||||||
MenuPanel menu;
|
MenuPanel menu;
|
||||||
GamePanel game;
|
GamePanel game;
|
||||||
boolean startGame = false;
|
JPanel main;
|
||||||
|
|
||||||
public GameFrame(){
|
public GameFrame(){
|
||||||
menu = new MenuPanel();
|
|
||||||
while (!startGame) {
|
|
||||||
startGame = menu.hasButtonClicked();
|
|
||||||
try {
|
|
||||||
Thread.sleep(10);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu.setVisible(false); // hide menu when game has launched
|
|
||||||
try {
|
try {
|
||||||
game = new GamePanel(); //run GamePanel constructor
|
main = new JPanel();
|
||||||
} catch (IOException | SpriteException e) {
|
main.setLayout(new CardLayout());
|
||||||
|
menu = new MenuPanel(main);
|
||||||
|
game = new GamePanel(main); //run GamePanel constructor
|
||||||
|
main.add(menu, "menu");
|
||||||
|
main.add(game, "game");
|
||||||
|
} catch (IOException | SpriteException | UnsupportedAudioFileException | LineUnavailableException e) {
|
||||||
// TODO: handle IO errors gracefully
|
// TODO: handle IO errors gracefully
|
||||||
// exceptions are raised when tiles are not found or are of incorrect dimensions
|
// exceptions are raised when tiles are not found or are of incorrect dimensions
|
||||||
menu.setVisible(true);
|
|
||||||
menu.launchGame.setText("Invalid sprites error");
|
|
||||||
} catch (UnsupportedAudioFileException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (LineUnavailableException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
this.add(game);
|
this.add(main);
|
||||||
this.setTitle("GUI is cool!"); //set title for frame
|
this.setTitle("GUI is cool!"); //set title for frame
|
||||||
// set game icon and ignore exception (failing to set icon doesn't otherwise break program)
|
// set game icon and ignore exception (failing to set icon doesn't otherwise break program)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -24,6 +24,8 @@ public class GamePanel extends JPanel implements Runnable, KeyListener{
|
||||||
public static final int GAME_WIDTH = 1225;
|
public static final int GAME_WIDTH = 1225;
|
||||||
public static final int GAME_HEIGHT = 630;
|
public static final int GAME_HEIGHT = 630;
|
||||||
|
|
||||||
|
public JPanel gameFrame;
|
||||||
|
|
||||||
public Thread gameThread;
|
public Thread gameThread;
|
||||||
public Image image;
|
public Image image;
|
||||||
public Graphics graphics;
|
public Graphics graphics;
|
||||||
|
@ -47,7 +49,8 @@ public class GamePanel extends JPanel implements Runnable, KeyListener{
|
||||||
public BufferedImage box = getImage("img/tiles/boxes/box.png");
|
public BufferedImage box = getImage("img/tiles/boxes/box.png");
|
||||||
public BufferedImage boxCoin = getImage("img/tiles/boxes/boxCoin.png");
|
public BufferedImage boxCoin = getImage("img/tiles/boxes/boxCoin.png");
|
||||||
|
|
||||||
public GamePanel() throws IOException, SpriteException, UnsupportedAudioFileException, LineUnavailableException {
|
public GamePanel(JPanel gameFrame) throws IOException, SpriteException, UnsupportedAudioFileException, LineUnavailableException {
|
||||||
|
this.gameFrame = gameFrame;
|
||||||
camera = new Camera(0);
|
camera = new Camera(0);
|
||||||
background = new BackgroundImage(0, 0, backgroundImage, GAME_WIDTH, GAME_HEIGHT, 10);
|
background = new BackgroundImage(0, 0, backgroundImage, GAME_WIDTH, GAME_HEIGHT, 10);
|
||||||
try {
|
try {
|
||||||
|
@ -80,7 +83,16 @@ public class GamePanel extends JPanel implements Runnable, KeyListener{
|
||||||
// the height of 35 is set because it is half of the original tile height (i.e., 70px)
|
// the height of 35 is set because it is half of the original tile height (i.e., 70px)
|
||||||
this.setFocusable(true); //make everything in this class appear on the screen
|
this.setFocusable(true); //make everything in this class appear on the screen
|
||||||
this.addKeyListener(this); //start listening for keyboard input
|
this.addKeyListener(this); //start listening for keyboard input
|
||||||
|
// request focus when the CardLayout selects this game
|
||||||
|
this.addComponentListener(new ComponentAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentShown(ComponentEvent cEvt) {
|
||||||
|
Component src = (Component) cEvt.getSource();
|
||||||
|
src.requestFocusInWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
//add the MousePressed method from the MouseAdapter - by doing this we can listen for mouse input. We do this differently from the KeyListener because MouseAdapter has SEVEN mandatory methods - we only need one of them, and we don't want to make 6 empty methods
|
//add the MousePressed method from the MouseAdapter - by doing this we can listen for mouse input. We do this differently from the KeyListener because MouseAdapter has SEVEN mandatory methods - we only need one of them, and we don't want to make 6 empty methods
|
||||||
addMouseListener(new MouseAdapter() {
|
addMouseListener(new MouseAdapter() {
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
|
@ -196,7 +208,6 @@ public class GamePanel extends JPanel implements Runnable, KeyListener{
|
||||||
//if a key is pressed, we'll send it over to the Player class for processing
|
//if a key is pressed, we'll send it over to the Player class for processing
|
||||||
public void keyPressed(KeyEvent e){
|
public void keyPressed(KeyEvent e){
|
||||||
player.keyPressed(e);
|
player.keyPressed(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//if a key is released, we'll send it over to the Player class for processing
|
//if a key is released, we'll send it over to the Player class for processing
|
||||||
|
@ -228,6 +239,4 @@ public class GamePanel extends JPanel implements Runnable, KeyListener{
|
||||||
return flippedImage;
|
return flippedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,45 +1,148 @@
|
||||||
import javax.swing.*;
|
/* GamePanel class acts as the main "game loop" - continuously runs the game and calls whatever needs to be called
|
||||||
|
|
||||||
|
Child of JPanel because JPanel contains methods for drawing to the screen
|
||||||
|
|
||||||
|
Implements KeyListener interface to listen for keyboard input
|
||||||
|
|
||||||
|
Implements Runnable interface to use "threading" - let the game do two things at once
|
||||||
|
|
||||||
|
*/
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.*;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Arrays;
|
import java.io.IOException;
|
||||||
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
public class MenuPanel extends JFrame implements ActionListener {
|
public class MenuPanel extends JPanel implements Runnable, KeyListener{
|
||||||
|
|
||||||
private Boolean buttonClicked = false;
|
//dimensions of window
|
||||||
public JButton launchGame;
|
public static final int GAME_WIDTH = 1225;
|
||||||
Container menuContainer;
|
public static final int GAME_HEIGHT = 630;
|
||||||
|
public final static int TOTAL_BOXES = 2;
|
||||||
|
|
||||||
public MenuPanel() {
|
public JPanel gameFrame;
|
||||||
this.setTitle("First");
|
|
||||||
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
|
||||||
this.setSize(1225, 630);
|
|
||||||
|
|
||||||
launchGame = new JButton("Click");
|
public Thread gameThread;
|
||||||
launchGame.addActionListener(this);
|
public Image image;
|
||||||
|
public Graphics graphics;
|
||||||
|
public static Player player;
|
||||||
|
public BackgroundImage background;
|
||||||
|
public int playerFrame, enemyFrame;
|
||||||
|
// keeps track of how many ticks has elapsed since last frame change
|
||||||
|
public int currentBox = 0;
|
||||||
|
|
||||||
menuContainer = getContentPane();
|
// image imports begin here
|
||||||
menuContainer.setLayout(new FlowLayout());
|
public BufferedImage backgroundImage = GamePanel.getImage("img/backgrounds/pointyMountains.png");
|
||||||
menuContainer.add(launchGame);
|
|
||||||
this.setVisible(true);
|
public MenuPanel(JPanel gameFrame) throws IOException, SpriteException, UnsupportedAudioFileException, LineUnavailableException {
|
||||||
|
this.gameFrame = gameFrame;
|
||||||
|
|
||||||
|
background = new BackgroundImage(0, 0, backgroundImage, GAME_WIDTH, GAME_HEIGHT, 10);
|
||||||
|
// the height of 35 is set because it is half of the original tile height (i.e., 70px)
|
||||||
|
this.setFocusable(true); //make everything in this class appear on the screen
|
||||||
|
this.addKeyListener(this); //start listening for keyboard input
|
||||||
|
// request focus when the CardLayout selects this game
|
||||||
|
this.addComponentListener(new ComponentAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentShown(ComponentEvent cEvt) {
|
||||||
|
Component src = (Component) cEvt.getSource();
|
||||||
|
src.requestFocusInWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
//add the MousePressed method from the MouseAdapter - by doing this we can listen for mouse input. We do this differently from the KeyListener because MouseAdapter has SEVEN mandatory methods - we only need one of them, and we don't want to make 6 empty methods
|
||||||
|
addMouseListener(new MouseAdapter() {
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
player.mousePressed(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setPreferredSize(new Dimension(GAME_WIDTH, GAME_HEIGHT));
|
||||||
|
|
||||||
|
//make this class run at the same time as other classes (without this each class would "pause" while another class runs). By using threading we can remove lag, and also allows us to do features like display timers in real time!
|
||||||
|
gameThread = new Thread(this);
|
||||||
|
gameThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void paint(Graphics g) {
|
//paint is a method in java.awt library that we are overriding. It is a special method - it is called automatically in the background in order to update what appears in the window. You NEVER call paint() yourself
|
||||||
super.paint(g);
|
public void paint(Graphics g){
|
||||||
draw(g);
|
//we are using "double buffering here" - if we draw images directly onto the screen, it takes time and the human eye can actually notice flashes of lag as each pixel on the screen is drawn one at a time. Instead, we are going to draw images OFF the screen, then simply move the image on screen as needed.
|
||||||
|
image = createImage(GAME_WIDTH, GAME_HEIGHT); //draw off screen
|
||||||
|
graphics = image.getGraphics();
|
||||||
|
draw(graphics, playerFrame, enemyFrame);//update the positions of everything on the screen
|
||||||
|
g.drawImage(image, 0, 0, this); //move the image on the screen
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Graphics g) {
|
//call the draw methods in each class to update positions as things move
|
||||||
g.setColor(Color.black);
|
public void draw(Graphics g, int playerFrame, int enemyFrame){
|
||||||
g.setFont(new Font("Monospaced", Font.PLAIN, 60));
|
background.draw(g);
|
||||||
g.setColor(Color.white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent evt) {
|
//call the move methods in other classes to update positions
|
||||||
buttonClicked = true;
|
//this method is constantly called from run(). By doing this, movements appear fluid and natural. If we take this out the movements appear sluggish and laggy
|
||||||
|
public void move(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasButtonClicked() {
|
//run() method is what makes the game continue running without end. It calls other methods to move objects, check for collision, and update the screen
|
||||||
return buttonClicked;
|
public void run(){
|
||||||
|
//the CPU runs our game code too quickly - we need to slow it down! The following lines of code "force" the computer to get stuck in a loop for short intervals between calling other methods to update the screen.
|
||||||
|
long lastTime = System.nanoTime();
|
||||||
|
double amountOfTicks = 60;
|
||||||
|
double ns = 1000000000/amountOfTicks;
|
||||||
|
double delta = 0;
|
||||||
|
long now;
|
||||||
|
|
||||||
|
while(true){ //this is the infinite game loop
|
||||||
|
now = System.nanoTime();
|
||||||
|
delta = delta + (now-lastTime)/ns;
|
||||||
|
lastTime = now;
|
||||||
|
|
||||||
|
//only move objects around and update screen if enough time has passed
|
||||||
|
if(delta >= 1){
|
||||||
|
move();
|
||||||
|
repaint();
|
||||||
|
delta--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if a key is pressed, we'll send it over to the Player class for processing
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||||
|
CardLayout cardLayout = (CardLayout) gameFrame.getLayout();
|
||||||
|
cardLayout.next(gameFrame);
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
|
||||||
|
currentBox = (currentBox + 1) % TOTAL_BOXES;
|
||||||
|
// sleep to prevent excessively fast scrolling
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
} else if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
|
||||||
|
// if currentBox > 0, subtract one
|
||||||
|
// else, set to TOTAL_BOXES-1
|
||||||
|
currentBox = currentBox > 0 ? currentBox - 1:TOTAL_BOXES - 1;
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//if a key is released, we'll send it over to the Player class for processing
|
||||||
|
public void keyReleased(KeyEvent e){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//left empty because we don't need it; must be here because it is required to be overridded by the KeyListener interface
|
||||||
|
public void keyTyped(KeyEvent e){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ public final class TextManager {
|
||||||
// utility class, constructor is private to prevent initialization
|
// utility class, constructor is private to prevent initialization
|
||||||
private TextManager() {}
|
private TextManager() {}
|
||||||
|
|
||||||
private static void drawCenteredTextBox(Graphics g, int y, int xWidth, int yHeight, int totalWidth,
|
public static void drawCenteredTextBox(Graphics g, int y, int xWidth, int yHeight, int totalWidth,
|
||||||
String text, Color backgroundColor, Color textColor) {
|
String text, Color backgroundColor, Color textColor) {
|
||||||
int newX = (totalWidth - xWidth)/2;
|
int newX = (totalWidth - xWidth)/2;
|
||||||
int newY = y - yHeight/2;
|
int newY = y - yHeight/2;
|
||||||
|
@ -13,7 +13,8 @@ public final class TextManager {
|
||||||
g.setColor(textColor);
|
g.setColor(textColor);
|
||||||
drawCenteredString(g, y, newX, xWidth, text);
|
drawCenteredString(g, y, newX, xWidth, text);
|
||||||
}
|
}
|
||||||
private static void drawCenteredString(Graphics g, int y, int x, int xWidth, String text) {
|
|
||||||
|
public static void drawCenteredString(Graphics g, int y, int x, int xWidth, String text) {
|
||||||
int newX, newY;
|
int newX, newY;
|
||||||
// get font size
|
// get font size
|
||||||
FontMetrics metrics = g.getFontMetrics();
|
FontMetrics metrics = g.getFontMetrics();
|
||||||
|
|
Loading…
Reference in New Issue