蛇游戏结束游戏画面

时间:2014-05-07 21:12:20

标签: java swing

我正在制作一个蛇游戏。

我的问题是" Game Over"图形显示在游戏开始时,但我希望它只显示蛇何时进入自身。

这是我到目前为止所做的:

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) {

}
}

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

我看到几个问题:

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

我相信更多会来......

答案 1 :(得分:2)

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;
}

分别用dx和dy改变X和Y的值。问题是,它们的初始值都是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 :(得分:1)

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

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

应该是:

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

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