Mutiple stages - Buttons don´t react? - java

once again a newbie needs an advice from you, gracious stranger.
I have some problems that, even after googling them, couldn´t been solved.
I have 2 Stages in my game with a Table in each one that hold Buttons:
The first one stores a Table with ingame buttons : move up/down and pause
the second one stores a Table that represents the pause menu.
if "pause" is clicked (the game pauses and) I want to draw the second stage that now can process input.
I initialized 2 stages:
public void create(){
...
mainStage = new Stage(viewport,batch);
menuStage = new Stage(viewport,batch);
Gdx.input.setInputProcessor(mainStage);
...
the pause Button got an Listener that sets the (enum) STATE to PAUSE
(same for the "resume" Button in the pause menu, that sets the state to RUNNING)
pause.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
thisState = STATE.PAUSE;
Gdx.input.setInputProzessor(menuStage);
}
});
then in the render method
switch (gameState) {
case RUNNING:
deltaTime = Gdx.graphics.getDeltaTime();
stateTime += deltaTime; // for the animations
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
update(deltaTime);
batch.begin();
... draws the characters
batch.end();
mainStage.act(deltaTime);
mainStage.draw();
break;
case PAUSE:
Gdx.gl.glClearColor(0, 0, 0, 0.6f); I want the background to become slightly darker.
Gdx.app.log("Game State","Game is PAUSED");
menuStage.act(deltaTime);
menuStage.draw();
}
If I start the mainStage Buttons appear, but arent clickable.
What I have noticed is that the game stops if I click in the middle of the screen. Howeverm the "pause" Button´s Listener apparantly doesnt even react to that as there was no notfication on the console, that the game is paused, nor that the Button was clicked.
My Start Screen uses only one Stage and works perfectly with the same setup.
What I think the resons might be:
I used setInputProcessor falsely
I used Viewport falsely (and resize)
I have to somehow let the first stage disappear before drawing a new stage
Help is appreciated a lot! Thank you.
sry for my bad english
.. and for my formating (this is my first Post here)

by your code, gdx is only processing inputs for mainStage, you could swap input processors when showing the menu or use a input multiplexer like this:
public void create(){
[...]
mainStage = new Stage(viewport,batch);
menuStage = new Stage(viewport,batch);
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(mainStage);
multiplexer.addProcessor(menuStage);
Gdx.input.setInputProcessor(multiplexer);
[...]
}

Related

How to make a similar animation to Flappy Bird in Libgdx?

I'm creating a game like flappy bird where the bird flaps his wings only when the screen is touched, but I'm having a problem activating the animation when the screen is touched.
batch.draw(animation.getKeyFrame(myTimeState, false), x, y); //the myTimeState is 0 to render the 1st frame only.
Then when the screen is touched I do this:
//myTimeStep is just basically a controllable timeState for the animation only
if(Gdx.input.justTouched){
myTimeState = timeState;
}else if(Gdx.input.justTouched == false && animation.isAnimationFinished(timeState)){
myTimeState = 0;
}
I don't think the animation is able to play all the frames because myTimeStep become 0 immediately after finishing to touch the screen. Also I don't think this is the right way of doing it, if you guys have better ideas or solution please help. Thanks in advance.
There are probably several ways to achieve this. You'll need to increment your timeState, of course, and also it depends how long your animation is and if you want it to loop.
If you've created your animation to play only once, and then stop (until the screen is touched again), you could simply set your myTimeState to 0 when the screen is touched, and then increment it every frame. The animation will run through and then "stop" on its own when it reaches the end (as you said no loop). The next time someone touches the screen, your myTimeState is set back to 0 and the animation starts again.
Firstly, you have to ensure your animation's playmode is set to Animation.PlayMode.NORMAL. It's a default setting, but if you set it somewhere to LOOPED, nothing would work as expected.
Secondly, I wouldn't use Input.justTouched() in this case. Instead, a listener in your input processor would be a great fit. Here's an example with Stage. If you have no idea what input processor is, here's tutorial on event handling and class documentation.
stage.addListener(new ClickListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if(button == Input.Buttons.LEFT) {
timeState = 0;
}
return super.touchDown(event, x, y, pointer, button);
}
});
You can pick what's going to be displayed (animation's keyframe or sprite) based on result of animation.isAnimationFinished()
if(animation.isAnimationFinished(timeState)) {
//draw some sprite
} else {
//draw animation keyframe
}
I haven't checked it but there's a possibility, that this could lead to the last frame being cut out, because as soon as it gets displayed, animation.isAnimationFinished() will return true. I may be wrong, so you'll have to check it. If it becomes an issue, you can add your sprite as the last frame of your animation. When animation ends, it frezzes on the last frame, which would be your static sprite.
In both cases you'll get your animation played at the beginning of game because timeStep equal to 0. I see 2 solutions, I advise you to take the second:
Set timeStep to a large number, that is for sure larger than your animation's duration. Animation.isAnimationFinished() will then return true.
Introduce boolean variable isAnimationPlayed that:
is initialized with false,
gets set to true in your click listener,
gets set to false during isAnimationFinished(), which is called each frame only when isAnimationPlayed is true,
is used in draw() method to determine what to display.
You could just set your timeState to the duration of the animation.

