贪吃蛇游戏:当蛇吃到自己时如何停止游戏

4

我正在制作一个贪吃蛇游戏,它工作得很好,除了蛇吃自己的部分。

以下是我的代码:

障碍类

class Obstacle {
    int x, y;

    public Obstacle(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void draw(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(x, y, 10, 10);
    }
}

食品类

class Food {
    int x, y;

    public Food(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void draw(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(x, y, 10, 10);
    }
}

Body类

class Body {
    int x, y;

    public Body(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(x, y, 10, 10);
        g.setColor(Color.black);
        g.drawRect(x, y, 10, 10);
    }
}

屏幕类

class Screen extends JPanel implements ActionListener, KeyListener {
    int WIDTH = 800, HEIGHT = 800;
    public static int time = 50;
    Timer t;
    int x = 400, y = 400;
    boolean right = false, left = false, up = false, down = false;
    public static int grade = 0;

    LinkedList<Food> foods;
    LinkedList<Body> snake;
    LinkedList<Obstacle> block;

    Body b;
    Food f;
    Obstacle k;

    Random rand = new Random();
    int size = 3;

    public Screen() {

        init();
    }


    public void init() {

        block = new LinkedList<Obstacle>();
        foods = new LinkedList<Food>();
        snake = new LinkedList<Body>();

        level();
        t = new Timer(time, this);
        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public void tracking() {

        if (x < 0 || x > 800 || y < 0 || y > 800) {
            hit();
        }
    }

    public void level() {
        Object[] options = {"Level 1", "Level 2", "Level 3"};

        int option = JOptionPane.showOptionDialog(null, "Please Select a Level", "Level Option",
        JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]);

        switch (option) {
        case JOptionPane.YES_OPTION: 
            System.out.println("Before: " + time);
            time = 50;
            System.out.println("After: " + time);
            break;
        case JOptionPane.NO_OPTION: 
            System.out.println("Before: " + time);
            time = 30;
            System.out.println("After: " + time);
            break;
        case JOptionPane.CANCEL_OPTION: 
            System.out.println("Before: " + time);
            time = 10;
            System.out.println("After: " + time);
            break;
        } 
    }

