LibGdx过多的FPS,如何限制?

7
我正在制作一款游戏,但在某些低端安卓设备(Galaxy S mini、Galaxy ACE)上出现了问题,这些设备硬件实际上很差。这两个设备的FPS都超过85,在其他设备上(HTC Desire、Sony Xperia Arc S、Samsung Galaxy S、HTC Wildfire)FPS是“正常”的(大约60FPS)。在电脑上也显示为60 FPS。显然,85+ FPS太多了,因为游戏体验不同,可能会给那些在85 FPS+上玩的玩家带来不公平的优势。
我想将FPS限制在最多60。
我已经搜索了这个论坛,并找到了与我现在提出的确切问题相同的问题。Limit FPS in Libgdx game with Thread.sleep() doesn't work 用户@daniel提出的解决方案是:
Thread.sleep((long)(1000/30-Gdx.graphics.getDeltaTime()));

但问题是这对我不起作用。如果我使用该代码(30替换为60),我会得到30-33 FPS,或者如果我只使用Daniel的代码,我会得到大约15-17 FPS。为什么会这样,为什么对我不起作用?如何将所有设备上的FPS限制为最大60?我已在计算机和设备上测试了此代码。
非常感谢任何帮助。谢谢。

1
你是如何测量FPS的?你是在渲染方法的开始和结束时自己计时每一帧,还是将一帧与下一帧进行比较? - Tenfour04
1
我非常怀疑更高的FPS会带来“优势”......作为一个支持“PC游戏大师种族”理念的人,限制FPS是我最讨厌的事情。FPS只应影响游戏的流畅度,不应对其他方面产生影响。如果有人认为85FPS比60FPS更具“优势”,那么为什么60FPS不是对硬件提供30FPS的优势呢?这肯定意味着你必须将FPS限制在10以下才能“公平”。除非FPS与游戏速度本身绑定(例如单位移动速度=每帧3像素等),否则不应限制FPS,这是一种极其糟糕的设计。 - Jacky Cheng
话虽如此,你的FPS似乎只有目标值的一半?也许将睡眠方程中的值更改为120会给你60FPS?另外,我注意到你说“低端”硬件提供85FPS,“高端”设备提供60FPS?你确定你看的是FPS而不是delta时间吗?delta时间意味着两个帧更新之间的时间,60FPS将给您16.6毫秒的delta时间。 - Jacky Cheng
最后但同样重要的是,非常小心你正在使用的睡眠方法,有很高的几率会导致该方程返回负值并崩溃你的程序。 - Jacky Cheng
1
显然,85+ FPS 太多了,因为游戏体验是不同的。这一点根本不明显。你永远不能假设 FPS 是恒定的。例如,总会有低于 60FPS 的设备。你必须通过乘以帧时间来规范化你的游戏玩法,以在所有设备上获得恒定的行为。 - noone
显示剩余4条评论
5个回答

12

在你的启动器类中;

AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.foregroundFPS = 60;
initialize(new MyGdxGame(), config);

我不知道这是一个新功能还是一个旧功能。在尝试使线程睡眠之前,请使用此功能。

我强烈建议不要通过让线程睡眠来限制帧数,以使所有运行速度快或慢的设备保持相同的运动速度。请使用类似于此的东西来移动屏幕上的物体。

x+= speed*Gdx.graphics.getDeltaTime();

祝你在使用libGDX的冒险中好运,看起来你刚刚开始。因为当我刚开始时,我也问了同样的问题 :)


编辑:这是一条提示:

如果在您的游戏中有碰撞,并且用户通过拖动窗口等方式使游戏睡眠,则Gdx.graphics.getDeltaTime()函数将返回一个意料之外的高值。例如,你可能期望它返回16毫秒(60fps),但实际上却返回了2秒。在这种情况下,您的角色将跳过墙壁,碰撞检测将失败。所以以下是你可以做的:

  1. 您可以覆盖该函数并取最后10帧的平均值并返回该值(在某些情况下有一些缺陷,但在其他情况下更好)。
  2. 如果该值大于30秒,则可以返回30毫秒。这样,即使玩家让它睡眠一个世纪,角色也不会跳跃、穿过墙壁等。
  3. 结合两者。(最佳)在取平均值时,不要计算超过30毫秒的值。