what is stopping my screen from rendering as planned?

#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
combattext.setText(combatstring);
stage.act();
stage.draw();
}
combatstring is a string that displays what happened in my game. when enemies attacks, it says what happened. when I attack, it says what happens. As of now my game has a loop when in combat that runs a turncounting instance. When it's time for a turn, it runs that participants turn, and when their turn is over it updates combatstring.
I have 2 combatstrings. One is for my characters, and one is for enemies. Here is an example of what happens when it's an enemies turn.
if(thisencounter.monster1turn){ //monster1's turn goes in here
thiscombat.getTarget(1); //get enemy's target
thiscombat.calculateVars(1); //calculate all combat variables for
// this turn
thiscombat.theyAttack();
combatstring = thisencounter.thisenemy.species+
" "+thiscombat.action+
" "+thiscombat.theirtarget.species+
" for "+thiscombat.effect;
thisencounter.monster1turn=false;
}
This works fine, my combattext label updates instantly when a monster goes.
For my characters, their turns make buttons visible on my screen. The buttons have listeners that determine actions, here is an example:
monster1.addListener(new ClickListener(){ //makes the first enemy's
//image clickable, but only
//when the attack button
//has been clicked
#Override
public void clicked(InputEvent event, float x, float y) {
thiscombat.ChooseTarget(1); //various methods that calculate damage,
//output what happened, and put us back in
thiscombat.calculateVars(4); //the loop to wait for next
//participant's turn
thiscombat.youAttack();
combatstring = thisencounter.thisspirit.species+
" "+thiscombat.action+
" "+thiscombat.yourtarget.species+
" for "+thiscombat.effect;
monster1.clear();
monster2.clear();
monster3.clear();
try {
combatloop();
} catch (InterruptedException ex) {
Logger.getLogger(map1field.class.getName()).
log(Level.SEVERE, null, ex);
}
}});
This also works fine, EXCEPT on the turn just before a monster goes. Since there is no wait between my turn and the monster's turn, the combattext just instantly displays what the monster does.
I assumed 'oh hey this is because there is no delay between the two turns'. So, I threw a thread.sleep(2000) just before where it updates the monsters combatstring.
But that does not fix it. It still does not show the text for my character that goes just before a monster. Also, since fighting starts right when you go to this screen in the game, it waits about 2 seconds before it displays anything on the screen.
For the life of me I don't understand why it behaves like this. Can someone explain what is happening to me? Is it because it isn't rendering before it gets to thread.sleep ?
If that's the case, how do I force it to render before it does thread.sleep, or what should I be using instead of thread.sleep ?

How to make my game stop after ten seconds in libgdx?

I'm almost done with my project to make a very simple game. The point of the game is to count how many times the user touches the screen and compare it to the number of times an object popped up on the screen to be touched. It's considered a win if number of touches = number of objects. All of this is to happen in 10 seconds, and I have no idea where to start on how to time the game? (It's supposed to be a veryyy very simple game just to learn how to use libgdx)
As of now, there's a start screen that the user touches to start and then the game starts where objects pop up to be touched. The problem is that it's basically an endless game right now... Here's how I make an object "randomly pop up":
if (Gdx.input.isTouched()) {
touchCount++;
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
visual.x = MathUtils.random(10, 700);
visual.y = MathUtils.random(100, 400);
}
Do I have to put some built in timer function in this part of the code? And how to I go about tracking the touches to compare with the number of objects that popped up?
Thanks, any advice would be very appreciated!
System.currentTimeMillis() gives you current time in milliseconds
For example you can do something like this
private long time;
public void show(){
//...
time = System.currentTimeMillis();
}
public void draw(){
//...
if(System.currentTimeMillis()>time+10000){
System.out.println("after 10 seconds");
}
}
You may use old fashioned java way either:
Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
// Pause your game or just close it...
Gdx.app.exit();
}
}, 10000L);
Of course it's better to use synchronous timer approach, but for fast debuging or prototyping needs its sometimes more convenient.
Use the delta value inside your render() method.
render(float delta){
// ......
if (yeni_oyun_mesaji_var_MI)// a boolean value to increment my time value only it is needed.
oyun_uyari_zamani_tutucu += delta;
if (oyun_uyari_zamani_tutucu > oyun_uyari_zaman_siniri) {// after some time (**oyun_uyari_zaman_siniri**) do what you need
oyun_uyari_zamani_tutucu = 0f;
oyun_durum_mesaji_str = "";
yeni_oyun_mesaji_var_MI = false;
Gdx.app.log(TAG, "Uyarı Kapatıldı!");
}
}

scrolling never-ending background in Game not working as expected

