【问题标题】:Snake game end game screen贪吃蛇游戏结束画面
【发布时间】:2014-05-07 21:12:19
【问题描述】:

我正在做一个蛇游戏。

我的问题是“游戏结束”图形出现在游戏开始时,但我希望它只在蛇撞到自己时显示。

这是我目前所拥有的:

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.util.*;

import javax.swing.JFrame;

public class Snake extends JFrame implements KeyListener {

private static final long serialVersionUID = 1L;

private boolean gameOver; 
private int windowWidth = 800;
private int windowHeight = 600;
private LinkedList<Point> snake;
private int dx;
private int dy;
private Random generator = new Random();
private Point food;
private int points;


public static void main(String[] args) {
    new Snake();
}

public Snake() {
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(windowWidth, windowHeight);
    this.setResizable(false);
    this.setLocation(100, 100);
    this.setVisible(true);

    this.createBufferStrategy(2);

    this.addKeyListener(this);

    initGame();

    while(true) {
        long start = System.currentTimeMillis();
        gameLoop();
        while(System.currentTimeMillis()-start < 40) {
             //do nothing
        }
    }
}

private void initGame() {
    // game variables initialized here
    snake = new LinkedList<Point>();
    snake.addFirst(new Point(20,20));
    growSnake(5);

    dx = 0;
    dy = 0;

    food = new Point(10,10);

    points = 0;
}

private void gameLoop() {
    // game logic

    // move the snake
    moveSnake(dx, dy);

    // check if snake has eaten food
    if(snake.getFirst().equals(food)) {
        moveFood();
        growSnake(3);
        points++;

    }

    // go through walls 

    if (snake.getFirst().x <= 0){
        snake.getFirst().x = windowWidth/10;//go left, wrap right
    }
    else if (snake.getFirst().x >= windowWidth/10){
        snake.getFirst().x = 0;//go right, wrap left
    } 
    else if (snake.getFirst().y <= 0){
        snake.getFirst().y = windowHeight/10;//go top, wrap bottom
    }
    else if (snake.getFirst().y >= windowHeight/10){
        snake.getFirst().y = 0;//go bottom, wrap top
    }

    // check if the snake has hit itself
    for(int n = 1; n < snake.size(); n++) {
        if(snake.getFirst().equals(snake.get(n))) { 
            initGame();
            gameOver = true; 
        }
    }

    drawFrame();
}

private void drawFrame() {
    // code for drawing
    BufferStrategy bf = this.getBufferStrategy();
    Graphics g = null;

    try {
        g = bf.getDrawGraphics();

        // clear the back buffer (just draw a big black rectangle over it)
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, windowWidth, windowHeight);

        drawSnake(g);
        drawFood(g);
        drawPoints(g);

        if (gameOver == true){
            gameEnd(g);
        } 


    } finally {

        g.dispose();
    }

    // Shows the contents of the backbuffer on the screen.
    bf.show();

    //Tell the System to do the Drawing now, otherwise it can take a few extra ms until 
    //Drawing is done which looks very jerky
    Toolkit.getDefaultToolkit().sync();
}

private void drawSnake (Graphics g) {
    for(int n = 0; n < snake.size(); n++) {
        g.setColor(Color.RED);
        Point p = snake.get(n);
        g.fillOval(p.x*10, p.y*10, 10, 10);
    }
}

private void moveSnake(int dx, int dy) {
    for(int n = snake.size()-1; n >= 1; n--) {
        snake.get(n).setLocation(snake.get(n-1));
    }
    snake.getFirst().x += dx;
    snake.getFirst().y += dy;
}

private void growSnake (int n) {
    while(n > 0) {
        snake.add(new Point(snake.getLast()));
        n--;
    }
}

private void moveFood() {
    food.x = generator.nextInt((windowWidth/10)-4)+2;
    food.y = generator.nextInt((windowHeight/10)-5)+3;
}

private void drawFood(Graphics g) {
    g.setColor(Color.BLUE);
    g.fillOval(food.x*10, food.y*10, 10, 10);
}

private void drawPoints(Graphics g) {
    g.setColor(Color.GRAY);
    g.drawString("points: " + points, 10, 40);
}