我在我的网站教程部分写了一页关于这个主题的内容。去看看吧。 nightlybuilddigital.ga


7

您不想这样做。

您需要将游戏开发为适用于任何手机的版本。

如果您有类似以下代码:

player.x+=10f;

你的玩家在更好的设备上会移动得更快。 你需要按照增量时间值来移动你的玩家。

player.x+=Gdx.graphics.getDeltaTime()*300; // this would be ~5f if your device is running with 60 fps

为什么是5f?它将恰好为+300/s。 - noone
1
这种方法对我很有效。我将2.15f(平台速度)* deltaTime * 50相乘。在60 FPS设备上,平台速度约为1.4-1.8,但在85FPS+设备上,平台速度降至1.1-1.4f。这对我来说有点奏效,因为所有平台在所有设备上都以相同的速度(视觉上)移动。但我很好奇这是否是正确的方法?但我仍然认为这比我首先想到的方法(限制游戏的FPS)要好。我会让这个答案保持开放状态一段时间,如果没有人能提供更好的答案或确认这是否是正确的方法,我会接受这个答案。 - rootpanthera
@Paul 啊,你的意思是每帧变化5,而不是每秒变化5。好的,没问题,那就对了。 :) - noone
@rootpanthera 当使用Box2D时,你不应该这样做。速度已经是以m/s为单位的。可能你正在错误地执行World.step(),否则Box2D会自行规范化速度。 - noone
在最简单的实现中,这是错误的。你在那里定义了一个恒定的时间步长(1/60)。这意味着你还必须每秒精确地调用 World.step(...) 60 次。由于你可能在每一帧中都会调用它,这取决于设备的帧速率。如果设备只有30FPS,那么你每秒只会将世界推进30次,这意味着它只会被处理0.5秒而不是预期的1秒。尝试使用 TIME_STEP = deltaTime,或者查看 http://stackoverflow.com/questions/20848442/libgdx-speeding-up-a-whole-game-using-box2d 获取最佳方法 :) - noone
显示剩余2条评论

3

为什么要暂停线程,当你可以简单地跟踪delta时间并在太早时省略绘制/更新呢?当时间太早时,你可以通过跳过渲染和逻辑更新来以编程方式限制FPS。

试试这样的代码:

private static final float MIN_FRAME_LENGTH = 1f/60f;
private float timeSinceLastRender;

/** @param delta time since the last render call. */
public void render(float delta) {
      timeSinceLastRender += delta;
      if (timeSinceLastRender >= MIN_FRAME_LENGTH) {
           // Do the actual rendering, pass timeSinceLastRender as delta time.
           timeSinceLastRender = 0f;
      }
}

如果你的游戏运行在每秒67帧(15毫秒间隔)而不是60帧(16.6毫秒间隔),那么每次渲染之间将会经过30毫秒,游戏将以33帧的速度运行。即使是让线程休眠也比这个选项更好。 - ossobuko
使用1f/120f,渲染线程将以120fps运行逻辑,但只绘制60fps。 - Michael N

2

就像其他人所说的那样,如果您正确编写游戏代码,则更高的fps不应该有任何影响。在这里查看文章,以获得更好的方法。虽然它无法直接翻译为libgdx,但其中的概念都是正确的。


0

试试这个c:

 if (dt < (1f / max_frames)) {

        float sleepTime = (1f / max_frames) - dt;
        try {
            Thread.sleep((long) sleepTime);
        } catch (InterruptedException ex) {
            LogTool.logError(ex.getLocalizedMessage());
            ex.printStackTrace();
        }
    }

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