Understanding outdated Libgdx code - android

Am trying to understand the following piece of code. According to the author,
he is trying to reset the camera position based on the gutter width and height. By gutter, I take it the author means the black bars on the screen.
The problem is that I cant seem to find the methods
setViewport(int,int,boolean) and getGutterWidth() and getGutterHeight() on the Stage class. I think this code was written with an outdated Libgdx API. What am looking for is the equivalent code that will perform the same task as this outdated code:
private Stage stage;
public void resize(int width, int height){
stage.setViewport(MyGame.WIDTH, MyGame.HEIGHT, true);
stage.getCamera().translate(-stage.getGutterWidth(),
-stage.getGutterHeight(), 0);}

These black bars are now handled by the viewport classes, see https://github.com/libgdx/libgdx/wiki/Viewports for a overview and short description.
In our case I would suggest a FitViewport:
Viewport viewport = FitViewport(MyGame.WIDTH, MyGame.HEIGHT, camera);
Stage stage = new Stage(viewport);

Related

Android: How to use a VirtualDisplay to host a WebView in a WallpaperService?

Background
I have a web-based animation that I've turned into an Android app with live wallpaper:
http://pixfabrik.com/livingworlds/
I've done so by creating a WebView and periodically copying its contents to the WallpaperService's Surface. Here's the code for that:
https://gist.github.com/iangilman/71650d46384a2d4ae6387f2d4087cc37
… And here's how I got to that solution:
Android: Use WebView for WallpaperService
That's been working great for the last four months, but WebView 76 broke the live wallpaper by introducing this bug:
https://bugs.chromium.org/p/chromium/issues/detail?id=991078
The bug is being worked on, so I'm optimistic that WebView 77 (due to be released September 10), and will have it fixed, but it would be nice to fix my app sooner than that, if possible!
The Issue
In the bug report above, one of the Chromium developers suggested using VirtualDisplay to connect the WebView to the WallpaperService instead, so now I'm pursuing that. I'm relatively new to Android, so I'm doing it naïvely, and so far it's not working. I'm writing here seeking help!
Here's what I currently have (in my Engine's OnSurfaceChanged (so I can take advantage of the width/height it gives me)):
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
DisplayManager mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
int density = DisplayMetrics.DENSITY_DEFAULT;
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay("MyVirtualDisplay",
width, height, density, holder.getSurface(), flags);
Presentation myPresentation = new Presentation(myContext, virtualDisplay.getDisplay());
WebView myWebView = new WebView(myPresentation.getContext());
myWebView.loadUrl("file:///android_asset/index.html");
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams (width, height);
myPresentation.setContentView(myWebView, params);
}
I'm using a Presentation to connect the VirtualDisplay to the WebView (on the recommendation of the Chromium developer), but I don't know for sure if that's the right way to go about it.
The WallpaperService runs, and I don't get any errors, but I also don't see my webpage; it's just a white screen.
Hopefully I'm just doing something dumb… Please enlighten me! :-)
You must call the show() method on your Presentation object otherwise it won't be displayed to the Virtual Display.

libgdx, several stages in one screen

I use two stages in one screen. One - for game actors, another - for control buttons and so on. I use FitViewport for game stage.
What function "resize" should I use? Something like this:
public void resize(int width, int height) {
FitViewport vpC = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
stageC.setViewport(vpC);
stageC.getViewport().update(width, height, true);
FitViewport vpG = new FitViewport(MyWorld.WIDTH, MyWorld.HEIGHT);
stageG.setViewport(vpG);
stageG.getViewport().update(width, height, true);
}
doesn't give correct result.
Actors distorted or buttons don't have right coordinates. That depends on what viewport I place first in func resize - vpC or vpG.
What correct method should I use?
Please read the Viewports wiki article once more. Especially the "Usage" part.
You are not supposed to create new viewports on every resize event. This pretty much destroys the functionality of the viewport. Furthermore the way you are currently using the FitViewport for vpC (please start to use better variable names), it should behave like a ScreenViewport. FitViewport has a "virtual resolution" which you define once. Then on resize events, when updating the viewport, it will scale this virtual viewport to fit the screen, while maintaining the aspect ratio. (maybe causing black bars).
The last flag of the Viewport.update(...) method should also only be true in case of UI. You do not want the camera to be centered in case of a "game" Stage.
public void show() {
stageC = new Stage(new ScreenViewport());
stageG = new Stage(new FitViewport(MyWorld.WIDTH, MyWorld.HEIGHT));
}
public void resize(int width, int height) {
stageC.getViewport().update(width, height, true);
stageG.getViewport().update(width, height, false);
}
However there is one more problem. Since you are using two different viewport scaling strategies for your stages, you need to "activate" them individually before rendering. This can be avoided by using the same FitViewport for both stages (easiest solution, probably what you want anyway).
public void render(float deltaTime) {
// this will "activate" the viewport
stageC.getViewport().apply();
stageC.act();
stageC.draw();
// now switch the viewport and activate the other one
stageG.getViewport().apply();
stageG.act();
stageG.draw();
}

