LibGDX Stage and Actor, Events and Actor properties - libgdx

I'm just starting android game development with LibGdx framework.
I read many online tutorial so far and the more I read the more I got confused: ApplicationListener, ApplicationAdapter, Stages, Game, Screens, Actors, Sprites, Images... not mentioning Input and Gesture listeners of all king).
I finally understood what kind of "model" I should use for the game I have in mind (a kind of puzzle game): Game, Screens, Stage and Actor.
So here is my first code.
This is the main application (Game):
package com.my.game1;
import com.badlogic.gdx.Game;
public class MyGame extends Game {
#Override
public void create () {
setScreen(new StarterScreen());
}
}
This is the main screen class:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.scenes.scene2d.Stage;
public class StarterScreen implements Screen {
private Stage stage;
private float screenW, screenH;
private Tess tessera;
#Override
public void show() {
tessera = new Tess("image.png");
stage = new Stage();
screenW = stage.getViewport().getWorldWidth();
screenH = stage.getViewport().getWorldHeight();
Gdx.input.setInputProcessor(stage);
stage.addActor(tessera);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
stage.dispose();
}
}
And the following is the class that extends Actor:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
public class Tess extends Actor {
private Texture texture;
private boolean selected = false;
public Tess (String img) {
this.texture = new Texture(Gdx.files.internal(img));
this.setBounds(0f, 0f, this.texture.getWidth(), this.texture.getHeight());
this.setOrigin(this.texture.getWidth() / 2, this.texture.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
public void tap(InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
((Tess)event.getTarget()).setColor(0.5f, 0f, 0.5f, 1f);
}
});
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(texture, 0, 0);
}
public void finalize() {
this.texture.dispose();
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
this.setColor(0.5f, 0f, 0.5f, 1f);
else
this.setColor(0f, 0f, 0f, 0f);
}
}
The screen shows correctly the actor, but I cannot set the Actor's position or its scale, nor the "tap" event seems to get detected; and the color doesn't change.
What I did wrong?

Several things were wrong. First, just on the side, you don't want to call dispose() from the Screen's hide() method. hide() can be called simply when the screen is turned off, or when the app is switched to the background, and disposing of the Screen during that would cause serious issues on resume.
With that out of the way, here's what your Actor should have looked like:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Touchable;
public class Tess extends Actor {
private Sprite sprite;
private boolean selected = false;
public Tess (String img) {
this.sprite = new Sprite(new Texture(Gdx.files.internal(img)));
this.setTouchable(Touchable.enabled);
this.setBounds(this.sprite.getX(), this.sprite.getY(), this.sprite.getWidth(), this.sprite.getHeight());
this.setOrigin(this.sprite.getWidth() / 2, this.sprite.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
#Override
public void tap (InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
}
});
}
#Override
public void draw(Batch batch, float alpha){
sprite.draw(batch);
}
#Override
public void positionChanged(){
sprite.setPosition(getX(), getY());
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
sprite.setColor(0.5f, 0f, 0.5f, 1f);
else
sprite.setColor(0f, 0f, 0f, 0f);
}
}
First thing changed: you should use a Sprite, not a Texture, to handle color, drawing and transformations easily. Texture is possible, but is not as straightforward as Sprite is.
Next, you need to call setTouchable(Touchable.enabled) inside the actor to actually enable hit detection. Without this, no touch events are passed to the Actor.
After that, with setBounds(), you need to use sprite.getX() and sprite.getY(), to utilize the Sprite's positional values. Setting them to any arbitrary number seems to disable any touch capacity for that Actor.
Another thing, if all of that had been OK, is that you were setting the color twice for each touch, once based on the selected field, and then immediately after straight to the dark purple, so I removed the second set and just used your toggle method.
Next, since we have a Sprite now, we can use the draw() method attached to the Sprite itself and feed it the Batch, instead of calling the Batch's draw.
Finally, when you want to change the position of the image, call setPosition on the actor itself, and utilize an override of the positionChanged() method to set the Sprite's position based on the Actor's new position.

