java - 如何为 Java 贪吃蛇游戏创建一个简单的菜单?
问题描述
我想在我的 Java Snake 游戏中添加一个简单的菜单,其中包含三个按钮(新游戏、难度和退出)。我为菜单创建了一个类,为鼠标输入创建了一个类。我使用了一个枚举来存储游戏的状态(MAIN_MENU、DIFFICULTY_MENU 和 GAME)和一个名为 STATE 的变量来存储当前状态。
主要问题是,尽管按下“新游戏”按钮时游戏状态发生了变化,但游戏并没有开始。我尝试在设置游戏玩法所涉及的方法中添加游戏状态检查,并且我还尝试从 MouseInput 类的 mousePressed() 方法调用这些方法,但这些方法都不起作用。
如果您能给我一些有关如何解决此问题的提示,我将不胜感激。这是我的代码:
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);
}
}
}
}
解决方案
推荐阅读
- javascript - 未捕获的 SyntaxError:函数中的输入意外结束
- sql - SQL 无法让 WHERE EXISTS 子句正常工作,并且仅返回在特定日期内具有客户端类型的行
- c++ - 我可以使用条件运算符将输入流传递给函数吗?
- html - 有没有办法让项目在布局中间居中
- javascript - 使用 React.js 语法将对象渲染到表
- javascript - 使用 JS/jQuery 将项目附加到存储在变量中的列表
- git - 如何在使用 rebase -ir 处理之前的不相关提交后重做合并冲突解决?
- java - 为什么在表中插入记录后休眠更新
- sql - 在拆分表单视图中,如何从子表单中获取准确的总计,目前需要在总计正确之前选择每条记录
- cassandra - Cassandra 3.11.4 中服务器端的慢速查询记录器 Cassandra