释放钥匙时游戏滞后

时间:2013-10-15 15:22:32

标签: java awt game-physics keylistener 2d-games

我正在制作一个java 2d侧卷轴并且我同时遇到多个键的问题。如右+上。每当你向上释放时,即使向右按下,你仍然会向右移动,然后慢慢地回到地面。这是我设置的键盘监听器。 dx是我的水平移动速度,dy是垂直高度。下面是字符类

public void keyPressed(KeyEvent e) {
    int key = e.getKeyCode();
    if (key == KeyEvent.VK_LEFT) {
        dx = -5;
        mainCharacterImageFacing = l.getImage();
        }

    if (key == KeyEvent.VK_RIGHT) {
        dx = 5;
        mainCharacterImageFacing = r.getImage();
    } 

    if (key == KeyEvent.VK_UP) {
        dy = 1;
        mainCharacterImageFacing = r.getImage();
    }

}

public void keyReleased(KeyEvent e) {
    int key = e.getKeyCode();
    if (key == KeyEvent.VK_LEFT);
    dx = 0;
    if (key == KeyEvent.VK_RIGHT)
        dx = 0;
    if (key == KeyEvent.VK_UP)
        {dy = 0;
        mainCharacterImageFacing = r.getImage();
        }

这是主游戏窗口中的一些代码,用于调用按键/释放键以及处理跳转。

private class AL extends KeyAdapter{
    public void keyReleased(KeyEvent e) {
        p.keyReleased(e);
    }

    public void keyPressed(KeyEvent e) {
        p.keyPressed(e);
    }
}

@Override
public void run() 
{
    long beforeTime;
    long timeDiff;
    long sleep;

    beforeTime = System.currentTimeMillis();
    while(done == false)
    {
        cycle();
        timeDiff = System.currentTimeMillis() - beforeTime;
        sleep = 10 - timeDiff;
        if (sleep < 0 )
            sleep = 2;
        try {
            Thread.sleep(sleep);
        } catch (Exception e)
        {}
        beforeTime = System.currentTimeMillis();
    }
    done = false;
    h = false;
    k = false;
}

boolean h = false;
boolean done = false;   
public void cycle() {
    if (h == false)
        v = v - 2; //jump speed falling
    if (v == 350) //max y value of jump.  Lower numbers = higher jumps
        h = true;
    if (h == true && v <= 470) //starting y value
        {
        v = v + 2; //jump speed rising
        if (v == 470)
            done = true;
    }

}

2 个答案:

答案 0 :(得分:2)

不要直接在AL类中处理您的动作。相反,使用布尔值并相应地将它们设置为true / false:

private class AL extends KeyAdapter{
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            left = true;
        }

        if (key == KeyEvent.VK_RIGHT) {
            right = true
        } 

        if (key == KeyEvent.VK_UP) {
            //...
        }

    }

    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT)
            left = false
        if (key == KeyEvent.VK_RIGHT)
            right = false
        if (key == KeyEvent.VK_UP)
            //...
        }
    }

原因是因为在操作键时会调用keyPressed和keyReleased,但这意味着它不会与主循环同步。

移动精灵调用循环中的方法,如果条件为真,则相应地移动精灵,否则不执行任何操作。

编辑:在审核了您的代码后,我有一些建议。

首先,查看子像素渲染。子像素渲染用于使精灵的移动看起来更平滑。

要查找的另一件事是可变时间步(有时称为delta时间步长)。 Delta时间可用于确保操作与玩家fps同步执行。如果一个玩家有60fps而另一个玩家有30fps,那么30fps的玩家将看到以一半速度执行的动作。但是,使用delta时间步长,操作始终以相同的速度执行。 Here's a good article

第三件事是你的时间安排。目前您正在使用 System.getCurrentTimeMills 。这很糟糕,而且不准确。而是使用 System.nanoTime

我发现的第四件事是你的跳跃算法。更好的方法是加速。首先,你需要声明加速度的常数(0.1或0.2是好的)并计算垂直速度。然后,当垂直速度达到某个值时,您可以下降。这是一个小片段,但如果你有重力,你可能想要编辑它。首先,默认情况下将vSpeed设置为-8。

public void jump() {
    vSpeed += ACCELERATION;
    if(vSpeed < 8)
        dy += vSpeed;
    else
        vSpeed = -8;
        falling = false;
}

我只是把它写在了我的头顶,但基本上,因为向上移动会带走一个数字,当你加上负数时你似乎会跳跃,然后你会在它达到0时开始下降,然后降落再次达到8。

答案 1 :(得分:0)

问题在于操作系统处理关键事件并将其传递给应用程序的方式。当您按某个键时,它会触发一个事件。然后根据您的重复设置,它会在一段时间后以一定的频率再次按下该键。 (键入时可以看到这一点。按一个键,然后按住它)。

当您按另一个键时,它会停止另一个键的重复触发。您也可以在打字时看到这一点。按住一个键,然后开始另一个键。正如您所料,原始键会停止。

这甚至不会与每个操作系统保持一致,人们可以通过在键盘上更快地重复计时器来欺骗你的游戏。

由于这些原因,在关键监听器中进行动画是一个非常糟糕的主意。你应该将设置标志设置为true / false并在游戏循环中读取它们。 (如@ Troubleshoot的回答所示)。