setBackground搞乱了Thread.sleep

时间:2015-11-06 01:26:58

标签: java swing animation graphics

我尝试过不同的方法为这个蛇游戏制作两个背景,一个是黑色的菜单,另一个是白色的游戏。我找到的最佳解决方案是使用setBackground。但是当我运行游戏时,Thread.sleep搞砸了,现在蛇速度非常快。为了尝试解决这个问题,我将多个值放入Thread.sleep中,但无论值如何,蛇都以相同的速度行进。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Thread;
import java.util.Random;

public class Snake extends JPanel implements KeyListener, MouseListener{
    public  boolean right = false;
    public  boolean left = false;
    public  boolean up = false;
    public  boolean down = false;

    public int snakex[] = new int[10000000];
    public int snakey[] = new int[10000000];
    public int snakeLength = 0;

    public int applex;
    public int appley;

    public int buttonX = 150;
    public int buttonY = 125;

    public boolean appleEaten = true;

    public static boolean reset = false;
    public static boolean ingame = false;
    public static boolean menu = true;

    public static int speed = 200;

    public void forLogic(){
        for(int i = snakeLength; i > 1; i--){
            if(snakeLength > 4 &&  snakex[0] ==  snakex[i] && snakey[0] == snakey[i]){
                System.out.println("You Loose \n Your Score was: " + snakeLength);
                ingame = false;
            }
        }

        Movement();

        if(snakex[0] >= 30*20){
            snakex[0] = 0;
        }
        if(snakex[0] < 0){
            snakex[0] = 29*20;
        }
        if(snakey[0] >= 25*20){
            snakey[0] = 0;
        }
        if(snakey[0] < 0){
            snakey[0] = 24*20;
        }

        if(snakex[0] == applex*20 && snakey[0] == appley*20) {
            appleEaten = true;
            snakeLength++;
            //System.out.println(snakeLength);
        }

        if(appleEaten){
            appleLocation();
            appleEaten = false;
        }
    }

    public void appleLocation(){
        boolean goodToGo = false;
        Random rand = new Random();
        while(!goodToGo){
            applex = rand.nextInt(30);
            appley = rand.nextInt(25);
            boolean checker = false;
            for(int i = snakeLength; i > 0; i--) {
                if (applex == snakex[i]||appley == snakey[i]) {
                    checker = true;
                }
            }
            if(!checker){goodToGo = true;}
        }
    }

    public void Movement(){
        if(reset){
            left = false;
            right = false;
            up = false;
            down = false;

            snakex[0] = 0;
            snakey[0] = 0;
            snakeLength = 1;
            appleLocation();
            reset = false;
        }

        if(right){
            snakex[0] += 20;
        }
        if(left){
            snakex[0] -= 20;
        }
        if(up){
            snakey[0] -= 20;
        }
        if(down){
            snakey[0] += 20;
        }
    }

    public void mouseEntered(MouseEvent e){}

    public void mouseExited(MouseEvent e){}

    public void mousePressed(MouseEvent e){
        int mouseX = e.getX();
        int mouseY = e.getY();
        if(mouseX > buttonX && mouseX < buttonX + 300 && mouseY > buttonY && mouseY < buttonY + 75){
            ingame = true;
        }
    }

    public void mouseReleased(MouseEvent e){}

    public void mouseClicked(MouseEvent e){}

