在Ubuntu上,使用Java和libGDX/LWJGL制作的游戏在多个显示器上全屏时大小不正确。

35

我正在开发一个基于LWJGL的libGDX游戏项目,并且在多个工作站上使用Intellij IDEA IDE:

  • Windows 7 x64笔记本电脑,有两个显示器(1920x1080和1600x1200),nVidia GT540M。
  • Ubuntu 12.04 LTS笔记本电脑,只有一个显示器(1366x768),Intel集成显卡。
  • Ubuntu 12.04 LTS桌面电脑,有两个显示器(1920x1080和1280x1024),nVidia GTS 450。

我在Ubuntu上使用OpenJDK for Java 6,在Windows上使用Sun/Oracle Java 6(据说Java 6是为了兼容Android而使用的)。

全屏运行时:

  • Windows 7笔记本电脑:正常运行。
  • Ubuntu笔记本电脑:正常运行。
  • Ubuntu桌面电脑:背景图像被放大显示,只有一部分适合屏幕大小。

进一步研究后,我发现调用Gdx.graphics.getHeight()和Gdx.graphics.getWidth()返回需要覆盖两个显示器的矩形的大小(在我的情况下是3200x1080),但当我告诉我的游戏全屏运行时,它只使用一个显示器,所以相机被设置为1920x1080,但我的相机移动和Tiled地图平移认为它们有3200x1080来工作,导致图像失真和无法使用(因为角色可以走到右边屏幕之外)。

我猜我的问题实际上来自于awt.Toolkit的getScreenSize()调用返回的大小,但我不知道如何更深入地询问它,以获取全屏时实际使用的屏幕大小。

我的DesktopStarter获得屏幕大小并设置全屏如下:

    LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
    Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
    cfg.width = screenDimension.width;
    cfg.height = screenDimension.height;
    cfg.fullscreen = true;
    new LwjglApplication(new Game1(), cfg);

有没有一种方法来获取仅“全屏”将实际启动的显示器的高度/宽度?
我遇到的问题是,执行game.jar文件,退出游戏,然后再次执行,反复多次,会导致在Gdx.graphics.getDisplayModes()返回的模式列表中出现不同的显示模式 - 正如P.T.在下面指出的那样,这是对LWJGL的Display.getAvailableDisplayModes()的简单封装。为什么会发生这种情况?为什么Ubuntu上每次运行时呈现的模式集合都不同?
编辑:根据P.T.的建议,在问题中放置LWJGL参考,因为似乎是LWJGL提供了显示模式列表。
谢谢!

1
Gdx.graphics.getDisplayModes() 返回的结果更加一致和有用吗?(这有点像鸡生蛋,因为您必须在查询之前初始化libgdx。) - P.T.
@P.T. 谢谢!虽然它只是返回由JRE与硬件接口报告的所有支持的显示模式列表,但这个提示对我很有用。我在我的Game.Create()中设置了一个循环来遍历所有模式,选择最高分辨率(最高到1920x1200),然后选择该分辨率下刷新率最高的模式。这将选择一个可玩的默认值,除非使用两个(或更多)极低分辨率的监视器(它们的宽度加起来小于1920)。把它作为答案添加上去,我会标记它 - 除非有更好的方法出现。 ;) - Shad
实际上,经过进一步的尝试,我发现在我的Ubuntu工作站上,Gdx.graphics.getDisplayModes() 是不稳定的。它报告了43种模式中,很多时候都没有列出1920x1080。但有时,它会列出几个不同的刷新率?令人沮丧。 - Shad
1
虽然不是编程答案,但这是大多数Linux游戏和多个显示器的持续问题之一。这也是为什么像Wayland这样的X替代品正在被研究的原因之一。请提供一种在命令行或配置文件中覆盖分辨率检测的方法,以确保Linux多显示器用户可以玩您的游戏 :) - Torp
@Torp:感谢您的评论。是的,我在网络上找到了类似的信息,更重要的是,我发现了很多应用程序在我的多显示器Ubuntu设置上表现不佳。目前,我已经切换回使用Windows作为我的开发机(我能够重新使用之前安装Ubuntu之前该计算机上的许可证)。我仍然会通过我的i5笔记本电脑在Ubuntu上进行测试,但不想在我的开发工作站上每天都处理它。我将保留我的命令行处理方式以选择分辨率,以防万一... - Shad
显示剩余2条评论
8个回答

1
GraphicsDevice monitors[]=GraphicsEnvironment.getScreenDevices(); 

Dimension screen_resolution[monitors.length];

for (int monitorID = 0; monitorID < monitors.length; monitorID++)
{
    screen_resolution[monitorID] = new Dimension(monitors[monitorID].getDisplyMode().getWidth(),monitors[monitorID].getDisplyMode().getHeight());
}

1

我建议避免使用Toolkit.getDefaultToolkit(),而是仅使用lwjgl.util.Display.getAvailableDisplayModes()libgdx描述的方法。

一旦您设置了全屏窗口,请获取其大小(如果您的设置方法还不知道该信息),并且从那时起只使用此信息。

