libgdx, several stages in one screen - android

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

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

Graphic problems with libgdx stage2d.ui

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.

LibGDX. Android. Black background on transparent DecalSprites

In my App I use several DecalSprites as a part of my scene. They all have transparency (PNG-textures). When I have them overlapping, some of those show black background instead of transparency. Those DecalSprites have different Z-coordinates. So they should look like one behind another.
Please note also the line on the border of a texture. This is also something that I'm struggling to remove.
Update 1: I use PerspectiveCamera in the scene. But all the decals are positioned to face the camera as in 2d mode. So this "black" background appears only in certain cases e.g. when camera goes right (and all those decals appear in the left of the scene). Also I use the CameraGroupStrategy
Solved! The reason was that CameraGroupStrategy when ordering Decals (from farthest to closest to camera) takes the "combined" vector distance between camera and the Decal. When my camera panned to left or to right the distance to the Z-farthest Decal became LESS than the Z-closer Decal. This produced the artifact. Fix:
GroupStrategy strategy = new CameraGroupStrategy(cam , new ZStrategyComparator());
And the Comparator:
private class ZStrategyComparator implements Comparator<Decal> {
#Override
public int compare (Decal o1, Decal o2) {
float dist1 = cam.position.dst(0, 0, o1.getPosition().z);
float dist2 = cam.position.dst(0, 0, o2.getPosition().z);
return (int)Math.signum(dist2 - dist1);
}
}
Thanks to all guys who tried to help. Especially Xoppa. He sent me into the right direction in libGDX IRC.

Andengine swipe navigation

I am new to andengine and want to know that how I can switch between two BaseGameActivities. And also when switching from first activity to second, there is no black screen transition in between switching. Is there any possible way to do it.
Please help me out.
A BaseGameActivity can be used as any other Android Activity, too:
Intent intent = new Intent(this, MyOtherBaseGameActivity.class);
startActivity(intent);
So if you want to change from your program to another app (maybe by opening the browser…) you can do that as with any other Android App, too. However if both Activities are part of your own App, there is rarely a case where this is recommendable (It is like starting a second program). Although it is possible to exchange data between the activities as described in this post.
But maybe you are only looking for a way to switch between Views in AndEngine. If that's the case you can switch between Scenes without any transition necessary.
MyOtherScene secondScene = new MyOtherScene();
mEngine.setScene(secondScene);
That way you can switch between what is being displayed, without needing to load every image again.
EDIT:
Since you can't use AndEngine to switch between Activities, nor is a smooth switching between scenes possible. Here a quick example on how to switch between two screens (e.g. menus). In this example the screens are actually 2 different images (as big as the display … maybe some background images). Note: there is no such thing as 'screens' in AndEngine, it is simply a self made class that extends Entity.
Your Screen
public MyScreen extends Entity{
private float firstX;
public MyScreen(Sprite niceBackgroundImage1, Sprite niceBackgroundImage2){
this.attachChild(niceBackgroundImage1); // attach something to the screen, so you can see it (preferably an image that is as big as your camera)
this.attachChild(niceBackgroundImage2);
this.firstY=-1; // this is a variable to remember the first x coordinate touched
}
#Override
public boolean onAreaTouched(TouchEvent sceneTouchEvent, float touchAreaLocalX, float touchAreaLocalY) {
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_DOWN){
this.firstY=touchAreaLocalX; // remember the x, on the first touch
}
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_MOVE){
if(touchAreaLocalX>firstY+20){
// user swiped from left to right (at least 20 pixels)
niceBackgroundImage1.registerEntityModifier(new MoveModifier(3f, 0, niceBackgroundImage1.getWidth(), 0, 0, EaseBounceOut.getInstance()));
// the last line actualy moves the nice..image1 from left to right (in 3 seconds) and lets it bounce a little bit before it is completely out of the screen
return true;
}
}
return false;
}
...
}
Your Activity
private HUD hud; // create a HUD
...
#Override
protected void onCreateResources() {
this.hud = new HUD(); // init the HUD
this.myScreen = new MyScreen(image1, image2) // init the screen
this.hud.attachChild(myScreen); // attach the screen to the hud
mEngine.getCamera().setHud(hud); // attach your HUD to the camera
}
#Override
protected Scene onCreateScene() {
Scene myScene = new Scene();
myScene.registerTouchArea(myScreen); // you have to register the touch area of your Screen Class to the scene.
mEngine.setScene(myScene);
}
And this is how it works:
you create yourself a own screen class that extends Entity. An Entity can be everything visible in AndEngine (like a Sprite, Rectangle or even a whole scene). Put something in your screen class to make it look nice, preferably a big image that fills the whole display. That image will be responsible to register the touch afterwards. If the image is too small and the user misses the image, then no touch will be registered.
In this case I attach the instance of MyScreen to the cameras HUD. That way it will be at a fixed position on the display and it will have a fixed size (just in case you want to make the scene scrollable or zoomable).
Now when the app starts the HUD will be created and attached to the camera and with it your MyScreen class. Then the scene will be created and the screen's area will be registered as touch area to the scene. When a swipe movement on a horizontal axis gets noticed by the screen class, the first image will move outside the screen (in the same direction as the swipe).
But be careful, this is just an example. There is nothing defined on how the touch has to act when the first image was moved outside the screen or how big the screen actually is etc...
I know this is quite a long example, maybe it won't even work the first time and it is definitely not the only way on how switching between different screens can be done. But it shows you how to override the onAreaTouched() method and register the entity modifier to make the image move. Hopefully it will lead you in the right direction, to accomplish what you want to do.

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.

Categories

Resources