I am working on a class project to recreate a Flappy Bird clone on PC. I have this code so far (below) however I would like to replace the red rectangle "bird" with a JPEG of a penguin. Any ideas on how to go about this? I have researched online but cannot seem to get it right; I have never done 2D graphic work in Java. Thank you!
package flappyBird;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;
public class FlappyBird implements ActionListener, MouseListener,
KeyListener
{
public static FlappyBird flappyBird;
public final int WIDTH = 800, HEIGHT = 800;
public Renderer renderer;
public Rectangle bird;
public ArrayList<Rectangle> columns;
public int ticks, yMotion, score;
public boolean gameOver, started;
public Random rand;
public FlappyBird()
{
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
rand = new Random();
jframe.add(renderer);
jframe.setTitle("Flappy Bird");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.addMouseListener(this);
jframe.addKeyListener(this);
jframe.setResizable(false);
jframe.setVisible(true);
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
columns = new ArrayList<Rectangle>();
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
timer.start();
}
public void addColumn(boolean start)
{
int space = 300;
int width = 100;
int height = 50 + rand.nextInt(300);
if (start)
{
columns.add(new Rectangle(WIDTH + width + columns.size() * 300, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(WIDTH + width + (columns.size() - 1) * 300, 0, width, HEIGHT - height - space));
}
else
{
columns.add(new Rectangle(columns.get(columns.size() - 1).x + 600, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(columns.get(columns.size() - 1).x, 0, width, HEIGHT - height - space));
}
}
//Column Color
public void paintColumn(Graphics g, Rectangle column)
{
g.setColor(new Color (112,128,144));
g.fillRect(column.x, column.y, column.width, column.height);
}
public void jump()
{
if (gameOver)
{
//Creates Bird
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
columns.clear();
yMotion = 0;
score = 0;
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
gameOver = false;
}
if (!started)
{
started = true;
}
else if (!gameOver)
{
if (yMotion > 0)
{
yMotion = 0;
}
yMotion -= 10;
}
}
#Override
public void actionPerformed(ActionEvent e)
{
int speed = 10;
ticks++;
if (started)
{
for (int i = 0; i < columns.size(); i++)
{
Rectangle column = columns.get(i);
column.x -= speed;
}
if (ticks % 2 == 0 && yMotion < 15)
{
yMotion += 2;
}
for (int i = 0; i < columns.size(); i++)
{
Rectangle column = columns.get(i);
if (column.x + column.width < 0)
{
columns.remove(column);
if (column.y == 0)
{
addColumn(false);
}
}
}
bird.y += yMotion;
for (Rectangle column : columns)
{
if (column.y == 0 && bird.x + bird.width / 2 > column.x + column.width / 2 - 10 && bird.x + bird.width / 2 < column.x + column.width / 2 + 10)
{
score++;
}
if (column.intersects(bird))
{
gameOver = true;
if (bird.x <= column.x)
{
bird.x = column.x - bird.width;
}
else
{
if (column.y != 0)
{
bird.y = column.y - bird.height;
}
else if (bird.y < column.height)
{
bird.y = column.height;
}
}
}
}
if (bird.y > HEIGHT - 120 || bird.y < 0)
{
gameOver = true;
}
if (bird.y + yMotion >= HEIGHT - 120)
{
bird.y = HEIGHT - 120 - bird.height;
gameOver = true;
}
}
renderer.repaint();
}
public void repaint(Graphics g)
{
//Background
g.setColor(new Color (176,224,230));
g.fillRect(0, 0, WIDTH, HEIGHT);
//Ground under bar
g.setColor(new Color (0,139,139));
g.fillRect(0, HEIGHT - 120, WIDTH, 120);
//Bar above ground
g.setColor(new Color(100,149,237));
g.fillRect(0, HEIGHT - 120, WIDTH, 20);
//Cube color
g.setColor(Color.red);
g.fillRect(bird.x, bird.y, bird.width, bird.height);
for (Rectangle column : columns)
{
paintColumn(g, column);
}
g.setColor(Color.white);
g.setFont(new Font("Arial", 1, 100));
if (!started)
{
g.drawString("Dare to try?", 75, HEIGHT / 2 - 50);
}
if (gameOver)
{
g.drawString("You died!", 100, HEIGHT / 2 - 50);
}
if (!gameOver && started)
{
g.drawString(String.valueOf(score), WIDTH / 2 - 25, 100);
}
}
public static void main(String[] args)
{
flappyBird = new FlappyBird();
}
#Override
public void mouseClicked(MouseEvent e)
{
jump();
}
#Override
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
jump();
}
}
#Override
public void mousePressed(MouseEvent e)
{
}
#Override
public void mouseReleased(MouseEvent e)
{
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
}
You can use the drawImage() Method of the Graphics object:
g.drawImage(yourImage,xPos,yPos,null);
Related
I am build a graph, with a while circle moving along a line, and stoping over for a few seconds at 3 points of the path.
I have managed to do it, however, it does not display the circle moving, it displays only when the circle stops...
I can't understand why.
Many thanks in advance for your help
Here is my code:
public class Robot0 extends JFrame implements ActionListener {
public Robot0(String nom, int larg, int haut) {
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
Timer tm = new Timer(10, this);
private int posX = 0;
private int posY = 0;
private int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
tm.start();
}
int segment = 0;
public void actionPerformed(ActionEvent e) {
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0) {
segment = 1;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0) {
segment = 3;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100) {
segment = 6;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
repaint();
}
// Build the Panel
public static void main(String[] args) {
Robot0 r = new Robot0("Robot0", 800, 600);
}
}
Swing is a single Thread library. All painting tasks are executed in the Event Dispatcher Thread
(EDT).
As commented by Andrew Thompson, running long processes (such as sleep) on the EDT makes keeps this thread busy, so it does not do other things
like updating the gui.
The gui becomes unresponsive (freezes).
So the first thing to do is to remove all sleeping.
To park at each stop, use a second timer:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame implements ActionListener {
private static final int PARKING_TIME = 15000;
Timer moveTimer , waitTimer;
private boolean isParking = false;
public Robot0(String nom, int larg, int haut) {
moveTimer = new Timer(10, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private int posX = 0;
private int posY = 0;
private final int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
moveTimer.start();
}
int segment = 0;
#Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0 && segment != 1) { //!=1 so it will not be invoked again
segment = 1;
isParking = true; //flag that robot is parking
waitTimer.start();
return;
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0 && segment !=3) {
segment = 3;
isParking = true;
waitTimer.start();
return;
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100 && segment !=6) {
segment = 6;
isParking = true;
waitTimer.start();
return;
}
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0", 800, 600));
}
}
TODO:
Implement custom painting on JPanel.
Simplify actionPerformed
logic
Edit: the following is an implementation with some improvements not necessarily related to question asked:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame {
public Robot0(String nom) {
setTitle(nom);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Floor());
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0"));
}
}
class Floor extends JPanel implements ActionListener{
private static final int PARKING_TIME = 5000, REPAINT_TIME = 10, W = 400, H = 200;
private static final int ROOM_SIZE = 30, ROBOT_SIZE = 20, CROSS_SIZE = 10;
private final Timer moveTimer , waitTimer;
private boolean isParking = false;
private int posX = 0, posY = 0;
private final int velX = 1;
// pathway
private static final int PATH_X[] = { 50, 50, 250, 250, 350, 350 };
private static final int PATH_Y[] = { 50, 150, 150, 50, 50, 150 };
//rooms
private static final Point[] ROOM_CENTERS = {new Point(PATH_X[1],PATH_Y[1]),
new Point(PATH_X[3],PATH_Y[3]),
new Point(PATH_X[5],PATH_Y[5]) };
Floor() {
moveTimer = new Timer(REPAINT_TIME, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
posX = PATH_X[0]; posY = PATH_Y[0];
setPreferredSize(new Dimension(W, H));
moveTimer.start(); //no need to restart with every paint
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawPolyline(PATH_X, PATH_Y, 6);
// draw rooms
g.setColor(Color.GREEN);
for(Point center : ROOM_CENTERS){
drawSquareAround(center, g);
}
//robot
g.setColor(Color.WHITE);
g.fillOval( posX - ROBOT_SIZE/2 , posY - ROBOT_SIZE/2 , ROBOT_SIZE, ROBOT_SIZE);
//cross
g.setColor(Color.RED);
g.drawLine(posX - CROSS_SIZE/2, posY, posX + CROSS_SIZE/2, posY);
g.drawLine(posX, posY - CROSS_SIZE/2, posX, posY + CROSS_SIZE/2);
}
private void drawSquareAround(Point center, Graphics g) {
g.drawRect(center.x - ROOM_SIZE/2, center.y - ROOM_SIZE/2, ROOM_SIZE, ROOM_SIZE);
}
#Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
if (posX <= PATH_X[0] && posY < PATH_Y[1]) {// move along the 1st segment
setPosY(posY + velX);
}else if (posX < PATH_X[2] && posY == PATH_Y[1]) { //move along the second segment
setPosX(posX + velX);
}else if (posX == PATH_X[2] && posY > PATH_Y[3]) { //move along the third segment
setPosY(posY - velX);
}else if (posY == PATH_Y[3] && posX < PATH_X[4]) {// move along the fourth segment
setPosX(posX + velX);
}else if (posX == PATH_X[4] && posY < PATH_Y[5]){// move along the fifth segment
setPosY(posY + velX);
}else {
moveTimer.stop(); //move finished, stop repainting
return;
}
//park if at room center
if(isRoomCeter()){
park();
}
repaint();
}
private void park() {
isParking = true; //flag that robot is parking
waitTimer.start();
}
private boolean isRoomCeter() {
for (Point center : ROOM_CENTERS){
if(posX == center.x && posY == center.y) return true;
}
return false;
}
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}
I want to add a simple menu to my Java Snake game which will contain three buttons (New Game, Difficulty and Quit). I have created a class for the menu and a class for the mouse input. I have used an enum to store the states of the game (MAIN_MENU, DIFFICULTY_MENU and GAME) and a variable called STATE which stores the current state.
The main problem is that although the state of the game is changed when the "New Game" button is pressed the game doesn't start. I have tried to add game state checks inside the methods that are involved in setting the gameplay and I have also tried calling those methods from the mousePressed() method of the MouseInput class but none of these worked.
I would greatly appreciate if you could give me some tips on how to solve this issue.
Here's my code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SnakeGame extends JFrame{
public SnakeGame() {
initGUI();
}
public void initGUI() {
add(new GamePlay());
setResizable(false);
pack();
setTitle("The Snake");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new SnakeGame();
frame.setVisible(true);
});
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class GamePlay extends JPanel implements ActionListener {
public static final int HEIGHT = 600;
public static final int WIDTH = 600;
private final int TOTAL_DOTS = 3600;
private final int DOT_SIZE = 10;
private final int RAND_POSITION = 29;
//private final int DELAY = 140;
private final int[] X = new int[TOTAL_DOTS];// the dots on X axis
private final int[] Y = new int[TOTAL_DOTS];//the dots on Y axis
private int dots;
private int apple_X;
private int apple_Y;
private int score = 0;
private int DELAY = 140;
private boolean leftDirection = false;
private boolean rightDirection = true;
private boolean upDirection = false;
private boolean downDirection = false;
private boolean inGame = true;
private Timer timer;
private Image bodyPart;
private Image snakeHead;
private Image apple;
private Menu menu;
public static GameState STATE = GameState.MAIN_MENU;//current game state(it changes when menu buttons are pressed)
public static enum GameState{
MAIN_MENU,
DIFFICULTY_MENU,
GAME
}
public GamePlay() {
setGamePlay();
}
public void setGamePlay() {
addKeyListener(new KeyboardEvent());
addMouseListener(new MouseInput());
setBackground(Color.BLACK);
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
if(STATE == GameState.GAME) {
loadImages();
startGame();
}
}
private void loadImages() {
ImageIcon img2 = new ImageIcon("src/images/dot.png");
bodyPart = img2.getImage();
ImageIcon img1 = new ImageIcon("src/images/head.png");
snakeHead = img1.getImage();
ImageIcon img3 = new ImageIcon("src/images/apple.png");
apple = img3.getImage();
}
//setting the starting snake length and the apple position on the board
public void startGame() {
dots = 3;
for(int i = 0 ; i < dots; i++) {
X[i] = 50 - i * 10;
Y[i] = 50;
}
locateApple();
timer = new Timer(DELAY,this);
//timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(STATE == GameState.GAME) {
draw(g);
}else if(STATE == GameState.MAIN_MENU) {
new Menu().displayMainMenu(g);
}else if(STATE == GameState.DIFFICULTY_MENU) {
new Menu().displayDifficultyMenu(g);
}
System.out.println("End of paint component method");
}
public void draw(Graphics g) {
scoreDisplay(g);
if(inGame) {
g.drawImage(apple, apple_X, apple_Y,this);
for(int i = 0 ; i < dots; i++) {
if(i == 0) {
g.drawImage(snakeHead,X[i], Y[i], this);
}else {
g.drawImage(bodyPart, X[i], Y[i], this);
}
}
Toolkit.getDefaultToolkit().sync();
}else {
gameOver(g);
}
}
public void gameOver(Graphics g) {
String msg = "Game Over!";
String msg2 = "Score: " + score + " " + "Length: " + dots;
Font small = new Font("Comic Sans",Font.BOLD,14 );
FontMetrics messageSize = getFontMetrics(small);
g.setColor(Color.WHITE);
g.setFont(small);
g.drawString(msg, (WIDTH - messageSize.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString(msg2, (WIDTH - messageSize.stringWidth(msg2)) / 2, (HEIGHT / 2) + 20);
restartMessageDisplay(g);
}
public void scoreDisplay(Graphics g) {
String gameScore = "Score: " + score;
String snakeLength = "Snake length: " + dots;
Font small = new Font("Arial", Font.BOLD, 14);
g.setColor(Color.WHITE);
g.setFont(small);
g.drawString(gameScore,480, 20);
g.drawString(snakeLength, 480, 40);
}
public void restartMessageDisplay(Graphics g) {
String restartMessage = " Press Enter to restart";
Font small = new Font("Arial", Font.BOLD, 14);
FontMetrics metrics = getFontMetrics(small);
g.drawString(restartMessage, (WIDTH - metrics.stringWidth(restartMessage)) / 2, (HEIGHT / 2) + 40);
}
private void checkApple() {
if((X[0] == apple_X) && (Y[0] == apple_Y)) {
dots++;
locateApple();
score += 5;//score update
DELAY -= 5;// speed increase when snake eats the apple
if(DELAY >= 40) {
timer.setDelay(DELAY);
}
}
}
//snake move logic
private void move() {
for(int i = dots; i > 0; i--) {
X[i] = X[(i-1)];
Y[i] = Y[(i-1)];
}
if(leftDirection) {
X[0] -= DOT_SIZE;
}
if(rightDirection) {
X[0] += DOT_SIZE;
}
if(upDirection) {
Y[0] -= DOT_SIZE;
}
if(downDirection) {
Y[0] += DOT_SIZE;
}
}
//checking for collision with the walls or the snake itself
private void checkCollision() {
for(int i = dots; i > 0; i--) {
if((i > 4) && (X[0] == X[i]) && (Y[0] == Y[i])) {
inGame = false;
}
}
if(X[0] < 0) {
inGame = false;
}
if(X[0] > WIDTH) {
inGame = false;
}
if(Y[0] < 0) {
inGame = false;
}
if(Y[0] > HEIGHT) {
inGame = false;
}
if(!inGame) {
timer.stop();
}
}
//setting apple position on the board
public void locateApple() {
int random = (int) (Math.random() * RAND_POSITION);
apple_X = random * DOT_SIZE;
random = (int) (Math.random()* RAND_POSITION);
apple_Y = random * DOT_SIZE;
}
#Override
public void actionPerformed(ActionEvent e) {
if(inGame) {
checkApple();
checkCollision();
move();
}
repaint();
}
private class KeyboardEvent extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if((keyCode == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if((keyCode == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if((keyCode == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
leftDirection = false;
rightDirection = false;
}
if((keyCode == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
leftDirection = false;
rightDirection = false;
}
if(keyCode == KeyEvent.VK_PAUSE) {
timer.stop();
}
if(keyCode == KeyEvent.VK_SPACE) {
timer.start();
}
//game restart
if(keyCode == KeyEvent.VK_ENTER) {
if(!inGame) {
inGame = true;
leftDirection = false;
rightDirection = true;
upDirection = false;
downDirection = false;
score = 0;
DELAY = 140;
setGamePlay();
repaint();
}
}
}
}
}
import java.awt.*;
import javax.swing.*;
public class Menu {
public Rectangle newGameButton;
public Rectangle gameDifficultyButton;
public Rectangle quitButton;
public Rectangle easyDifficultyButton;
public Rectangle mediumDifficultyButton;
public Rectangle hardDifficultyButton;
public Button button1;
public Menu() {
int buttonWidth = 150;
int buttonHeight = 50;
newGameButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) - 50, buttonWidth, buttonHeight);
gameDifficultyButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) + 50, buttonWidth, buttonHeight);
quitButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) + 150, buttonWidth, buttonHeight);
easyDifficultyButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) - 50, buttonWidth, buttonHeight);
mediumDifficultyButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) + 50, buttonWidth, buttonHeight);
hardDifficultyButton = new Rectangle((GamePlay.WIDTH - buttonWidth) / 2, (GamePlay.HEIGHT / 2) + 150, buttonWidth, buttonHeight);
}
public void displayMainMenu(Graphics g) {
Graphics2D buttonGraphics =(Graphics2D) g;
String title = "THE SNAKE GAME";
Font font = new Font("Arial", Font.BOLD, 50);
FontMetrics size = g.getFontMetrics(font);
g.setFont(font);
g.setColor(Color.WHITE);
g.drawString(title,(GamePlay.WIDTH-size.stringWidth(title)) / 2, (GamePlay.HEIGHT / 2) - 130);
Font buttonFont = new Font("Arial", Font.BOLD, 28);
g.setFont(buttonFont);
g.drawString("New Game",newGameButton.x + 2, newGameButton.y + 35);
buttonGraphics.draw(newGameButton);
g.drawString("Difficulty",gameDifficultyButton.x + 15,gameDifficultyButton.y + 35);
buttonGraphics.draw(gameDifficultyButton);
g.drawString("Quit", quitButton.x + 45, quitButton.y + 35);
buttonGraphics.draw(quitButton);
}
public void displayDifficultyMenu(Graphics g) {
Graphics2D difficultyMenuGraphics = (Graphics2D) g;
String title = "Difficulty level";
Font difficultyMenuTitleFont = new Font("Arial", Font.BOLD,40);
FontMetrics size = g.getFontMetrics(difficultyMenuTitleFont);
g.setFont(difficultyMenuTitleFont);
g.setColor(Color.WHITE);
g.drawString(title, (GamePlay.WIDTH - size.stringWidth(title)) / 2, (GamePlay.HEIGHT / 2) - 100);
Font difficultyButtonFont = new Font("Arial", Font.BOLD, 28);
g.setFont(difficultyButtonFont);
g.drawString("Easy", easyDifficultyButton.x + 40 , easyDifficultyButton.y + 35);
difficultyMenuGraphics.draw(easyDifficultyButton);
g.drawString("Medium",mediumDifficultyButton.x + 20, mediumDifficultyButton.y + 35);
difficultyMenuGraphics.draw(mediumDifficultyButton);
g.drawString("Hard", hardDifficultyButton.x + 40, hardDifficultyButton.y + 35);
difficultyMenuGraphics.draw(hardDifficultyButton);
}
}
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.Thread.State;
public class MouseInput extends MouseAdapter {
public Rectangle newGameButton;
public Rectangle gameDifficultyButton;
public Rectangle quitButton;
public Rectangle easyDifficultyButton;
public Rectangle mediumDifficultyButton;
public Rectangle hardDifficultyButton;
Graphics g;
public void mousePressed(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
//NewGame button
if(mouseX >= (GamePlay.WIDTH - 150) / 2 && mouseX <= ((GamePlay.WIDTH - 150) / 2) + 150) {
if(mouseY >= (GamePlay.HEIGHT / 2) - 50 && mouseY <= (GamePlay.HEIGHT/ 2)) {
GamePlay.STATE = GamePlay.GameState.GAME;
System.out.println(GamePlay.STATE);
}
}
//Difficulty button
if(mouseX >= (GamePlay.WIDTH - 150) / 2 && mouseX <= ((GamePlay.WIDTH - 150)/ 2 ) + 150) {
if(mouseY >= (GamePlay.HEIGHT / 2) + 50 && mouseY <= (GamePlay.HEIGHT/ 2) + 100) {
GamePlay.STATE = GamePlay.STATE.DIFFICULTY_MENU;
System.out.println("Game state = " + GamePlay.STATE)
}
}
//Quit button
if(mouseX >= (GamePlay.WIDTH - 150) / 2 && mouseX <= ((GamePlay.WIDTH - 150)/ 2 ) + 150) {
if(mouseY >= (GamePlay.HEIGHT / 2) + 150 && mouseY <= (GamePlay.HEIGHT/ 2) + 200) {
System.exit(0);
}
}
}
}
When you click in a box, it should create a circle in that box from the designated coordinate. Unless if its already there then its removed. How do I get currentx and currenty coordinates into the fill oval?
public class Grid extends Applet{
boolean click;
public void init()
{
click = false;
addMouseListener(new MyMouseListener());
}
public void paint(Graphics g)
{
super.paint(g);
g.drawRect(100, 100, 400, 400);
//each box
g.drawRect(100, 100, 100, 100);
g.drawRect(200, 100, 100, 100);
g.drawRect(300, 100, 100, 100);
g.drawRect(400, 100, 100, 100);
//2y
g.drawRect(100, 200, 100, 100);
g.drawRect(200, 200, 100, 100);
g.drawRect(300, 200, 100, 100);
g.drawRect(400, 200, 100, 100);
//3y1x
g.drawRect(100, 300, 100, 100);
g.drawRect(200, 300, 100, 100);
g.drawRect(300, 300, 100, 100);
g.drawRect(400, 300, 100, 100);
//4y1x
g.drawRect(100, 400, 100, 100);
g.drawRect(200, 400, 100, 100);
g.drawRect(300, 400, 100, 100);
g.drawRect(400, 400, 100, 100);
if (click)
{
g.fillOval(currentx, currenty, 100, 100); // problem HERE
}
}
private class MyMouseListener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
int nowx = e.getX();
int nowy = e.getY();
nowx = nowx / 100;
String stringx = Integer.toString(nowx);
stringx = stringx+"00";
int currentx = Integer.parseInt(stringx);
nowy = nowy /100;
String stringy = Integer.toString(nowy);
stringy = stringy+"00";
int currenty = Integer.parseInt(stringy);
click = true;
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
Your main problem is, painting in Swing/AWT is destructive, that is, each time your paint method is called, you are expected to repaint the current state of the component.
In that case, what you really need is some way to model the state of the game so when paint is called, you can repaint it in some meaningful way. This a basic concept of a Model-View-Controller paradigm, where you separate the responsibility of the program into separate layers.
The problem then becomes, how do you translate from the view to model?
The basic idea is take the current x/y coordinates of the mouse and divide it by the cell size. You also need to ensure that the results are within the expected ranges, as you could get a result which is beyond the columns/rows of grids
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final int CELL_COUNT = 3;
private int[][] board;
private int[] cell;
private boolean isX = true;
public TestPane() {
board = new int[CELL_COUNT][CELL_COUNT];
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int[] cell = getCellAt(e.getPoint());
if (board[cell[0]][cell[1]] == 0) {
board[cell[0]][cell[1]] = isX ? 1 : 2;
isX = !isX;
repaint();
}
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
cell = getCellAt(e.getPoint());
repaint();
}
});
}
protected int[] getCellAt(Point p) {
Point offset = getOffset();
int cellSize = getCellSize();
int x = p.x - offset.x;
int y = p.y - offset.y;
int gridx = Math.min(Math.max(0, x / cellSize), CELL_COUNT - 1);
int gridy = Math.min(Math.max(0, y / cellSize), CELL_COUNT - 1);
return new int[]{gridx, gridy};
}
protected Point getOffset() {
int cellSize = getCellSize();
int x = (getWidth() - (cellSize * CELL_COUNT)) / 2;
int y = (getHeight() - (cellSize * CELL_COUNT)) / 2;
return new Point(x, y);
}
protected int getCellSize() {
return Math.min(getWidth() / CELL_COUNT, getHeight() / CELL_COUNT) - 10;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Point offset = getOffset();
int cellSize = getCellSize();
if (cell != null) {
g2d.setColor(new Color(0, 0, 255, 128));
g2d.fillRect(
offset.x + (cellSize * cell[0]),
offset.y + (cellSize * cell[1]),
cellSize,
cellSize);
}
g2d.setColor(Color.BLACK);
FontMetrics fm = g2d.getFontMetrics();
for (int col = 0; col < CELL_COUNT; col++) {
for (int row = 0; row < CELL_COUNT; row++) {
int value = board[col][row];
int x = offset.x + (cellSize * col);
int y = offset.y + (cellSize * row);
String text = "";
switch (value) {
case 1:
text = "X";
break;
case 2:
text = "O";
break;
}
x = x + ((cellSize - fm.stringWidth(text)) / 2);
y = y + ((cellSize - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
}
}
int x = offset.x;
int y = offset.y;
for (int col = 1; col < CELL_COUNT; col++) {
x = offset.x + (col * cellSize);
g2d.drawLine(x, y, x, y + (cellSize * CELL_COUNT));
}
x = offset.x;
for (int row = 1; row < CELL_COUNT; row++) {
y = offset.x + (row * cellSize);
g2d.drawLine(x, y, x + (cellSize * CELL_COUNT), y);
}
g2d.dispose();
}
}
}
First off, if you want to truncate a number to the nearest 100, e.g. 142 becomes 100, all you have to do is:
num = (num/100)*100;
this is because when you divide 2 integers it automatically truncates it, and you can just multiply it back to get the number. And what I think you want in this case is to create some field variables and some accessor methods. At the top of your MouseListener class, you will need to add:
private int mouseX=0;
private int mouseY=0;
then to be able to access these variables from outside of the mouselistener class you will need to add accessor methods:
public int getMouseX(){
return mouseX;
}
in your Grid Class, you can add the field:
private MyMouseListener listener;
and then initialize it in your init by doing:
listener = new MyMouseListener();
addMouseListener(listener);
then you can do the same for mouseY, and finally from your paint method you can then call:
int mouseX = listener.getMouseX();
int mouseY = listener.getMouseY();
and from there it is as simple as doing if statements or switch statements to find which box you clicked in!
Ill first start off with my code,
package flappyBird;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class FlappyBird extends JPanel implements ActionListener, MouseListener, KeyListener
{
public static FlappyBird flappyBird;
public final int WIDTH = 1600, HEIGHT = 800;
public Renderer renderer;
public Rectangle bird;
public ArrayList<Rectangle> columns;
public int ticks, yMotion, score;
public boolean gameOver, started;
public Random rand;
Image Flappy = Toolkit.getDefaultToolkit().getImage("src/flappybird/flappy.png");
Image Icon = Toolkit.getDefaultToolkit().getImage("src/flappybird/Icon.png");
Image Background = Toolkit.getDefaultToolkit().getImage("src/flappybird/background.jpg");
Image Log = Toolkit.getDefaultToolkit().getImage("src/flappybird/Log.png");
Image Grass = Toolkit.getDefaultToolkit().getImage("src/flappybird/Grass.png");
public FlappyBird()
{
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
rand = new Random();
jframe.add(renderer);
jframe.setTitle("Missle Launch");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.addMouseListener(this);
jframe.addKeyListener(this);
jframe.setResizable(false);
jframe.setIconImage(Icon);
jframe.setVisible(true);
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 54, 54);
columns = new ArrayList<Rectangle>();
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
timer.start();
}
public void addColumn(boolean start)
{
int space = 250;
int width = 100;
int height = 50 + rand.nextInt(300);
if (start)
{
columns.add(new Rectangle(WIDTH + width + columns.size() * 300, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(WIDTH + width + (columns.size() - 1) * 300, 0, width, HEIGHT - height - space));
}
else
{
columns.add(new Rectangle(columns.get(columns.size() - 1).x + 600, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(columns.get(columns.size() - 1).x, 0, width, HEIGHT - height - space));
}
}
public void paintColumn(Graphics g, Rectangle column)
{
g.setColor(Color.orange.darker().darker());
g.drawImage(Log, column.x, column.y, column.width, column.height, null);
}
public void jump()
{
if (gameOver)
{
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
columns.clear();
yMotion = 0;
score = 0;
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
gameOver = false;
}
if (!started)
{
started = true;
}
else if (!gameOver)
{
if (yMotion > 0)
{
yMotion = 0;
}
yMotion -= 10;
}
}
#Override
public void actionPerformed(ActionEvent e)
{
int speed = 10;
ticks++;
if (started)
{
for (int i = 0; i < columns.size(); i++)
{
Rectangle column = columns.get(i);
column.x -= speed;
}
if (ticks % 2 == 0 && yMotion < 15)
{
yMotion += 1.5 ;
}
for (int i = 0; i < columns.size(); i++)
{
Rectangle column = columns.get(i);
if (column.x + column.width < 0)
{
columns.remove(column);
if (column.y == 0)
{
addColumn(false);
}
}
}
bird.y += yMotion;
for (Rectangle column : columns)
{
if (column.y == 0 && bird.x + bird.width / 4 > column.x + column.width / 2 - 10 && bird.x + bird.width / 2 < column.x + column.width / 2 + 10)
{
score++;
}
if (column.intersects(bird))
{
gameOver = true;
if (bird.x <= column.x)
{
bird.x = column.x - bird.width;
}
else
{
if (column.y != 0)
{
bird.y = column.y - bird.height;
}
else if (bird.y < column.height)
{
bird.y = column.height;
}
}
}
}
if (bird.y > HEIGHT - 120 || bird.y < 0)
{
gameOver = true;
}
if (bird.y + yMotion >= HEIGHT - 120)
{
bird.y = HEIGHT - 120 - bird.height;
gameOver = true;
}
}
renderer.repaint();
}
public void repaint(Graphics g)
{
g.drawImage(Background, 0, 0, null);
g.drawImage(Grass, 0, 680, null);
g.drawImage(Flappy, bird.x, bird.y, null);
for (Rectangle column : columns)
{
paintColumn(g, column);
}
g.setFont(new Font("Arial", 1, 100));
if (!started)
{
g.setColor(Color.GREEN.darker());
g.drawString("Click to start!", 475, HEIGHT / 2 - 50);
}
if (gameOver)
{
g.setColor(Color.RED.darker());
g.drawString("Game Over!", 500, HEIGHT / 2 - 50);
g.drawString("Your score was: " + String.valueOf(score), WIDTH /2 -430 , 100);
}
if (!gameOver && started)
{
g.setColor(Color.ORANGE);
g.drawString(String.valueOf(score), WIDTH / 2 - 25, 100);
}
}
public void getScore() {
String.valueOf(score);
}
public static void main(String[] args)
{
flappyBird = new FlappyBird();
}
#Override
public void mouseClicked(MouseEvent e)
{
jump();
}
#Override
public void keyReleased(KeyEvent e)
{
if (((e.getKeyCode() == KeyEvent.VK_SPACE) || e.getKeyCode() == KeyEvent.VK_UP))
{
jump();
}
}
#Override
public void mousePressed(MouseEvent e)
{
}
#Override
public void mouseReleased(MouseEvent e)
{
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
}
Now, i have my src package, then my flappyBird package which contains my main class and my image files, when i test the game before compiling the images are there but afterwards the images are gone, any ideas?
After compilation and packaging to JAR you have to reffer to your files as to resources. Load your images using ImageIO.read(InputStream). To get your resources as stream simply
FlappyBird.class.getRousourceAsStream(your/package/name/filename.extension)
While your files are "uncomplited" you can reffer to them as files because they can be read by the native filesystem. When they go to jar, filesystem is unable to get that files (in straightforward way).
After further preview this is the code line i found to run the images:
String Background = "background.jpg";
URL imgURL = FlappyBird.class.getResource(Background);
Toolkit tk = Toolkit.getDefaultToolkit();
Image bg = tk.getImage(imgURL);
this code is used to replace:
Image Background = Toolkit.getDefaultToolkit().getImage("src/flappybird/background.jpg");
i just did the same for each i hope this helps other people looking at the same problem.
Question repeat: How do you get an image stored in the same package of your main class to appear after building it into a .jar file. Via paintImages(Graphics, g)
I have the following program, it's a SubKiller game and I have one question. How do I make the boat launch the bomb anytime I press the down key? So far I have made to launch it multiple times. I can launch the first bomb but when I'm trying to launch the second one, the first one disappears and it doesn't continue it's way. I am stuck on this matter for almost two days, help me please.
I am going to provide you the SSCCE code.
This is the class called SubKillerPanel, basically everything is here, the boat is here, the bomb is here, the submarine is here.
import java.awt.event.*;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Color;
public class SubKillerPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Timer timer;
private int width, height;
private Boat boat;
private Bomb bomb;
private Submarine sub;
public SubKillerPanel() {
setBackground(Color.WHITE);
ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (boat != null) {
boat.updateForNewFrame();
bomb.updateForNewFrame();
sub.updateForNewFrame();
}
repaint();
}
};
timer = new Timer( 20, action );
addMouseListener( new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
requestFocus();
}
}
);
addFocusListener( new FocusListener() {
public void focusGained(FocusEvent evt) {
timer.start();
repaint();
}
public void focusLost(FocusEvent evt) {
timer.stop();
repaint();
}
}
);
addKeyListener( new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
int code = evt.getKeyCode(); // ce tasta a fost apasata
if (code == KeyEvent.VK_LEFT) {
boat.centerX -= 15;
}
else
if (code == KeyEvent.VK_RIGHT) {
boat.centerX += 15;
}
else
if (code == KeyEvent.VK_DOWN) {
if (bomb.isFalling == false)
bomb.isFalling = true;
bomb.centerX = boat.centerX;
bomb.centerY = boat.centerY;
}
}
}
);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (boat == null) {
width = getWidth();
height = getHeight();
boat = new Boat();
sub = new Submarine();
bomb = new Bomb();
}
if (hasFocus())
g.setColor(Color.CYAN);
else {
g.setColor(Color.RED);
g.drawString("CLICK TO ACTIVATE", 20, 30);
g.setColor(Color.GRAY);
}
g.drawRect(0,0,width-1,height-1);
g.drawRect(1,1,width-3,height-3);
g.drawRect(2,2,width-5,height-5);
boat.draw(g);
sub.draw(g);
bomb.draw(g);
}
private class Boat {
int centerX, centerY;
Boat() {
centerX = width/2;
centerY = 80;
}
void updateForNewFrame() {
if (centerX < 0)
centerX = 0;
else
if (centerX > width)
centerX = width;
}
void draw(Graphics g) {
g.setColor(Color.blue);
g.fillRoundRect(centerX - 40, centerY - 20, 80, 40, 20, 20);
}
}
private class Bomb {
int centerX, centerY;
boolean isFalling;
Bomb() {
isFalling = false;
}
void updateForNewFrame() {
if (isFalling) {
if (centerY > height) {
isFalling = false;
}
else
if (Math.abs(centerX - sub.centerX) <= 36 && Math.abs(centerY - sub.centerY) <= 21) {
sub.isExploding = true;
sub.explosionFrameNumber = 1;
isFalling = false; // Bomba reapare in barca
}
else {
centerY += 10;
}
}
}
void draw(Graphics g) {
if ( !isFalling ) {
centerX = boat.centerX;
centerY = boat.centerY + 23;
}
g.setColor(Color.RED);
g.fillOval(centerX - 8, centerY - 8, 16, 16);
}
}
private class Submarine {
int centerX, centerY;
boolean isMovingLeft;
boolean isExploding;
int explosionFrameNumber;
Submarine() {
centerX = (int)(width*Math.random());
centerY = height - 40;
isExploding = false;
isMovingLeft = (Math.random() < 0.5);
}
void updateForNewFrame() {
if (isExploding) {
explosionFrameNumber++;
if (explosionFrameNumber == 30) {
centerX = (int)(width*Math.random());
centerY = height - 40;
isExploding = false;
isMovingLeft = (Math.random() < 0.5);
}
}
else {
if (Math.random() < 0.04) {
isMovingLeft = ! isMovingLeft;
}
if (isMovingLeft) {
centerX -= 5;
if (centerX <= 0) {
centerX = 0;
isMovingLeft = false;
}
}
else {
centerX += 5;
if (centerX > width) {
centerX = width;
isMovingLeft = true;
}
}
}
}
void draw(Graphics g) {
g.setColor(Color.BLACK);
g.fillOval(centerX - 30, centerY - 15, 60, 30);
if (isExploding) {
g.setColor(Color.YELLOW);
g.fillOval(centerX - 4*explosionFrameNumber, centerY - 2*explosionFrameNumber,
8*explosionFrameNumber, 4*explosionFrameNumber);
g.setColor(Color.RED);
g.fillOval(centerX - 2*explosionFrameNumber, centerY - explosionFrameNumber/2,
4*explosionFrameNumber, explosionFrameNumber);
}
}
}
}
The SubKiller class, where the main method is located.
import javax.swing.JFrame;
public class SubKiller {
public static void main(String[] args) {
JFrame window = new JFrame("Sub Killer Game");
SubKillerPanel content = new SubKillerPanel();
window.setContentPane(content);
window.setSize(700, 700);
window.setLocation(0,0);
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setResizable(false);
window.setVisible(true);
}
}
You only have a single Bomb being tracked by the graphics at any time. You should build a collection of Bombs and instantiate a new one whenever the down key is pressed, then iterate through all the collection of Bombs and draw them as needed.
So, instead of private Bomb bomb;
You would have private List<Bomb> bombs;
Afterwards, anywhere you update the single bomb you can use a for loop to go through the list of bombs and have them all update, and then if they are no longer being drawn, remove them from the list.