Graphic problems with libgdx stage2d.ui - android

I'm playing with stage2d.ui...
Just creating an empty stage with only a button, and it happens this in android (screenshot directly from a Nexus5):
Also, it looks ok in desktop, but if you resize the screen, you can see the image of the button flickering at its previous position like this (image after making the window a bit more width):
I'm not sure if I'm doing something wrong or it's just a graphic issue...
For the button widget, I'm using the test data like this:
stage = new Stage(new ScreenViewport());
Skin skin = new Skin(Gdx.files.internal("uiskin.json"));
TextButton button = new TextButton("Button 1", skin);
button.setSize(100, 50);
button.setPosition(10, 10);
stage.addActor(button);
And then in the main render method, stage.act(delta) and stage.draw() are called, of course.
For the resize part... here's the code
public void resize(int width, int height) {
stage.getViewport().update(width, height);
}
I have other stages without ui widgets working fine, but this is my first time with ui and I'm not sure about what's happening here...

Moved from comment above.
My guess is you are not clearing the screen at the start of your render method. Try adding Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); if it isn't there already.

Related

Understanding outdated Libgdx code

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);

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();
}

Removing View from layout, from GLRendering thread

Summary
I'm trying to reliably remove a view from my layout, from my GL Rendering thread.
Details
I've got a splash screen which is added to my main layout, so my views are in this order:
GLSurfaceView
Splashscreen (which is a simple Android View)
All my objects and anything that can be loaded in the background is loaded from an AsyncTask, then, my GL Textures are loaded on the GL Thread (as is required), I'm then removing the Splashscreen from my layout to reveal my app's main menu screen.
90% of the time it works perfectly, (load time on my device is approx 3.5 seconds), however, occasionally, it appears to either never remove the view, or can take up to 8 seconds.
This is my current implementation
In my Activity class, I have the following method setup
public void dismissSplashScreen(){
removeSplash = new Runnable(){
public void run(){
//Is splashscreen currently visible?
if (splash.isShown()){
//Remove the splashscreen
layout.removeView(splash);
//Recycle splash screen as it's no longer required
recycle();
}
}
};
//Remove it
handler.post(removeSplash);
}
And then in my GLRenderer's onSurfaceCreated method, I have this:
public void onSurfaceChanged(GL10 gl, int deviceWidth, int deviceHeight) {
GLES20.glViewport(offsetX, offsetY, width, height);
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
loadGLTextures();
//Everything is done! Dismiss the splash to reveal main menu
activity.dismissSplashScreen();
}
I also attempted to use runOnUIThread, but the results were the same, if not worse. Is my implementation correct here? What things can I check and is there a simpler way to remove this view from my layout once everything is done? (I can't dismiss it from the activity class directly as I have to wait for the GL textures to load on the GL thread).
Sorted.
The reason was because I am calling activity.dismissSplashScreen from onSurfaceChanged and onSurfaceChanged is being called multiple times (a common problem I gather and one which I've not been able to get to the bottom of yet).
So what I think was happening, was it was posting my runnable to the queue and then posting another before the first one had either started or completed, sometimes a third time.
So everything was getting a bit confused.
I simply added a boolean flag to guarantee that the runnable was posted only once like so:
if (!splashIsGone){
activity.dismissSplash();
splashIsGone = true;
}

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.

AndEngine -- Having problems with attaching a new Sprite Entity

I've been doing trial and error for hours now and I have not yet come up with a solution for something that seems simple....
I am using the
public void onConfigurationChanged(Configuration newConfig)
method to detect if a user has changed their screen orientation.
Eventually, it gets sent to this method where the entitys are attached to the scene:
public void BuildScene(final Scene scene){
// Destroys current scene.
scene.detachChildren();
this.SpriteDayPortrait = new Sprite(-200, 0, 2000, 500, this.mParallaxLayerDayPortrait);
this.SpriteDayLandscape = new Sprite(0, 0, 750, 500, this.mParallaxLayerDayLandscape);
if (prefs.getString("frontImage", "1").equals("3"))
{
//Day
if (orientationValue.equals("PORTRAIT"))
{
Log.d("Orientation", "Portrait");
scene.detachChild(SpriteDayLandscape);
scene.attachChild(SpriteDayPortrait);
}
else if (orientationValue.equals("LANDSCAPE"))
{
Log.d("Orientation", "Landscape");
scene.detachChild(SpriteDayPortrait);
scene.attachChild(SpriteDayLandscape);
}
}
}
This method is called to when the wallpaper is first created, and also when a user changes screen orientation.
I have tested this on my phone and it successfully displays the log messages when I switch orientations, which means that it is doing it what I want it to do.
The Problem--
The sprite child does not detach when this method is called to. If I am in Portrait mode, and switch to Landscape, the portrait sprite remains and I would like it to disappear, and vice versa.
I would be extremely happy if anyone could answer this I've been having a headache over this for probably 20 hours.
It looks like the problem might be logic: You reassign the SpriteDayPortrait and SpriteDayLanscape before calling the branch about detaching them or attaching them.
So each time the detach script is called it is referring to a new instance of the sprite, rather than the old instance that you want to detach.
try moving the assignment of the sprites into another function that is only called when the scene is created:
// Move this
this.SpriteDayPortrait = new Sprite(-200, 0, 2000, 500, this.mParallaxLayerDayPortrait);
this.SpriteDayLandscape = new Sprite(0, 0, 750, 500, this.mParallaxLayerDayLandscape);
Keep in mind that since changing orientation in AndEngine doesn't exist (You are not allowed to change engine orientation), you should't make your game be using orientation changes (That would be weird for the user).
Anyways, onConfigurationChanged is called from the UI thread, and you should not manipulate objects of AndEngine but in the UpdateThread. It might cause some problems (However, if it would, your game would crash) so change it.
I think it happens because you didn't clear your ParallaxBackground before setting the new background (Perhaps the old background hides the new one?)
Keep a reference to your last ParallaxEntity then remove it from the background before adding a new one.

Categories

Resources