Related

Libgdx ScaleToAction not resizing

I am trying to make a sprite move, rotate and resize by using MoveToAction, RotateToAction and ScaleToAction. The first two works fine, but I have a problem with ScaleToAction.
I add the action to the Actor just like I do with the two that works. I think the problem might be in the #Override? When I run the code the sprite moves and rotates but no scaling is done.
I tried to use sprite.setscale as suggested in the answer below, but still no luck. I add the code from the class here:
public class Prizes extends Actor {
private LearnToRead game;
private TextureAtlas atlas;
private TextureRegion prizepic;
private Sprite sprite;
private RotateToAction rta;
private ScaleToAction sta;
private MoveToAction mta;
public Prizes(LearnToRead game) {
this.game = game;
atlas = new TextureAtlas("prizes.pack");
prizepic = atlas.findRegion("haxhatt");
sprite = new Sprite(prizepic);
sprite.setPosition(450 - sprite.getWidth() / 2, 450 * Gdx.graphics.getHeight() / Gdx.graphics.getWidth() - sprite.getHeight() / 2);
//setBounds(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
setTouchable(Touchable.enabled);
rta = new RotateToAction();
sta = new ScaleToAction();
mta = new MoveToAction();
rta.setRotation(180f);
sta.setScale(2f);
mta.setPosition(0, 0);
mta.setDuration(5f);
rta.setDuration(5f);
sta.setDuration(5f);
Prizes.this.addAction(rta);
Prizes.this.addAction(sta);
Prizes.this.addAction(mta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
sprite.draw(batch);
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void positionChanged() {
sprite.setPosition(getX(), getY());
}
#Override
protected void rotationChanged() {
sprite.setRotation(getRotation());
}
#Override
protected void sizeChanged() {
sprite.setScale(getScaleX(), getScaleY());
}
}
If also tried to remove sprite and just use the TextureRegion, but didn't get it to work. The texture is drawn, but not moving. I post that code as well, but I do confess that I am quite uncertain about this code:
public class Prizes extends Actor {
private LearnToRead game;
private TextureAtlas atlas;
private TextureRegion prizepic;
private RotateToAction rta;
private ScaleToAction sta;
private MoveToAction mta;
public Prizes(LearnToRead game) {
this.game = game;
atlas = new TextureAtlas("prizes.pack");
prizepic = atlas.findRegion("haxhatt");
Prizes.this.setBounds(450 - Prizes.this.getX(), Prizes.this.getY(), Prizes.this.getWidth(), Prizes.this.getHeight());
setTouchable(Touchable.enabled);
rta = new RotateToAction();
sta = new ScaleToAction();
mta = new MoveToAction();
rta.setRotation(180f);
sta.setScale(2f);
mta.setPosition(0, 0);
mta.setDuration(5f);
rta.setDuration(5f);
sta.setDuration(5f);
Prizes.this.addAction(rta);
Prizes.this.addAction(sta);
Prizes.this.addAction(mta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
game.batch.begin();
game.batch.draw(prizepic, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
game.batch.end();
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void positionChanged() {
Prizes.this.setPosition(getX(), getY());
}
#Override
protected void rotationChanged() {
Prizes.this.setRotation(getRotation());
}
#Override
protected void sizeChanged() {
Prizes.this.setScale(getScaleX(), getScaleY());
}
}
Maybe someone has a good idea about what I am doing wrong?
Use sprite.setScale instead of sprite.scale. The difference is that you are setting it a specific value instead of multiplying the current scale by some value.
But it is redundant to use Sprite with Actor because both classes store position, rotation, scale, and color. It makes more sense to use a TextureRegion with Actor. Or you can use the Image class, which already handles this for you.
Edit:
I see the other part of the issue. You are overriding sizeChanged, but it's the scale, not the size, that you are changing with a ScaleToAction. Actor doesn't have a callback for the scale changing. You could override the setScale methods to apply your change to the Sprite, but like I said above, it doesn't make sense to be using a Sprite for this. You should reference a TextureRegion, and draw it with all the appropriate parameters in the draw() method.

Actor in Stage Does Not Update the MoveTo XY Location

I am creating a game wherein an apple is being shot with an arrow. The apple's location is the XY location of the user input and the arrow actor has to move to that location using the code actor.moveto. The problem is the arrow only moves only once to the user input's direction. I know that the moveTo action of the actor is updated many times per second when I called stageArrow.act in the update method so I am wondering why the arrow only moves once. Here's my code:
appleclass.java
public class AppleClass implements Screen {
Arrow arrow;
private final MainApp app;
public Image ShotImage;
public AppleClass(final MainApp app){
this.app = app;
this.stageApple = new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
this.stageArrow =new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
arrow = new ArrowClass(app);
}
#Override
public void show() {
InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stageApple);
inputMultiplexer.addProcessor(stageArrow);
Gdx.input.setInputProcessor(inputMultiplexer);
arrow();
}
public void arrow(){
arrow.isTouchable();
stageArrow.addActor(arrow);
arrow.addAction((moveTo(Gdx.input.getX(),Gdx.input.getY(),0.3f))); //===> only executes once.
arrow.addListener(new InputListener(){
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){
if (Gdx.input.isTouched()){
ShotImage.setVisible(true);
}
}
});}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update(delta);
}
public void update(float deltaTime){
stageApple.draw();
stageArrow.draw();
stageApple.act(deltaTime);
stageArrow.act(deltaTime);
}
ArrowClass.java
public class ArrowClass extends Actor {
MainApp app;
AppleClass appleClass;
public Texture arrowTexture;
public ArrowClass(final MainApp app){
this.app = app;
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
final float delta = Gdx.graphics.getDeltaTime();
this.act(delta);
app.batch.begin();
app.batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
app.batch.end();
}
}
Any help will be highly appreciated. Thanks.
I think the problem is because you are calling this.act(delta) in your ArrowClass' draw method. When you call Stage#act(), it will call the act method on all of its actors for you. Since you're calling it once when you draw and again when you update the stage, it's moving at twice the normal speed and that could be causing it to reach its destination prematurely.
A few other comments about your code, if I may:
First, you probably don't want two separate stages- unless you're using Scene2D.UI, you would normally have a single stage with Arrow and Apple added to it as actors.
Second, when you override Actor#draw(), you should use the batch it passes you to do the rendering instead of using the one from app. You also don't want to call begin() and end() inside your draw method- these are 'expensive' and you only want to call them once per frame. However, if you just use the batch that is passed to draw(), the Stage class will handle beginning and ending for you and you won't need to call them explicitly.
Third, you actually don't need to call super.draw(batch, parentAlpha) because it's an empty method in the Actor class.
Thus, your class could be simplified to the following:
public class ArrowClass extends Actor {
AppleClass appleClass; // You never set this; you may not need it
Texture arrowTexture;
public ArrowClass(MainApp app, arrowWidth, arrowHeight) {
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
}
}

LibGdx - Adding array of actors to a table, with delay

I want to have several comets falling in the background of my UI,I have a working comet Actor that does what it is supposed to, but I am not sure how to create a continuous spawn with these comets (with a random delay between each) in a table, without scene2d/actors it would look something like:
cometTimer += delta
if(cometTimer >= interval){
addCometToArray();
cometTimer = 0;
}
With the cometArray being looped over and drawn every frame, and then removing the entity when it goes out of bounds.
The only way I know how to add Actors to a table is like this:
table().add(new DialogComet());
How would I go about adding this type of behaviour using Scene2d?
Not sure if this is what you were looking for, but the below is a small working app that shows comets "falling" from the top to bottom, using Tables and having the tables manage the comets (no separate array/data structure). I created a small Comet class that extends Actor as well, to allow for movement and placement.
"main" class:
import java.util.Iterator;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
public class StageComet implements ApplicationListener {
private static final float INTERVAL = 0.3f;
private Batch batch;
private ShapeRenderer shapeRenderer;
private OrthographicCamera camera;
private BitmapFont font;
private Table rootTable;
private Table cometTable;
private Stage stage;
private Iterator<Actor> iter;
private Comet comet;
private float cometTimer = 0;
private float delta = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 960, 640);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
font = new BitmapFont();
stage = new Stage();
/*
* The root table could contain main "play" actors. It is empty in this example.
*/
rootTable = new Table();
rootTable.setFillParent(true);
/*
* Usually in Scene2d I think the practice is only to have 1 root table that takes up the entire screen (above),
* but for simplicity/illustrative purposes, I created a cometTable only, set it to Fill Parent as well, and the
* getChildren() of the table will have our array of comets in play at any given time.
*/
cometTable = new Table();
cometTable.setFillParent(true);
stage.addActor(rootTable);
stage.addActor(cometTable);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
delta = Gdx.app.getGraphics().getDeltaTime();
stage.act(delta); // make sure the comets "fall"
shapeRenderer.begin(ShapeType.Filled); // simple rendering of comets, they are just a circle ...
iter = cometTable.getChildren().iterator(); // Table subclasses Group, which has a snapshot array of its Actors
while ( iter.hasNext() ) {
comet = (Comet)iter.next();
shapeRenderer.circle(comet.getX(), comet.getY(), 20.0f); // Draw the comet
if ( comet.getY() < -100 ) { // Hack/hardcode, if the comet fell far enough "off stage" ...
iter.remove(); // ... remove it from the stage
}
}
shapeRenderer.end();
/*
* Sample code from original question on how to create a comet without scene2d ...
*/
cometTimer += delta;
if ( cometTimer > INTERVAL ) {
cometTable.add(new Comet()); // ... but in this case, we use scene2d
cometTimer = 0;
}
/*
* To keep track, display a simple message of # of comets on stage at any given time.
*/
batch.begin();
font.draw(batch, "Comets on stage: " + cometTable.getChildren().size, 100, 100);
batch.end();
}
/*
* I may have missed disposing something, but you get the idea ...
*/
#Override
public void dispose() {
shapeRenderer.dispose();
batch.dispose();
stage.dispose();
font.dispose();
}
#Override
public void resize(int width, int height) { }
#Override
public void pause() { }
#Override
public void resume() { }
}
And the small Comet class:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.Actor;
public class Comet extends Actor{
/*
* Spawn a comet at the top of the screen, in the middle
*/
public Comet() {
super();
this.setY(Gdx.app.getGraphics().getHeight());
this.setX(Gdx.app.getGraphics().getWidth()/2.0f);
}
/*
* Let the comet fall (same speed) to the bottom of the screen ...
*/
#Override
public void act (float delta) {
this.setY(this.getY() - 10);
super.act(delta);
}
}

Pause Menu is "moving down" & improving the code

I have a problem with my pause screen. I made a simple Splash screen, followed by the main menu, where you can start or end the game, followed by a random picture. If the user presses Esc it switches to the pause screen, which is very similar to the main menu. Only difference is that it doesn't generate a new picture if the user clicks on "Continue", instead it just renders the game screen again. But if I press Esc after continuing again, the pause menu appears lower on the screen than it should. If I repeat pressing Continue and then Escape, the buttons eventually moved out of the displayed screen. I didn't find a solution yet, so I made an account here, since this site helped me a lot so far.
Furthermore I want to know if there are things I could improve. I just started with libGDX, so there probably are a lot of things I could've done better, and I want to know that. SO if you have a few improvements, I would be glad to read them :)!
This is the code:
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
public class GameScreen implements Screen{
private Texture[] monsterTextures = {new Texture(Gdx.files.internal("Ressources/DemonHunter.jpg")), new Texture(Gdx.files.internal("Ressources/WingedDemon.jpg")),
new Texture(Gdx.files.internal("Ressources/Viking.jpg")), new Texture(Gdx.files.internal("Ressources/DemonWarrior.jpg"))};
private Image[] monsterImages = {new Image(monsterTextures[0]), new Image(monsterTextures[1]), new Image(monsterTextures[2]), new Image(monsterTextures[3])};
private Stage gameStage = new Stage(), pauseStage = new Stage();
private Table table = new Table();
private Skin menuSkin = new Skin(Gdx.files.internal("skins/menuSkin.json"),
new TextureAtlas(Gdx.files.internal("skins/menuSkin.pack")));
private TextButton buttonContinue = new TextButton("Continue", menuSkin),
buttonExit = new TextButton("Exit", menuSkin);
private Label title = new Label ("Game", menuSkin);
private int randomMonster;
public static final int GAME_RUNNING = 0;
public static final int GAME_PAUSING = 1;
public static final int GAME_PAUSED = 2;
private int gamestatus = 0;
#Override
public void show() {
randomMonster = 0 + (int)(Math.random() * ((3-0) + 1));
gameStage.addActor(monsterImages[randomMonster]);
}
#Override
public void render(float delta) {
if(Gdx.input.isKeyJustPressed(Keys.ESCAPE)) pauseGame();
if(gamestatus == GAME_RUNNING) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gameStage.act();
gameStage.draw();
}
if(gamestatus == GAME_PAUSING) {
buttonContinue.addListener(new ClickListener(){
public void clicked(InputEvent event, float x, float y) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gamestatus = GAME_RUNNING;
}
});
buttonExit.addListener(new ClickListener(){
public void clicked(InputEvent event, float x, float y) {
Gdx.app.exit();
}
});
table.add(title).padBottom(40).row();
table.add(buttonContinue).size(150, 60).padBottom(20).row();
table.add(buttonExit).size(150, 60).padBottom(20).row();
table.setFillParent(true);
pauseStage.addActor(table);
Gdx.input.setInputProcessor(pauseStage);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
pauseStage.act();
pauseStage.draw();
gamestatus = GAME_PAUSED;
}
if(gamestatus == GAME_PAUSED) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
pauseStage.act();
pauseStage.draw();
}
}
public void pauseGame() {
gamestatus = GAME_PAUSING;
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
pauseGame();
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
for(int i = 0; i < monsterTextures.length; i++) {
monsterTextures[i].dispose();
}
gameStage.dispose();
pauseStage.dispose();
menuSkin.dispose();
}
}
Thanks, Joshflux
I think your render() method is doing things it shouldn't. Like creating the clickListener and also adding buttons to the table (and possibly some other items in there).
The render method gets called every "frame". You don't want to be recreating this, say 60 times a second. You want to do it once (like when you create the particular screen) and then just draw (render) it every frame.
Restructure your code to do the "Creation" stuff once. The render() method should just draw it. I think you continually adding items to your table each frame may be what is causing the buttons to move off the screen.

How to properly use setposition in libgdx?

This is the java file created by gdx-setup-ui.jar of v0.9.7
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
Why we need to set position to negative value in order to center the picture?
Where is the reference base point of the libgdx picture? (left-bottom corner?)
I was told that the origin of libgdx is left-bottom corner. Given the above values, part of the picture should have been outside the screen....It turns out not! I am very confused.
Thanks in advance
Complete listing:
package com.packtpub.libgdx.basic;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class Basic implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
sprite = new Sprite(region);
sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
}
#Override
public void dispose() {
batch.dispose();
texture.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
It's because the default center point for the orthographic camera is (0,0,0), so if you just draw your image at (0,0) its bottom left cornet will be in the center of the screen.
You can change this center point by using cam.position.set(w / 2, h / 2, 0) method
See here for more detailed example of OrthographiCamera use: https://github.com/libgdx/libgdx/wiki/Orthographic-camera