libGDX: Adding multiple TextButton in table - libgdx

When I'm adding the same TextButton multiple times in my table, only the last one will be displayed:
public void show(){
button = new TextButton("Hello", textButtonStyle);
stage.addActor(button);
final Table table = new Table();
table.add(button);
table.row();
table.add(button);
table.row();
table.add(button);
table.setFillParent(true);
table.debug();
stage.addActor(table);
}
public void render(float delta) {
stage.act();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
What am I doing wrong?

addActor(actor) method called when you're adding a Actor to table by using add(..).
because Table is inherently a Group and according to doc :
When we call addActor(actor) method of Group
Adds an actor as a child of that group, removing it from its previous
parent. If the actor is already a child of that group, no changes are
made.
so create different object of required Actor and add them on table.

Related

Change at runtime the background of a table added to a stage in the constructor

I need at runtime to reload a background of a table added to a stage (the user can change it at runtime).
I'm doing this but the background will change only when I switch back from another Screen or reopen my game.
MyGame.java:
String backgroundFileName = "background1.jpg";
public class MyGame extends Game {
public void create() {
...
this.setScreen(new MainMenuScreen(this));
}
public void handleChoosenBackground(String _backgroundFileName) {
backgroundFileName = _backgroundFileName;
if(getScreen() instanceof MainMenuScreen) {
((MainMenuScreen)getScreen()).reloadBackground();
}
}
}
MainMenuScreen.java:
public class MainMenuScreen implements Screen, InputProcessor {
Stage stage;
Table table;
TextureRegionDrawable textureRegionDrawableBackground;
public MainMenuScreen(final MyGame game) {
...
stage = new Stage(new FillViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight())));
textureRegionDrawableBackground = new TextureRegionDrawable(new TextureRegion(new Texture(game.backgroundFileName)));
table = new Table();
table.setFillParent(true);
table.setBackground(textureRegionDrawableBackground);
stage.addActor(table);
}
public void reloadBackground() {
textureRegionDrawableBackground = new TextureRegionDrawable(new TextureRegion(new Texture(game.backgroundFileName)));
table.setBackground(textureRegionDrawableBackground);
// log prints here, so this method is reached, with the correct new backgroundFileName
}
}
I also tried this on MyGame class but it seems that does nothing because MainMenuScreen is already the active screen:
setScreen(new MainMenuScreen(this));
If, instead, I set textureRegionDrawableBackground to null, it works showing a white background:
public void reloadBackground() {
textureRegionDrawableBackground = null; // <<<<<
table.setBackground(textureRegionDrawableBackground);
}
Thanks!
I had a similar problem when I didn't run table.pack() once I finished putting all the things into the table - apparently the background size doesn't automatically resize to the table size, and you need to tell it to do so.
Hope that solves your problem :)

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

AddListener to an Actor one time only

Is it possible to allow the user to touch an actor only one time.
I've tried using boolean but the problem is I write addListener in the class constructor and I want it to be here not in a separate method
I believe you can remove the listener like this, I have not tested it though and no time for it right now.
final Table t = new Table();
t.addListener(ClickListener listener = new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
//Do stuff
//...
//remove this listener
t.removeListener(this);
}
});

Some Actions do not work

I want to make a text appear in the center of the screen, indicating
the current level. It should appear gradually and after a while disappear gradually. I'm using scene2d with stages, actors.. so i would use Actions.
This is what i have now:
public class TextActor extends Actor {
private BitmapFont font;
private CharSequence charSequence;
public TextActor(CharSequence charSequence) {
font = new BitmapFont(Gdx.files.internal("fonts/white_standard_font.fnt"));
this.charSequence = charSequence;
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float delta) {
super.draw(batch, delta);
font.draw(batch, charSequence, getX(), getY());
}
}
In the class that creates the TextActor..
textActor.addAction(Actions.sequence(Actions.fadeIn(1f), Actions.delay(1f), Actions.fadeOut(1f), new Action() {
#Override
public boolean act(float delta) {
textActor.remove();
transitionInProgress = false;
gameState = GameState.RUNNING;
Gdx.input.setInputProcessor(stage);
return true;
}
}));
gameTable.addActor(textActor);
fadeIn, fadeOut, alpha.. don't work. I tried with "moveBy" and it works, so it seems a problem concerning the appearance of the Actor. There is something that escapes me.
The fade actions modify the alpha value of the Actor's color (getColor().a). You're drawing the font directly without applying the color associated with the actor.
Take a look at how Label.draw is implemented for a better understanding. In the meantime, just try adding this above your font.draw(...) call:
font.setColor(getColor())
Or, if you don't want to modify the entire color, just the alpha, try this:
font.getColor().a = getColor().a;
UPDATE:
Also note that you should apply the parentAlpha (second parameter of draw - labelled as delta in your example) to the final alpha:
font.getColor().a = getColor().a * parentAlpha
This allows your actor to fade if you change the alpha of the stage or any parents.

libgdx: Adding Table to Stage causes Actors that aren't children of the Table to not render, despite not having overlapping coordinates

So, I have a Game Screen that I have set to 800x480, and at the top of that screen I'm trying to create a Table that contains some information. I've set the table bounds to x = 0, y = 380, width = 800, height = 100, and when the screen renders, the table shows up at the top of the screen just like I want. However, below that table, I want to render additional Actors that I've added to my stage. Problem is, they aren't rendering. If I comment out the line where I add the table to the stage, everything renders just fine - its only when I add the table that the issue occurs, even though the non-Table Actors don't overlap screen coordinates with the Table. For the purpose of this question, I cut out all of the Actors other than the one called "Field", which is a game board with coordinates of x=0, y=0, width=500, height=300.
Why is the inclusion of the Table obfuscating the rendering of my other Actors?
Here's my code (first GameScreen, then Field):
public GameScreen(MyGame game) {
// TODO Auto-generated constructor stub
this.game = game;
log = "Starting game";
plyscore = 0;
oppscore = 0;
stage = new Stage(new StretchViewport(800,480));
gameskin = new Skin(Gdx.files.internal("uiskin.json"));
gametable = new Table();
background = new TextureRegionDrawable(new TextureRegion(AssetLoader.background));
field = new Field();
score = new Label(plyscore+" - "+oppscore, gameskin);
logarea = new TextArea(log, gameskin);
logarea.setPrefRows(3);
logscroll = new ScrollPane(logarea, gameskin);
logscroll.setForceScroll(false, true);
logscroll.setFlickScroll(false);
gametable.setBounds(0, 380, 800, 100);
gametable.add(score).width(390);
gametable.add(logscroll).width(390).row();
stage.addActor(gametable);
stage.addActor(field);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.0f, 0.5f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
public class Field extends Actor {
public Field() {
setBounds(getX(), getY(), AssetLoader.field.getRegionWidth(),
AssetLoader.field.getRegionHeight());
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(AssetLoader.field,this.getX(),getY());
}
}