private static final Font FONT_LARGE = new Font("Times New Roman", Font.BOLD, 40);

private void gameEnd(Graphics g){

    if (gameOver == true){
        g.setColor(Color.RED);
        g.setFont(FONT_LARGE);
        g.drawString("Game Over",300, 320);
    }
}

@Override
public void keyPressed(KeyEvent e) {
    int key = e.getKeyCode();

    if(key == 37) {//left
        dx = -1;
        dy = 0;
    } else if(key == 38) {//up
        dx = 0;
        dy = -1;
    } else if(key == 39) {//right
        dx = 1;
        dy = 0;
    } else if(key == 40) {//down 
        dx = 0;
        dy = 1;
    }
}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void keyTyped(KeyEvent e) {

}
}

有什么想法吗?

【问题讨论】:

  • Any ideas? 使用调试器?不要写容易出错的if (gameOver == true)而是if (gameOver),而不是像while(System.currentTimeMillis()-start &lt; 40) {}那样主动等待使用Timer/Swing Timer
  • 你没有初始化 gameOver 设置为 false
  • @sherif:这不是问题,因为布尔值在声明时默认为 false。
  • 只是猜测它使代码更具可读性的任何方式

标签: java swing


【解决方案1】:
private void growSnake (int n) {
while(n > 0) {
    snake.add(new Point(snake.getLast()));
    n--;
}

}

因为一开始蛇的唯一元素是Point(20,20)

snake.add(new Point(snake.getLast()));

创建一条只包含相同点的蛇。所以

growSnake(5);

在 initGame() 内部创建与头部相同的 5 个点。

那么,在

private void moveSnake(int dx, int dy) {
for(int n = snake.size()-1; n >= 1; n--) {
    snake.get(n).setLocation(snake.get(n-1));
}
snake.getFirst().x += dx;
snake.getFirst().y += dy;
}

您将 X 和 Y 的值分别更改为 dx 和 dy。问题是,它们的初始值都是 0,所以蛇的头是不动的。 dx 和 dy 值只有在按键后才会改变

public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();

if(key == 37) {//left
    dx = -1;
    dy = 0;
// and so on

所以,总结一下 - 将 dx 或 dy 的默认值更改为 1,因此蛇从游戏开始移动。

还有一件事。你可以将你的蛇“向后”移动——如果你的蛇向右移动并且你按下左键——你的蛇会再次吃掉自己的头——游戏结束。

【讨论】:

  • 谢谢!这帮助我做我想做的事!
【解决方案2】:

我发现了几个问题:

  • 最重要的是,您的代码不遵守 Swing 线程规则,因为您似乎有一段长时间运行的代码,即您的游戏循环,在 Swing 事件线程上被调用。不要这样做,因为这可能会冻结您的 GUI。
  • 改为查找并使用 Swing Timer 进行游戏循环。
  • 接下来,您将使用通过在组件上调用 getGraphics() 获得的 Graphics 对象在 GUI 中进行绘图。此 Graphics 对象不会持续存在,这可能会导致绘图不一致。
  • 而是创建一个扩展 JPanel 或 JComponent 的类,并在 protected void paintComponent(Graphics g) 覆盖方法中进行绘图。
  • 您需要将游戏逻辑从 GUI 中提取出来以简化代码,并使其更易于调试。我会创建一个 SnakeLogic 类来保存每个蛇段的位置、移动每个段、测试交叉点,然后让 GUI 类保存一个 SnakeLogic 对象。

我肯定还会有更多...

【讨论】:

    【解决方案3】:

    因为在新游戏的第一个动作中,蛇的“头”位置与身体的位置相同。所以...这个:

    if(snake.getFirst().equals(snake.get(n)))
    

    应该是:

    if(snake.getFirst().equals(snake.get(n)) && snake.size() > 6)
    

    这样,只有当蛇开始移动时才验证条件(考虑初始大小为5)。

    【讨论】:

    • 如果我想在蛇仍然是 5 号的时候加入“游戏结束”怎么办?
    猜你喜欢
    • 2017-03-14
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多