Java 蛇中的线

Java 蛇中的线,java,multithreading,swing,Java,Multithreading,Swing,我在做一个像蛇一样的游戏。我的启动按钮有问题。当我开始游戏时,一切正常,但如果我用按钮重新开始游戏,一条新的蛇会移动得更快,每次使用按钮重新启动时,它的移动速度都会比上一条快。我不知道代码出了什么问题,有人能解释一下我的错误吗 // In Frame class addButton(buttonPanel, "Start", event -> { counter = -1; // resets points counting area.start();

我在做一个像蛇一样的游戏。我的启动按钮有问题。当我开始游戏时,一切正常,但如果我用按钮重新开始游戏,一条新的蛇会移动得更快,每次使用按钮重新启动时,它的移动速度都会比上一条快。我不知道代码出了什么问题,有人能解释一下我的错误吗

// In Frame class
addButton(buttonPanel, "Start", event -> 
    {
        counter = -1; // resets points counting
    area.start();  // area is a JPanel variable in Frame class
    area.snake();           
    });

// In JPanel class
public void start()
{
    body.removeAll(body); // ArrayList with snake body elements
    add();
    body.get(0).setX(300);
    body.get(0).setY(300);
    repaint();
}

public void snake()
{
    Runnable r = () ->
    {
    try {
            while(!isCollided())
            {
                for(int a=body.size()-1; a>0 ;a--) // Moving elements
                {
                    if(a>0)
                    {
                    body.get(a).setX(body.get(a-1).getX());
                    body.get(a).setY(body.get(a-1).getY());
                    }
                }

    body.get(0).move();
    double a = Math.abs(((body.get(0).getCenterX())-(food.getRandX()+5)));
    double b = Math.abs(((body.get(0).getCenterY())-(food.getRandY()+5)));
    if((a<10) && (b<10)) // Eating and growing a snake
    {
    food.newFood();
    add();
    }

    this.repaint();
    Thread.sleep(waiting); // waiting is final int = 100;
        }
            if(isCollided()) return;
    }
    catch (InterruptedException e) { return;}

    };
    Thread t = new Thread(r);
    t.start();
}
//在框架类中
添加按钮(按钮面板,“开始”,事件->
{
计数器=-1;//重置点计数
area.start();//area是Frame类中的JPanel变量
snake()区域;
});
//在JPanel课堂上
公开作废开始()
{
body.removeAll(body);//包含蛇身元素的ArrayList
添加();
body.get(0.setX(300);
body.get(0.setY(300);
重新油漆();
}
公众假期
{
可运行r=()->
{
试一试{
而(!iscollide())
{
对于(int a=body.size()-1;a>0;a--)//移动元素
{
如果(a>0)
{
body.get(a.setX(body.get(a-1.getX());
body.get(a.setY)(body.get(a-1.getY());
}
}
body.get(0.move();
double a=Math.abs(((body.get(0.getCenterX())-(food.getRandX()+5));
double b=Math.abs((body.get(0.getCenterY())-(food.getRandY()+5));

如果((a在每个
snake()
调用上看起来都是这样的,那么您将创建一个新线程来移动您的snake。我看不出它们被放置在何处

解决此问题的方法之一是只使用一个“移动器”
线程
。按下按钮可以重置字段(包括snake)

这里的诀窍是确保数据结构(表示snake和字段)不会同时被两个线程修改(因为有一个mover线程和一个UI线程处理重置字段的按钮单击)

同步可以用来克服这个困难

private final Object monitor = new Object();
然后在你的移动线程中

while (!isCollided()) {
    synchronized (monitor) {
        // make all the modifications to the shared data (i.e. the field)
    }
    ...
    Thread.sleep(...);
}
在“新游戏”按钮中,单击处理程序:

synchronized (monitor) {
    // reset the shared data (the field)
}

重要的一点是要确保
synchronized
下的代码能够快速工作。如果你的移动线程获得锁,然后在锁内工作几秒钟,那么你的按钮点击处理程序将不得不等待所有这些秒钟,你的UI将冻结。

那么我们可能需要该按钮代码。我在上面的代码中没有看到任何内容at似乎在处理“速度”…在每次
snake()
调用中,您都会添加一个新的“移动器”
线程。但我不知道您如何处理它们。请尝试使用调试程序。那么,如何在不添加新移动器线程的情况下重新启动游戏?