    public void hit() {
        t.stop();
        if (JOptionPane.showConfirmDialog(null, "Snake: You hit the wall! \nRestart the Game?", "OUCH!!!", 
                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
            x = 400;
            y = 400;
            while (snake.size() != 3) {
                snake.remove();
                size = 3;
            }
            init();

        } else {
            System.exit(0);
        }
    }

    public void move() {
        if (right) x += 10;
        if (left) x -= 10;
        if (up) y -= 10;
        if (down) y += 10;
    }

    public void snake() {
        if (snake.size() == 0) {
            b = new Body(x, y);
            snake.add(b);
        }
        move();
        b = new Body(x, y);
        snake.add(b);

        if (snake.size() > size) {
            snake.remove(0);
        }
    }

    public void food() {
        if (foods.size() == 0) {
            int ok = 0;
            int rx = 0;
            int ry = 0;
            while (ok != 1) {
                rx = (int) (rand.nextInt(700) + 1);
                ry = (int) (rand.nextInt(700) + 1);

                if ((rx % 10) == 0 && (ry % 10) == 0) {
                    ok = 1;
                } 
            }
            f = new Food(rx, ry);
            foods.add(f);
        }

        if (snake.get(snake.size() - 1).x == foods.get(0).x && snake.get(snake.size() - 1).y == foods.get(0).y) {
            foods.remove();
            size++;
            grade += 100;
        }
    }

    public void block() {
        if (block.size() == 0) {
            int ok = 0;
            int rx = 0;
            int ry = 0;
            while (ok != 15) {
                rx = (int) (rand.nextInt(750) + 1);
                ry = (int) (rand.nextInt(750) + 1);

                if ((rx % 10) == 0 && (ry % 10) == 0) {
                    k = new Obstacle(rx, ry);
                    block.add(k);
                    int temp = 10;

                    int r = (int) (rand.nextInt(2) + 1);

                    for (int i = 0; i < 5; i++) {

                        if (r == 1) {
                            k = new Obstacle(rx + temp , ry);
                        } else if (r == 2) {
                            k = new Obstacle(rx , ry + temp);
                        }
                        block.add(k);

                        if ((k.x == foods.get(0).x && k.y == foods.get(0).y) || 
                            (k.x == 400 && k.y == 400) || 
                            ((k.x >= 350 && k.x <= 450) && (k.y >= 350 && k.y <= 450)))  {
                            block.remove(k);
                        }

                        temp += 10;
                    }
                    ok++;
                } 
            }
        }

        for (int i = 0; i < block.size(); i++) {
            if (snake.get(snake.size() - 1).x == block.get(i).x && snake.get(snake.size() - 1).y == block.get(i).y) {
                hit();
            }
        }
    }

    public void update() {
        snake();
        food();
        block();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.DARK_GRAY);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(Color.BLACK);
        for (int i = 1; i < WIDTH / 10; i++) {
            g.drawLine(i * 10, 0, i * 10, HEIGHT);
        }
        for (int i = 1; i < HEIGHT / 10; i++) {
            g.drawLine(0, i * 10, WIDTH, i * 10);
        }

        for (int i = 0; i < snake.size(); i++) {
            snake.get(i).draw(g);
        }

        for (int i = 0; i < foods.size(); i++) {
            foods.get(i).draw(g);
        }

        for (int i = 0; i < block.size(); i++) {
            block.get(i).draw(g);
        } 
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        update();
        tracking();
        repaint(); 
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_RIGHT && left == false) { 
            up = false;
            down = false;
            right = true;

        }
        if (key == KeyEvent.VK_LEFT && right == false) { 
            up = false;
            down = false;
            left = true;
        }
        if (key == KeyEvent.VK_UP && down == false) {
            left = false;
            right = false;
            up = true;
        }
        if (key == KeyEvent.VK_DOWN && up == false) {
            left = false;
            right = false;
            down = true;
        } 
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

还有主类SnakeGame

public class SnakeGame extends JFrame {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        Screen s = new Screen();
        f.add(s);
        f.setSize(810, 810);
        f.setVisible(true);
        f.setLocationRelativeTo(null);
        f.setResizable(false);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

所以一开始,我决定在蛇头吃到自己的尾巴时进行比较,但由于我的蛇在移动,尾巴的x和y会跟随头部的x和y,因此比较总是为真

我也考虑过当蛇改变方向时,编写一些代码来跟踪x y坐标及其尾巴的x y坐标,但我不知道如何实现

是否有其他方法可以使游戏在蛇吃到自己时停止?


1
Body 应该知道它有多少个段落和它的长度。 - MadProgrammer
@HovercraftFullOfEels 我的英语口语不错...但打字就不太确定了... - MadProgrammer
@MadProgrammer:我只是稍微调整一下你的话,因为我认为你的意思很明显。不过我不确定那个单词是澳大利亚拼写方式。 - Hovercraft Full Of Eels
1
@HovercraftFullOfEels 那是我拼写的单词。我是个程序员,只需要拼写 xyi ;) - MadProgrammer
1
@MadProgrammer snake 知道... - Daniel
1个回答

1
当您调用move();时,您会获得xy的新值,即蛇头正在移动到的位置。我看到您的LinkedList<Body> snake;保存了蛇身每个部分的位置。
如果在每次调用move();时,将下一个“头”位置与蛇的所有其他部分进行比较,您将找出它是否被撞击。
类似于这样的东西:
        for (int i = 0; i < snake.size(); i++) {

        if ((x == snake.get(i).x) && y == snake.get(i).y) {
            hit();
        }
    }

游戏将以hit();开始,因为“头”的xy与您的全局xy变量匹配,所以您需要修复它(即等待move();调用开始检查)。 编辑: 这是一个示例修改:
在您的Screen类中添加boolean started = false;
snake()方法更改为检查碰撞:
public void snake() {

if (snake.size() == 0) {
    b = new Body(x, y);
    snake.add(b);

}
move();

if (started) {

    for (int i = 0; i < snake.size(); i++) {

        if ((x == snake.get(i).x) && y == snake.get(i).y) {
            hit();
        }
    }

}
b = new Body(x, y);
snake.add(b);

if (snake.size() > size) {
        snake.remove(0);
}

}

food()方法的末尾添加started = true;(找不到更好的位置,但我认为你可以!):
public void food() {
    if (foods.size() == 0) {
        int ok = 0;
        int rx = 0;
        int ry = 0;
        while (ok != 1) {
            rx = (int) (rand.nextInt(700) + 1);
            ry = (int) (rand.nextInt(700) + 1);

            if ((rx % 10) == 0 && (ry % 10) == 0) {
                ok = 1;
            }
        }
        f = new Food(rx, ry);
        foods.add(f);
    }

    if (snake.get(snake.size() - 1).x == foods.get(0).x
            && snake.get(snake.size() - 1).y == foods.get(0).y) {
        foods.remove();
        size++;
        grade += 100;
        started = true;
    }
}

而且它应该能够工作!

Snake hitting itself


事情是尾巴会跟随头部移动,所以每次头部移动时,尾巴会接收头部的x值和y值,并使比较始终为真。 - user47103
并不是真的 - 我的想法是将最近更改的x和y值与整个主体进行比较,在赋值之前 - 蛇即将移动,当它移动时,它会碰到,因此我们可以假设并结束游戏。 - Daniel
谢谢,我现在有点明白你的意思了。我试图比较它的头和身体,所以它没有起作用。无论如何,非常感谢你:D - user47103

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接