How to create an Android 2D game?

I'm an dev still learning in Android, I've created two apps so far, an alarm clock, a widget and a pass manager using databases, I have a little bit of experience, but I'd like to create a 2D side scroller game, I check on the web and there are different tutorials, but, what's the best way to start working on it? I've read about libgdx but I'm not sure if it's outdated.
I've seen that all the games are made in Java, and then ported to Android, is this correct? I would appreciate some guidance, thanks!
You have multiple options, you can either go for AndEngine (which to me seemed extremely underdocumented and random), make your own "native" Android game with extending from a SurfaceView (which isn't impossible but it certainly doesn't make your life easy, especially when handling images and especially sound, but here's a setup for it: Using a custom SurfaceView and thread for Android game programming (example)), and there's LibGDX.
I personally recommend LibGDX, I even made a fairly simple 4-player multiplayer game in it and it certainly was not difficult. I'd recommend the following tutorial on how to get to it: http://www.gamefromscratch.com/page/LibGDX-Tutorial-series.aspx
And the basics are the following:
When you create a project, the first thing you want to do is change the ApplicationAdapter to Game so you'll have access to the setScreen(Screen) delegation function, so that you can seperate the display and logic of your game into Screens.
You want to handle elapsed time in your Screen, which is done as the following: How to track time in Libgdx(android)
You probably want to make a menu, which of course can be done with pretty pictures and BitmapFonts, but I'll point you to the official wiki ( https://github.com/libgdx/libgdx/wiki ) with that. You can use Scene2D, although I found it slightly difficult, so I personally made a menu made of rectangles, it worked fairly well: LibGDX - Custom Click Listener?
A bit more "click oriented" guide on how I handled touch events using LibGDX: https://stackoverflow.com/a/24511980/2413303
Afterwards, it's literally just implementing game logic, timers, data models, behavior.
The way I solved the stretching rather than using a StretchingViewport or the in-built cameras was the following:
public class Resources
{
public static Texture texture;
public static SpriteBatch batch;
public static Matrix4 normalProjection;
public static BitmapFont bitmapFont;
public static ShapeRenderer shapeRenderer;
....
}
public static void initialize()
{
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
Resources.bitmapFont = new BitmapFont();
Resources.shapeRenderer = new ShapeRenderer();
Gdx.gl.glLineWidth((width < 640 && height < 480) ? 2.5f : 6f);
//camera = new OrthographicCamera(1, h / w); //I didn't use this at all
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
loadTextures();
Resources.batch = new SpriteBatch();
Resources.normalProjection = new Matrix4().setToOrtho2D(0, 0, 480, 320); //model is 480x320
Resources.batch.setProjectionMatrix(Resources.normalProjection);
Resources.shapeRenderer.setProjectionMatrix(Resources.normalProjection);
}
public class InputTransform
{
private static int appWidth = 480;
private static int appHeight = 320;
public static float getCursorToModelX(int screenX, int cursorX)
{
return (((float)cursorX) * appWidth) / ((float)screenX);
}
public static float getCursorToModelY(int screenY, int cursorY)
{
return ((float)(screenY - cursorY)) * appHeight / ((float)screenY) ;
}
}
Make sure to dispose resources that need disposing, in the Game's dispose() callback.
Libgdx is not outdated and is, IMHO, the best way to program for android. The reason ist, that you can develop 99% on desktop (ofc think about the controlls, which won't be a keyboard on android) and then you have a working android app with a few lines only.
If you instead develop for android directly, you need to use the verry slow emulator or you have to send the app to a testphone, just to debug your code. This is a lot slower then debuging on desktop directly.
Libgdx is verry efficient, easy to use (as soon as you understan how it works) and has a verry good documentation.
For tutorials: I wrote an answer here on SO, which seemed to help some people. It is a short "tutorial" which shows only the verry basics and i have added the links to some tutorials which helped me learning it. So i hope it helps you to^^

android - set starting point to top left on libgdx

i want to use libgdx as a solution to scaling of apps based on screens aspect ratio.
i've found this link , and i find it really useful:
http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
i'm quite rusty with opengl (haven't written for it in years) and i wish to use the example on this link so that it would be easy to put images and shapes .
sadly , the starting point is in the middle . i want to use it like on many other platforms - top left corner should be (0,0) , and bottom right corner should be (targetWidth-1,targetHeight-1) ,
from what i remember, i need to move(translate) and rotate the camera in order to achieve it , but i'm not sure .
here's my modified code of the link's example for the onCreate method:
#Override
public void create()
{
camera=new OrthographicCamera(VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
// camera.translate(VIRTUAL_WIDTH/2,VIRTUAL_HEIGHT/2,0);
// camera.rotate(90,0,0,1);
camera.update();
//
font=new BitmapFont(Gdx.files.internal("data/fonts.fnt"),false);
font.setColor(Color.RED);
//
screenQuad=new Mesh(true,4,4,new VertexAttribute(Usage.Position,3,"attr_position"),new VertexAttribute(Usage.ColorPacked,4,"attr_color"));
Point bottomLeft=new Point(0,0);
Point topRight=new Point(VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
screenQuad.setVertices(new float[] {//
bottomLeft.x,bottomLeft.y,0f,Color.toFloatBits(255,0,0,255),//
topRight.x,bottomLeft.y,0f,Color.toFloatBits(255,255,0,255),//
bottomLeft.x,topRight.y,0f,Color.toFloatBits(0,255,0,255),//
topRight.x,topRight.y,0f,Color.toFloatBits(0,0,255,255)});
screenQuad.setIndices(new short[] {0,1,2,3});
//
bottomLeft=new Point(VIRTUAL_WIDTH/2-50,VIRTUAL_HEIGHT/2-50);
topRight=new Point(VIRTUAL_WIDTH/2+50,VIRTUAL_HEIGHT/2+50);
quad=new Mesh(true,4,4,new VertexAttribute(Usage.Position,3,"attr_position"),new VertexAttribute(Usage.ColorPacked,4,"attr_color"));
quad.setVertices(new float[] {//
bottomLeft.x,bottomLeft.y,0f,Color.toFloatBits(255,0,0,255),//
topRight.x,bottomLeft.y,0f,Color.toFloatBits(255,255,0,255),//
bottomLeft.x,topRight.y,0f,Color.toFloatBits(0,255,0,255),//
topRight.x,topRight.y,0f,Color.toFloatBits(0,0,255,255)});
quad.setIndices(new short[] {0,1,2,3});
//
texture=new Texture(Gdx.files.internal(IMAGE_FILE));
spriteBatch=new SpriteBatch();
spriteBatch.getProjectionMatrix().setToOrtho2D(0,0,VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
}
so far , i've succeeded to use this code in order to use scaled coordinates , and still keep aspect ratio (which is great) , but i didn't succeed in moving the starting point (0,0) to the top left corner .
please help me .
EDIT: ok , after some testing , i've found out that the reason for it not working is that i use the spriteBatch . i think it ignores the camera . this code occurs in the render part. no matter what i do to the camera , it will still show the same results.
#Override
public void render()
{
if(Gdx.input.isKeyPressed(Keys.ESCAPE)||Gdx.input.justTouched())
Gdx.app.exit();
// 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);
//
final String msg="test";
final TextBounds textBounds=font.getBounds(msg);
spriteBatch.begin();
screenQuad.render(GL10.GL_TRIANGLE_STRIP,0,4);
quad.render(GL10.GL_TRIANGLE_STRIP,0,4);
Gdx.graphics.getGL10().glEnable(GL10.GL_TEXTURE_2D);
spriteBatch.draw(texture,0,0,texture.getWidth(),texture.getHeight(),0,0,texture.getWidth(),texture.getHeight(),false,false);
spriteBatch.draw(texture,0,VIRTUAL_HEIGHT-texture.getHeight(),texture.getWidth(),texture.getHeight(),0,0,texture.getWidth(),texture.getHeight(),false,false);
font.draw(spriteBatch,msg,VIRTUAL_WIDTH-textBounds.width,VIRTUAL_HEIGHT);
spriteBatch.end();
}
These lines:
camera.translate(VIRTUAL_WIDTH/2,VIRTUAL_HEIGHT/2,0);
camera.rotate(90,0,0,1);
should move the camera such that it does what you want. However, my code has an additional:
camera.update()
call after it calls translate, and it looks like you're missing that. The doc for Camera.update says:
update
public abstract void update()
Recalculates the projection and view matrix of this camera and the Frustum planes. Use this after you've manipulated any of the attributes of the camera.

Obtaining SurfaceView dimensions

I think I might be about to ask a dummy question, but I'm still new with Android programming, and I couldn't (despite all my efforts) find my answer on Google.
The thing is, I'm trying to develop a little game, with 2D Graphics. I want my "gaming board" to be at a specific position on my screen, so that I can display in-game informations above and below the box. But since there is beginning to be a lot of Android phones out there, I was thinking about getting "dynamic" values so that I can adapt my font size to every device.
My game is not in full screen (but it could be, it's no big deal), but in a window with no title bar.
I'm using an extension of the default SurfaceView class, implementing SurfaceHolder.Callback. I tried writing the following method :
public void getViewSize()
{
VIEW_WIDTH = this.getWidth();
VIEW_HEIGHT = this.getHeight();
}
but the values returned are zeroes.
Anyone got an idea (even if it means changing display strategy) ?
Thanks a lot.
You can do this:
public void onDraw(Canvas canvas) {
VIEW_WIDTH = canvas.getWidth();
VIEW_HEIGHT = canvas.getHeight();
}

Categories

Resources