如何处理libGDX中的不同长宽比?
我已经使用libGDX实现了一些屏幕,显然会使用libGDX框架提供的Screen
类。 但是,这些屏幕的实现只适用于预定义的屏幕大小。 例如,如果精灵用于640 x 480大小的屏幕(4:3纵横比),则其在其他屏幕大小上不会如预期的那样工作,因为精灵将在屏幕边界上移动并且不缩放到屏幕大小在所有。 而且,如果libGDX提供了简单的缩放比例,那么我所面临的问题将会一直存在,因为这会导致游戏画面的高宽比发生变化。
经过在互联网上的研究,我遇到了一个博客/论坛讨论过同样的问题。 我已经实现了,到目前为止它工作正常。 但是我想确认这是否是实现这一目标的最佳select,或者是否有更好的select。 以下是显示我如何处理这个合法问题的代码。
论坛链接: http : //www.java-gaming.org/index.php? topic=25685.new
public class SplashScreen implements Screen { // Aspect Ratio maintenance private static final int VIRTUAL_WIDTH = 640; private static final int VIRTUAL_HEIGHT = 480; private static final float ASPECT_RATIO = (float) VIRTUAL_WIDTH / (float) VIRTUAL_HEIGHT; private Camera camera; private Rectangle viewport; // ------end------ MainGame TempMainGame; public Texture splashScreen; public TextureRegion splashScreenRegion; public SpriteBatch splashScreenSprite; public SplashScreen(MainGame maingame) { TempMainGame = maingame; } @Override public void dispose() { splashScreenSprite.dispose(); splashScreen.dispose(); } @Override public void render(float arg0) { //----Aspect Ratio maintenance // update camera camera.update(); camera.apply(Gdx.gl10); // set viewport Gdx.gl.glViewport((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height); // clear previous frame Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // DRAW EVERYTHING //--maintenance end-- splashScreenSprite.begin(); splashScreenSprite.disableBlending(); splashScreenSprite.draw(splashScreenRegion, 0, 0); splashScreenSprite.end(); } @Override public void resize(int width, int height) { //--Aspect Ratio Maintenance-- // calculate new viewport float aspectRatio = (float)width/(float)height; float scale = 1f; Vector2 crop = new Vector2(0f, 0f); if(aspectRatio > ASPECT_RATIO) { scale = (float) height / (float) VIRTUAL_HEIGHT; crop.x = (width - VIRTUAL_WIDTH * scale) / 2f; } else if(aspectRatio < ASPECT_RATIO) { scale = (float) width / (float) VIRTUAL_WIDTH; crop.y = (height - VIRTUAL_HEIGHT * scale) / 2f; } else { scale = (float) width / (float) VIRTUAL_WIDTH; } float w = (float) VIRTUAL_WIDTH * scale; float h = (float) VIRTUAL_HEIGHT * scale; viewport = new Rectangle(crop.x, crop.y, w, h); //Maintenance ends here-- } @Override public void show() { camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); //Aspect Ratio Maintenance splashScreen = new Texture(Gdx.files.internal("images/splashScreen.png")); splashScreenRegion = new TextureRegion(splashScreen, 0, 0, 640, 480); splashScreenSprite = new SpriteBatch(); if(Assets.load()) { this.dispose(); TempMainGame.setScreen(TempMainGame.mainmenu); } } }
更新:我最近知道,libGDX有一些自己的function来维持纵横比,我想在这里讨论。 在search互联网上的宽高比问题时,我遇到了几个论坛/开发者,他们遇到了“如何在不同屏幕尺寸上保持宽高比的问题? 其中一个真正为我工作的解决scheme已在上面发布。
后来,当我继续为屏幕实现touchDown()
方法时,我发现由于缩放resize,我实现了touchDown()
的坐标会发生很大的变化。 在根据屏幕大小调整一些代码来翻译坐标之后,我在很大程度上减less了这个数量,但是我没有成功地保持它们的精确度。 例如,如果我已经在纹理上实现了touchDown()
,调整屏幕的大小会使纹理区域上的touchListener向右或向左移动一些像素,具体取决于resize,这显然是不希望的。
后来我才知道舞台类拥有自己的本地function来保持宽高比( boolean stretch = false
)。 现在我已经使用舞台类实现了我的屏幕,高宽比保持良好。 但是,在resize或不同的屏幕尺寸时,生成的黑色区域总是出现在屏幕的右侧; 那就是屏幕没有居中,如果黑色区域相当大,就会使屏幕变得非常难看。
任何社区成员能帮我解决这个问题吗?
如何做到现在:
由于这是libgdx中最着名的问题之一,所以我稍微更新一下:
LibGDX v1.0引入了Viewport
来处理这个问题。 它使用起来更容易,扩展策略是可插入的,这意味着一行可以改变行为,你可以玩它,看看哪一个最适合你的游戏。
你需要知道的一切可以在这里find。
编辑: libGDX已经演变。 现在最好的答案是用户noone。 一定要检查到Viewport
文档的链接。 。
正如史蒂夫·布莱克(SteveBlack)在舞台课上发布的那个问题的链接,我去了那里发现这个问题(这实际上不是我的问题)在最近的晚上已经解决了。
经过在互联网上对这个问题的研究,我找不到任何解决scheme,因此决定直接联系报告错误的人。 之后,他在libgdx论坛上回复我,感谢他的帮助。 链接在这里
这是一行代码,你所要做的就是:
在resize()方法中:
stage.setViewport(640, 480, false); stage.getCamera().position.set(640/2, 480/2, 0);
其中640 X 480是您的纹理区域的分辨率,描述了预期的高宽比。 如果你的TextureRegion的大小是320×240,那么这两个参数应该改变成新的分辨率来完成这个技巧。
实际上解决了我的问题的原始个人资料链接
左/右或上/下的黑条看起来比扭曲整个场景以适应屏幕更好。 如果您的目标宽高比在可能范围的中间(4:3可能是低端,16:9可能是高端),那么对于大多数设备来说,条形应该保持较小。 这也让你使用大部分的屏幕,甚至在更大的屏幕上,你已经有了这个家伙的代码,所以这很容易。 如果这只是libgdx中的一个选项,那更好。
但是,我认为最好的方法是使用整个屏幕。 我还没有这样做,但这将是我为下一个项目所采取的方法。 这个想法是,如果有人有更宽的屏幕,那么他们应该看到更多的双方。 克里斯·普鲁特(Chris Pruett)在他的一次会谈中谈到了如何做到这一点( 链接现场谈话 -事实上,整个事情实际上是相当不错的)。 这个想法是为了缩放高度,然后将视口设置得足够宽以适合屏幕。 OpenGL应该照顾其余的显示。 他这样做的方式在这里 。
对于libgdx,也许有一个简单的方法,通过在舞台上移动摄像头来实现这一点,但我从来没有真正使用过scene2d。 在任何情况下,运行应用程序作为一个本地可resize的窗口是testing多个屏幕尺寸比创build一堆AVD更容易的方法。
请参阅官方文档中“视口”部分的最后部分: https : //code.google.com/p/libgdx/wiki/scene2d#Viewport
ResolutionFileResolver类允许您将文件名parsing为最佳分辨率。 我相信,如果您已经创build了这些纵横比的精灵,那么也可以使用不同的纵横比。 在AssetManagerTest中有一个示例用法。
我使用的方法从http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
我做了这个function,返回触摸屏幕上的点,缩小到你想要的游戏位置。
public Vector2 getScaledPos(float x, float y) { float yR = viewport.height / (y - viewport.y); y = CAMERA_HEIGHT / yR; float xR = viewport.width / (x - viewport.x); x = CAMERA_WIDTH / xR; return new Vector2(x, CAMERA_HEIGHT - y); }
在触地/向上/拖动中使用此function,您可以检查游戏中的触摸。
这个代码适用于我的最新更新:* OrthographicCamera是凸轮,这不会裁剪,只是改变视口,所以宽度仍然是实际窗口/设备的“许多”倍
public void resize(int width, int height) { int newW = width, newH = height; if (cam.viewportWidth > width) { float scale = (float) cam.viewportWidth / (float) width; newW *= scale; newH *= scale; } // true here to flip the Y-axis cam.setToOrtho(true, newW, newH); }