限制我的游戏FPS

3

好的,我正在制作一款小游戏,我需要限制FPS,因为当我在我的非常快的计算机上玩游戏时,我的FPS大约为850,游戏会变得非常快,当我切换到我的旧电脑时,游戏速度会变慢很多,所以我需要限制FPS来解决这个问题。如何限制FPS? 我的主要游戏循环:

    public void startGame(){
    initialize();
    while(true){
        drawScreen();
        drawBuffer();
        plyMove();

        //FPS counter
        now=System.currentTimeMillis(); 
        framesCount++; 
        if(now-framesTimer>1000){
            framesTimer=now; 
            framesCountAvg=framesCount; 
            framesCount=0; 
        }

        try{
            Thread.sleep(14);
        }catch(Exception ex){}
    }
}

我如何绘制屏幕以及绘制其他所有物品,比如玩家、球等等。顺便说一下,这个游戏是一个乒乓球的翻版。

    public void drawBuffer(){
    Graphics2D g = buffer.createGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0,0,600,500);
    g.setColor(Color.GREEN);
    g.fillRect(ply1.getX(),ply1.getY(),ply1.getWidth(),ply1.getHeight());
    g.setColor(Color.RED);
    g.fillRect(ply2.getX(),ply2.getY(),ply2.getWidth(),ply2.getHeight());
    g.setColor(Color.WHITE);
    g.fillOval(ball1.getX(),ball1.getY(),ball1.getWidth(),ball1.getHeight());
    g.drawString("" + framesCountAvg,10,10);
}

public void drawScreen(){
    Graphics2D g = (Graphics2D)this.getGraphics();
    g.drawImage(buffer,0,0,this);
    Toolkit.getDefaultToolkit().sync();
    g.dispose();
}

10
如果你的游戏速度取决于每秒帧数,那么整个设计就相当糟糕。 - Dr McKay
2
你可以通过让游戏代码实际上尊重经过的时间(例如,如果FPS高,则移动较少,如果FPS低,则移动更多)来代替限制FPS。这可以通过从实际帧到前一帧的System.nanoTime()差异来获得。 - Howard
这是 https://dev59.com/PHA75IYBdhLWcg3wy8Ui 的重复吗? - Michael McGowan
我看了那个,但那并没有完全解决我的问题,而且我不知道如何让它工作。 - Stan
6个回答

4

看起来你的显示器和游戏引擎有关联。请确保两者没有关联。无论帧率如何,您都希望游戏以相同的速度运行。如果您的快速计算机重新绘制屏幕速度更快,那么只要引擎使游戏以恒定的速度运行就可以了。


我有点困惑如何做到这一点。我创建了一个主游戏循环,我将把它放入 OP 中。 - Stan
@Stan,你的主游戏循环应该基于时间而不是循环进行移动/更改。 - jzd
如果我基于循环来实现,该怎么做呢?如果我移除Thread.sleep,它将达到约850FPS,而我不想要那样的速度。 - Stan
它基于一个循环。相反,根据时间进行更改。这样你的游戏引擎就可以比你的绘画更快/更慢地计算事物。 - jzd
更重要的是,您可能希望渲染发生在与游戏处理不同的线程中。游戏处理会为渲染产生内容,然后渲染引擎可以选择渲染多少或少量的数据。 - Stefan Kendall
如何实现jzd所描述的内容:http://gafferongames.com/game-physics/fix-your-timestep/ - Prof. Falken

2

不要限制你的FPS,而是使游戏在FPS高时不会运行得太快。

假设您有一些代码,每帧执行某些操作,例如:如果按下按钮,则向前移动角色。相反,您应该根据自上一帧以来经过的时间量向前移动角色。


1
如前所述,您需要在游戏的核心某处将显示循环与更新循环分开。可能有类似以下代码:
while (1)
{
    drawscene();
    update();
}

在更新中,您将时间提前了一个固定的量,例如0.17秒。如果您以恰好60fps绘制,则动画正在实时运行,而在850fps下,一切都会加速14倍(0.17 * 850)。为了防止这种情况发生,您应该使您的更新时间依赖于时间。例如:

elapsed = 0;
while (1)
{
   start = time();
   update(elapsed); 
   drawscene();
   sleep(sleeptime);
   end = time();

   elapsed = end - start;
}

这样效率非常低。更新应该异步进行,而不是与渲染同时发生。 - Stefan Kendall

0
我在评论中的意思是描述你的方法plyMove();内部可能有类似以下内容的代码。
plyMove() {
    ply1.x += amountX;
    ply1.y += amountY;
}

而是根据经过的时间来进行移动

plyMove(double timeElapsed) {
    ply1.x += amountX * timeElapsed;
    ply1.y += amountY * timeElapsed;
}

在主循环中计算时间差并按比例缩放,以获得良好的运动效果。

double timePrev = System.currentTimeMillis();
while(true) {
    double timeNow = System.currentTimeMillis();
    double elapsed = timeNow - timePrev;

    drawScreen();
    drawBuffer();
    plyMove(0.001 * elapsed);

    timePrev = timeNow;
}

0
如果你真的想要一个固定时间框架的游戏,你可以这样做:
float timer = 0;
float prevTime= System.currentTimeMillis();
while(true)
{
    draw();

    float currentTime = System.currentTimeMillis();
    timer += currentTime - prevTime;

    while (timer > UPDATE_TIME) // To make sure that it still works properly when drawing takes too long
    {
        timer -= UPDATE_TIME;
        update();
    }
}

UPDATE_TIME 是以毫秒为单位的更新间隔时间。


-3

一种方法是使用

try {
    Thread.sleep(20);
} catch(InterruptedException e) {}

在主循环结束时。根据您的需求调整数字。

3
这会减慢两台机器上的游戏速度。这不是原帖作者想要的。 - jzd
1
好的,这样可以解决游戏加速的问题,现在帧率是60,但是在我的其他速度较慢的电脑上它会运行得更慢吗? - Stan

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