    public void keyTyped(KeyEvent e) {}

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == 39 && !left) {
            right = true;
            up = false;
            down = false;
        }
        if(key == 37 && !right){
            left = true;
            up = false;
            down = false;
        }
        if(key == 38 && !down){
            up = true;
            left = false;
            right = false;
        }
        if(key == 40 && !up){
            down = true;
            left = false;
            right = false;
        }
        if(key == 82){
            reset = true;
        }
    }

    public void keyReleased(KeyEvent e) {}

    @SuppressWarnings("serial")
    public void paint(Graphics g) {
        super.paintComponent(g);
        if(menu){
            setBackground(Color.BLACK);
            g.setColor(Color.green);
            g.setFont(new Font("Courier New", Font.BOLD, 50));
            g.drawString("Snake Game", 150, 50);
            g.drawRect(buttonX, buttonY, 300, 75);
            g.setFont(new Font("Courier New", Font.BOLD, 40));
            g.drawString("PLAY", 250, 175);
        }
        if(ingame) {
            setBackground(Color.WHITE);
            int x = 0;
            int y = 0;
            for (x = 0; x < 30; x++) {
                for (y = 0; y < 25; y++) {
                    g.setColor(Color.black);
                    g.fillRect(x * 20, y * 20, 19, 19);
                }
            }

            g.setColor(Color.red);
            g.fillOval(applex * 20, appley * 20, 19, 19);

            forLogic();

            g.setColor(Color.green);
            for (int i = snakeLength; i > 0; i--) {
                snakex[i] = snakex[(i - 1)];
                snakey[i] = snakey[(i - 1)];
                g.fillRect(snakex[i], snakey[i], 19, 19);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        JFrame jframe = new JFrame("Snake Game");
        Snake snake = new Snake();
        jframe.add(snake);
        snake.addMouseListener(snake);
        snake.addKeyListener(snake);
        jframe.setSize(615, 540);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setFocusable(true);
        jframe.setVisible(true);
        snake.requestFocusInWindow();
        jframe.setLocationRelativeTo(null);

        while(true) {
            if (!menu) {
                ingame = true;
            }
            if (menu == ingame) {
                ingame = false;
            }

            if (menu) {
                snake.repaint();
            }

            if (ingame) {
                while (true) {
                    Thread.sleep(200);
                    snake.repaint();
                }
            }
        }
    }
}

3 个答案:

答案 0 :(得分:3)

我很抱歉直言不讳,但这段代码存在很多问题,很难知道从哪里开始。

的问题:

  • 首先,您在绘画方法中调用setBackground(...),这可能会触发重绘,这通常不会成为问题......
  • 但是你的程序逻辑是从你的paint mehtod覆盖中调用的,这是一个主要问题。当您发现自己不能完全或甚至部分控制何时或甚至调用绘制方法或多长时间,因此在其中包含程序逻辑可能是致命的,并且可能导致您的程序因setBackground调用而完全失灵。
  • 您的Swing代码中还有while (true)次循环和Thread.sleep(...)次调用,如果Swing代码已启动(应该已完成),则代码可能会完全冻结您的GUI Swing事件线程。
  • 你重写了paint方法,然后调用了超级paintComponent,一个不匹配的超级方法,这将打破Swing图形链,可能导致严重的绘画不规则。

建议:

  • 首先,在所有绘画方法之外获取所有程序逻辑。
  • 删除所有Thread.sleep(...)个电话和while (true)个圈。
  • 使用Swing Timer,推进您的游戏&#34; tick&#34;在你的Timer的ActionListener中。
  • 在此&#34; tick&#34;中,更新程序中关键字段的状态
  • 然后拨打repaint();
  • 仅覆盖paintComponent方法
  • 在此覆盖范围内,调用相同的超级方法。
  • 在paintComponent中,使用修改后的字段来更改绘制的内容和方式。
  • 在班级的构造函数中调用setBackground(...)一次。 在绘画方法中拥有游戏逻辑。这表明使用第一原理重写是非常有益的:为游戏循环使用Swing Timer,在Swing代码中不使用其他延迟代码,覆盖paintComponent并在覆盖中调用相同的super方法,将绘画与逻辑分离
  • 阅读教程。你猜测哪些在这​​里工作(你正在发现)。

更多

  • 考虑创建一些非GUI逻辑类。
  • 这可以包括GridPoint网格上每个点的x和y位置
  • 网格类是GridPoint的二维数组,这是一个逻辑网格,用于保存蛇移动的宇宙。
  • SnakePoints可以包含ArrayList<GridPoint>,其中包含蛇上点的 逻辑 位置。
  • 最后一节课也可以设置添加点,移动蛇,吃苹果的方法。
  • 一个定时器,它会告诉SnakePoints前进一个方格

答案 1 :(得分:2)

public void paint(Graphics g) {
    super.paintComponent(g);

不要覆盖paint()。自定义绘画是通过覆盖paintComponent()来完成的。然后你仍然会调用super.paintComponent(g);

if(key == 39 && !left) {

不要使用魔术数字。 API将有变量供您使用。我猜你想要KeyEvent.VK_LEFT。

if(key == 82){

但我不知道这个神奇的数字是什么。

    if(ingame) {
        setBackground(Color.WHITE);

不要在绘画方法中更改组件的属性。绘画方法仅用于绘画。

也许你需要像setPlayingGame(Boolean)这样的方法。然后,如果为true,则设置玩游戏的属性。如果为false,则设置菜单属性。

或者更好的是你有两个面板。一个用于菜单,一个用于游戏。然后使用CardLayout并交换面板,具体取决于您是否要绘制菜单或游戏。

你有太多的游戏逻辑来调试可能是你的问题。

答案 2 :(得分:0)

蛇移动速度太快,因为“移动”蛇的方法太频繁了。你每200毫秒重新绘制一次,但程序的逻辑没有睡眠。你的Thread.sleep应该在程序的逻辑部分:

public void forLogic(){
    for(int i = snakeLength; i > 1; i--){
        if(snakeLength > 4 &&  snakex[0] ==  snakex[i] && snakey[0] == snakey[i]){
            System.out.println("You Loose \n Your Score was: " + snakeLength);
            ingame = false;
        }
    }

    Movement();

    if(snakex[0] >= 30*20){
        snakex[0] = 0;
    }
    if(snakex[0] < 0){
        snakex[0] = 29*20;
    }
    if(snakey[0] >= 25*20){
        snakey[0] = 0;
    }
    if(snakey[0] < 0){
        snakey[0] = 24*20;
    }

    if(snakex[0] == applex*20 && snakey[0] == appley*20) {
        appleEaten = true;
        snakeLength++;
        //System.out.println(snakeLength);
    }

    if(appleEaten){
        appleLocation();
        appleEaten = false;
    }
    try {
        Thread.sleep(speed);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}