I am trying to give functionality to a JButton btnReset
restart button ( ) so that the game restarts when the user presses it once a game has finished, the code does not follow the MVC model, it only has a Main ( MainW
) that launches the app and calls to the controller ( SnakeGame
) that has all the logic of the program. But at the end of a game when the button is pressed, it does nothing, it seems that the button is not listening, something that I have already verified. I paste both classes, any help will be welcome...
package Controlador;
import java.awt.Image;
import javax.swing.Timer;
import Vista.MainW;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JButton;
public class SnakeGame extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 3575398609620689669L;
// Constantes del juego
private final int B_WIDTH = 300;
private final int B_HEIGHT = 300;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 900;
private final int RAND_POS = 29;
private final int DELAY = 140;
// coordenadas de la serpiente por sus ejes X e Y
private final int x[] = new int[ALL_DOTS];
private final int y[] = new int[ALL_DOTS];
private int dots;
private int apple_x;
private int apple_y;
private JButton btnReset;
public JButton getBtnReset() {
return btnReset;
}
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 ball;
private Image apple;
private Image head;
/**
* Create the frame.
*/
public SnakeGame() {
initSnakeGame();
}
private void initSnakeGame() {
addKeyListener(new TAdapter());
setBackground(Color.BLACK);
setFocusable(true);
btnReset = new JButton("Reiniciar");
btnReset.setBounds(104, 204, 86, 23);
add(btnReset);
btnReset.setVisible(false);
btnReset.addActionListener(this);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
loadImages();
initGame();
}
private void loadImages() {
ImageIcon iid = new ImageIcon("Images/ball.png");
ball = iid.getImage();
ImageIcon iia = new ImageIcon("Images/apple.png");
apple = iia.getImage();
ImageIcon iih = new ImageIcon("Images/snake.png");
head = iih.getImage();
}
private void initGame() {
dots = 3;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
timer = new Timer(DELAY, this);
setLayout(null);
timer.start();
}
private void checkApple() {
if (x[0] == apple_x && y[0] == apple_y) {
dots++;
locateApple();
}
}
private void checkCollision() {
for (int z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
if (y[0] >= B_HEIGHT) {
inGame = false;
}
if (y[0] < 0) {
inGame = false;
}
if (x[0] >= B_WIDTH) {
inGame = false;
}
if (x[0] < 0) {
inGame = false;
}
if (!inGame) {
timer.stop();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(ball, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
gameOver(g);
btnReset.setVisible(true);
}
}
private void gameOver(Graphics g) {
String msg = "Game Over";
Font small = new Font("Helvetica", Font.BOLD, 14);
FontMetrics metr = getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (B_WIDTH - metr.stringWidth(msg)) / 2, B_HEIGHT / 2);
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 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;
}
}
private void locateApple() {
int r = (int) (Math.random() * RAND_POS);
apple_x = (r * DOT_SIZE);
r = (int) (Math.random() * RAND_POS);
apple_y = (r * DOT_SIZE);
}
// clase privada para manejar las flechas del teclado
private class TAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == getBtnReset()) {
initGame();
}
if (inGame) {
checkApple();
checkCollision();
move();
}
repaint();
}
}
And here I paste the Main that launches the app:
package Vista;
import javax.swing.JFrame;
import Controlador.SnakeGame;
public class MainW extends JFrame{
private static final long serialVersionUID = 2873342823046220930L;
public MainW() {
initUI();
}
private void initUI() {
add(new SnakeGame());
setResizable(false);
pack();
setTitle("Snake game");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
try {
JFrame frame = new MainW();
frame.setVisible(true);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
The button does capture the event and therefore the new game can be made.
The problem that arises is that you ignore resetting the variable
inGame
to its initial valuetrue
so that itdoDrawing()
continues drawing the images; and the other detail is to hide the button.So just...
As this program grows, it will become evident the need to use a method that resets: game times, scores, variables such as
inGame
, etc... It is just a suggestion.P.S. Also as a suggestion, use the call to
repaint()
in a method likemove()
for example and not in the methodactionPerformed()
;D