I am working on my first side-scroller game and am trying to achieve a neverending background effect and it's nearly working as i would expect but there are little glitches.
I have 2 instances of the background (each fills the screen width), with one placed at the bottom left corner of the screen and one off the screen to the right. I am then moving my camera each frame to the right and when the first background instance is completely offscreen to the left i reset its X to the right of the camera so that it is now (relative to the camera) off the right of the screen. this is working a lot of the time, but every now and again it seems the method to reset its x position is getting called a few frames late and results in a gap in the background.
the update code i am using in the main game is -
private void update(float delta){
//update camera and world
camera.position.set(camera.position.x+scrollSpeed, camera.position.y, 0);
camera.update();
world.step(step, velocityIterations, positionIterations);
if(gameInProgress){
//backgrounds (array holds the 2 instances of the background)
for(int i=0; i< bgFillArray.size; i++){
bgFillArray.get(i).update();
}
}
stage.act(delta);
tweenManager.update(delta);
}
the update method in the BgFill class -
public void update(){
float currentXPos = getX();
float leftBoundary = camera.position.x-1200;
float rightOfScreen = camera.position.x+400;
if(active){
//check to see if the camera has gone past this instance. if so then move to right
if(currentXPos <= leftBoundary){
setX(rightOfScreen);
}
}
}
Firstly, is this the usual way (or even close) to do a continuous scrolling background?
if it is, what am I doing wrong?

Setting text on Label (Actor) stops drawing

I just can't figure this, and I am pulling my hair out right now!!
I have a Stage with a Label added to it, I set everything up and the first time I call Stage.draw() everything works fine. However, as soon as I set the text of the Label nothing gets drawn. Funny thing is, when I don't change the text it draws perfectly as expected, but when I call label.setText("THE TEXT") it just doesn't draw.
I have stepped through my code and I have noted down the height, width, x and y values before and after setting text of the Label, and they are all the same (before and after).
Also, when I draw the Stage it's drawn above a Sprite, and positioning the Sprite is based on the Label's position.
The Sprite draws fine before I set text on the Label and after.
PS: I have also made sure that the Sprite is not drawn "over" the Label.
This is my setup:
I have a MainGame class that renders a Player class, when ever the back button is pressed the Sprite with the Stage gets drawn, or should get drawn.
spriteBatch.begin();
player.update(spriteBatch, delta);
spriteBatch.end();
// the pause menu is drawn with a separate sprite batch as it needs to be in middle relative to the screen and above everything else
if (player.isPaused()){
messageSpriteBatch.begin();
messageSprite.draw(messageSpriteBatch);
messageSpriteBatch.end();
messageStage.draw(); // the stage doesn't seem to be getting drawn
}
Player class - update method
if (!paused){
// removed for clarity
}else{
// on MainGame class we render a small box with one of the following messages
// READY
// PAUSE
// QUIT?
// GAME OVER
if (Gdx.input.justTouched()){
paused = false;
}
spriteBatch.setProjectionMatrix(camera.combined);
camera.update();
}
messageSpriteBatch = new SpriteBatch();
messageStage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
messageFont = new BitmapFont(Gdx.files.internal("fonts/fontfile.fnt"));
messageStyle = new LabelStyle();
messageStyle.font = messageFont;
messageLabel = new Label("READY", messageStyle);
This is how I initialise my Label, Sprite and Stage:
float fontScaleX = Gdx.graphics.getWidth()/SCALE_X_DIVIDER;
float fontScaleY = Gdx.graphics.getHeight()/SCALE_Y_DIVIDER;
messageLabel.setFontScale(fontScaleX*1.4f, fontScaleY*4.2f);
messageLabel.setPosition((messageStage.getWidth()/2)-((messageLabel.getWidth()/2)*messageLabel.getFontScaleX()), (messageStage.getHeight()/2)-((messageLabel.getHeight()/2)*messageLabel.getFontScaleY())+(player.getScoreboard().getSize().y/2));
messageStage.addActor(messageLabel);
messageStage.act();
messageTexture = new Texture(Gdx.files.internal("images/message_background.png"));
messageSprite = new Sprite(messageTexture);
messageSprite.setSize((messageLabel.getWidth()*messageLabel.getFontScaleX())*1.5f, (messageLabel.getHeight()*messageLabel.getFontScaleY())*3);
messageSprite.setPosition(messageLabel.getX()-(messageSprite.getWidth()/6), messageLabel.getY()-messageSprite.getHeight()/2);
Please help me, before I get bald xD
Well the width and height of the label is usually set once when creating the Label, matching the width and height of the initial text passed to the Constructor. You of course can make it bigger by setting the width and height later on. Then you could also use alignments by the way...
Are you using any special characters when changing the text, so the font has a problem with that?
Maybe posting some code could give more insights...
Haha, well, I found out what was up, it was my font file, you see when I was editing it, I used the text READY, so when I saved it, I didn't know that the text written is what is saved, so when I looked at the font.png file, I found that it only contained the letters ADERY.
Thanks for the help anyway =]

Categories