如果Display.getAvailableDisplayModes()在不同的执行中更改了其排序顺序,则简单地重新对它们进行排序并使用可用的最大分辨率或使用标准分辨率并提供游戏内设置来更改它们。


0

我不确定,但它对我有用。只需在“开始”游戏后设置大小,就像以下代码中所示:

public static void main(String[] args) {
    LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
    cfg.title = "Palmeiras!!";
    cfg.vSyncEnabled = false;
    cfg.forceExit = true;
    cfg.allowSoftwareMode = true;
    new LwjglApplication(new Palmeiras(null), cfg);

    Gdx.graphics.setDisplayMode(Gdx.graphics.getDesktopDisplayMode().width,
            Gdx.graphics.getDesktopDisplayMode().height, true);
}

如果它对你有用,请让我知道。


0
你可以使用 javafx.stage.screen 来解决这个问题,但是如果你继续使用 Java 6,就需要添加 JavaFX;或者升级到 Java 7(Java 7 SDK 中已经包含了它)。
根据文档描述:
"描述了图形目标的特征,例如显示器。在虚拟设备多屏环境下,桌面区域可能跨越多个物理屏幕设备,“Screen” 对象的边界是相对于“Screen.primary”的。
例如: Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds(); // 将舞台边界设置为主屏幕的可见边界 stage.setX(primaryScreenBounds.getMinX()); stage.setY(primaryScreenBounds.getMinY()); stage.setWidth(primaryScreenBounds.getWidth()); stage.setHeight(primaryScreenBounds.getHeight()); stage.show();"
还有许多其他方法(如 getBounds(), getDpi(), getScreens() 等)也可能对你非常有用。

1
Harvath II -- 感谢您的回复。我会尝试在我的libGDX游戏中实现这些内容,但主要问题可能在于支持Android...我希望尽可能避免平台依赖。我会尝试并看看能做到什么。 - Shad

0

也许可以获取当前使用的显示器尺寸,以便在不同尺寸的显示器上获取尺寸。对于不同尺寸的显示器,您可能需要采取不同的措施。

也许背景图像因为它认为仍在其他屏幕上工作而被放大。

希望这能帮到您,如果不能祝好运。


0
我建议完全避免使用lwjgl。表面上看起来可能很简单,但是当你尝试添加更高级的功能时,你会意识到OpenGL的包装器不会给你那些功能,或者它会使程序变慢3倍。我建议转向c++和OpenGL(如果有这个选项)。你会惊讶于它的简单性。
否则,跨平台库通常会出现这些问题。要解决你的问题,你需要停止依赖库来确定你的视口分辨率。相反,枚举所有可能的显示模式,并根据你的需求选择最佳的一个。这将导致更明确定义的行为,并且比使用默认配置更容易调试。总的来说,你要确保知道你正在使用的数据。更糟糕的是,我刚刚注意到你正在使用一个包装器的包装器。这会使渲染过程变得过于复杂,并且会比你想象的更加缓慢(平均20倍)。

1
是的,每个包装器都会平均使所有东西变慢20倍。仅使用一个包装器会使其变慢3倍。这是事实。而且,包装器永远无法提供与被包装的内容相同的功能。只有C++才是唯一真正的语言,它非常简单,甚至3岁的孩子也可以用它制作游戏。-1 - noone
1
更不用说C++自动比Java更好、更快了!互联网上说的,所以我显然应该相信它!Christian,除非你有来源证实你那个极其不准确的问题,否则请不要试图混淆OP并给他无用的谎言。-1 - user1650305
我并不是说所有的包装器都很糟糕,但在这个特定的例子中,libGDX非常糟糕。举个例子,看看这个比较: - Darth Zaloj
我想要非常清楚地表明,我已经使用过OpenGL本地化、LWJGL和libGDX进行各种活动。由于其内存管理方式,LWJGL比C++慢得多。java.nio.Buffers可以缓解部分问题,但并非全部。试试在纯Java中快速创建交错顶点数据——这不是一件容易的事情,不是吗?至于libGDX……它对其绘图例程的控制很少(类似于XNA)。它决定放弃控制权,只是说:“给你一个包装好的LWJGL上下文句柄,随便你怎么用。” - Darth Zaloj
更不用说 C++ 自动比 Java 更好、更快了吧!Java 运行在使用 C++ 构建的 JVM 上。毫无争议,Java 永远比不上 C++ 的速度。这就好比说用 C++ 编写优化过的机器码程序得到执行一定会比编写 Java 程序更快一样。此外,如果你喜欢在这些网站上恶意发言(根据匿名用户名来判断),我强烈建议你停止这种行为。 - Darth Zaloj

0

-2

我建议避免使用Toolkit.getDefaultToolkit(),而是仅使用lwjgl.util.Display.getAvailableDisplayModes()或libgdx中描述的方法。

一旦设置了全屏窗口,请获取其大小(如果您的设置方法还不知道),并且从此时起只使用该信息。

如果Display.getAvailableDisplayModes()在不同执行中更改排序顺序,只需重新排序它们并使用最大的可用模式,或者使用标准模式,并提供游戏内设置来更改它们。


2
如果你要复制我的答案,请至少保留格式。 - cfstras

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