Libgdx Hud Stage Button not Listening events - libgdx

I am trying to implement a HUD stage on top of the current stage. I am able to render and draw the HUD stage but its buttons' touch events are not responding.
I am calling my drawHUD() from my draw() method of GameScreen. Code for drawHUD() is
public void drawHud(int scoreVal){
Hud.this.getCamera().update();
Hud.this.hudSpriteBatch.setProjectionMatrix(Hud.this.getCamera().combined);
hudSpriteBatch.begin();
scoreStr = "Score: " + scoreVal;
glyphLayout.setText(scoreFont, scoreStr);
halfWidth = glyphLayout.width/2;
halfHeight = glyphLayout.height/2;
scoreFont.draw(hudSpriteBatch, scoreStr, EatGame.CAMERA_WIDTH/2 - halfWidth, EatGame.CAMERA_HEIGHT - halfHeight);
hudSpriteBatch.end();
}
I have added a listener to my pauseBtn like this when creating my HUD
pauseBtn.addListener(new InputListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("PauseBtn Touched");
return false;
}
}
I have also tested by setting the bounds of the button, but it is not responding to events.
Thanks for reading and helping.

Usually you use the scene2d API for implementing buttons and stuff like that. The Stage class is responsible for handling the events on the correct actor. Look at the Stage#touchDown() how they do it. If you want to implement this on your own, you would have to implement a global touch-listener and check, if the coordinates are inside the bounds of the button and then call fire on the button with the correct Event object.
I would highly recommend to use the scene2d api, its far more easier then to write your own hit-detection-firing-event-system.

I had to use InputMultiplexer for taking input events from both the stages. I have done this that way.
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(GameScreen.this);
multiplexer.addProcessor(hud);
Gdx.input.setInputProcessor(multiplexer);
This way it will receive events from both the stages. GameScreen and Hud are Stages.

Related

Libgdx: Draw a Sprite on touchdown

I want to draw A Sprite when touchDown event occurs and disposed when touchUp occurs. I tried following code:
public class Connect4Screen implements Screen {
SpriteBatch batch;
Connect4Screen(){
batch = new SpriteBatch();
camera = new OrthographicCamera(30, 20);
camera.update();
batch.setProjectionMatrix(camera.combined);
Gdx.input.setInputProcessor(new InputAdapter(){
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
drawChip();
}
}
}
public void drawChip(){
batch.begin();
batch.draw(new Texture("Images/yellow.png"), 0, 5, 1.4f,1.4f);
batch.end();
}
}
I scrapped off unnecessary code.
What is wrong here?
If you simply draw something as a one-time event, it will only be visible for 1/60 of a second. Games redraw the screen over and over in a loop, so to cause something to appear and stay on the screen, you need to set a member Boolean that indicates it should be drawn, and then in your render method you draw that item if the Boolean is true.
That's a very simplified explanation. Games tend to have many different items to draw that come and go, and keeping separate Booleans for each of them is impractical. So typically you'll have a list of items to draw, and you can add and remove items from the list based on events in the game. In your render method, you would loop through the list and draw everything in it.
Also, you must not create a new Texture without keeping a member reference to it so you can dispose() it later. Textures use native memory on the GPU and must be disposed of or they will leak memory. In LibGDX, any object that can leak memory implements Disposable, and must be disposed before you lose track of the reference.

How to tell stage that event didn't handle

I'm new with scene2d I don't know if what I do is right or not but I struggling with this problem.
I have two stage that add to InputMultiplexer.
first stage have two type of actor as stage's actor
stage.addActor(actor_1);
stage.addActor(actor_2);
then I add listener to the stage to check
if actor_1 or actor_2 was clicked
stage1.addListener(new ClickListener() {
#Override
public void clicked (InputEvent event, float x, float y) {
//task1;
}
});
if actor_2 was dragged I want the stage to pass the event to next stage below it but it seem the listener is always check event as handled so the stage below is not handle the drag event as I intent.
I check on Event class it doesn't have method to change handle state to false, then what I have to do to make this listener tell the first stage to pass event to the second stage in InputMultiplexer.

LibGdx ImageButton playing sound

I have created an imageButton with three drawable images;
one is button-up,button-down and button checked.Its purpose is to ON and OFF sound for the game.once sound is OFF,checked image should be displayed.
I have written the code like this:
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),
new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture3));
stage.addActor(soundButton);
soundButton.setPosition(Constants.WORLD_WIDTH / 4 + 300f, Constants.WORLD_HEIGHT / 4, Align.bottomLeft);
soundButton.addListener(new ChangeListener(){
#Override
public void changed(ChangeEvent event, Actor actor) {
if(!game.soundBool)
game.soundBool=true;
else
game.soundBool=false;
}
});
Here soundBool is initially false and game sounds will play when it is false.
once I make it true,sounds should not play.This boolean is working well.
Problem is that once I checked the button(sound OFF) sound is getting OFF permanantly.Again Button click is not working as expected.
How do I change the code to work it well?
Have you checked how often the changed() method is called? Use Gdx.app.log() for logging. Or try using a different Listener, like ClickedListener for the button.
You could also make you own Button, class MyButton extends Button to keep a cleaner code. Here is how I solved it.

click events don't reach root flash object

I started using as3 a while ago, and mostly used starling instead of native flash objects. Today I decided to give a try to raw flash, and created a simple button:
private var _button: SimpleButton;
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
}
private function OnClick(e:MouseEvent):void
{
trace("clicked");
}
This would definely work in starling, but I found that the click event won't dispatch to the button for some reason. Neither is hand cursor shown on mouse over. I tried mouse over, mouse up and other mouse events, but none of them work. I checked that the button is correctly added to stage. Also, when I add a mouse click event listener to the stage itself, clicks register normally. When I add a listener to Main, no events are registered again.
I'm probably misunderstanding something obvious. Maybe I need to dispatch events manually down to the children? But that would be strage, though. Or can it be a bug in FlashDevelop? Please, help.
The constructor of SimpleButton takes 4 optional parameters:
public function SimpleButton(upState:DisplayObject = null,
overState:DisplayObject = null,
downState:DisplayObject = null,
hitTestState:DisplayObject = null)`
of which you supply the first one (upState):
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
The others default to null. That includes hitTestState which is the same as property of the class hitTestState:
Specifies a display object that is used as the hit testing object for the button. [...] If you do not set the hitTestState property, the SimpleButton is inactive — it does not respond to user input events.
It also includes a solution to your problem:
For a basic button, set the hitTestState property to the same display object as the overState property.
However, if all you want is to add click functionality to that Bitmap, which it doesn't have on its own, because it's not an InteractiveObject, simply use a Sprite:
// entry point
_button = new Sprite();
_button.addChild(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
Use SimpleButton only if you want the functionality of its 4 states.
Please be careful with the overloaded term "stage":
I checked that the button is correctly added to stage.
If you mean the "drawing area" that you can see in the Adobe Flash IDE or the main time line with "stage", then yes, you'd be correct that your button is added to that.
The stage property of DisplayObject however is something different. It's the top most element of the display list and the container that the instance of your Main class is added to, which happens at the start of the execution of your .swf in the FlashPlayer.
As your Main class adds the _button to itself by calling its ownaddChild(), the button is added to the instance of Main and not stage, which are two different objects.

How to finish animation with libgdx

I am trying to implement a simple animation with libGDX and I am currently stuck on one thing. Lets say I have a bunch of sprites which take some time to finish. For example, around 30 sprites like this link: https://github.com/libgdx/libgdx/wiki/2D-Animation
However, before the animation completes some key is pressed. For smooth animation I want the 30 frames to be completed before I start the next set of animation, to prevent an abrupt stop.
So my question is how do I achieve it this in libGDX? My current idea is to extend the Animation class, which would keep track of how frames I have and how many have been rendered and then display the rest. Or use the isAnimationFinished(float stateTime) function (though I haven't had luck using that).
The examples I have seen like superjumper have very few animations and don't really change that much.
Also, is there a way to hold the list of sprites from a TextureAtlas.createSprites method and use those with the Animation class? If not, whats the purpose of providing this function?
Thanks
You can use
animation.isAnimationFinished(stateTime);
To see if your animation is finished.
For the sprites : personnaly I use TextureRegion from a TextureAtlas and I store them in an array for my animation
I create a class AnimatedImage that extends Image to automate spriting in Image. My code will be like this:
public class AnimatedImage extends Image{
private Array<Array<Sprite>> spriteCollection;
private TextureRegionDrawable drawableSprite;
private Animation _animation;
private boolean isLooping;
private float stateTime;
private float currentTime;
public AnimatedImage(Array<Array<Sprite>> _sprites, float animTime, boolean _looping){
// set the first sprite as the initial drawable
super(_sprites.first().first());
spriteCollection = _sprites;
// set first collection of sprite to be the animation
stateTime = animTime;
currentTime = 0;
_animation = new Animation(stateTime, spriteCollection.first());
// set if the anmation needs looping
isLooping = _looping;
drawableSprite = new TextureRegionDrawable(_animation.getKeyFrame(currentTime));
this.setDrawable(drawableSprite);
}
public void update(float delta){
currentTime += delta;
TextureRegion currentSprite = _animation.getKeyFrame(currentTime, isLooping);
drawableSprite.setRegion(currentSprite);
}
public void changeToSequence(int seq){
// reset current animation time
resetTime();
_animation = new Animation(stateTime, spriteCollection.get(seq));
}
public void changeToSequence(float newseqTime, int seq){
_animation = new Animation(newseqTime, spriteCollection.get(seq));
}
public void setRepeated(boolean _repeat){
isLooping = _repeat;
}
public boolean isAnimationFinished(){
return _animation.isAnimationFinished(currentTime);
}
public void resetTime(){
currentTime = 0;
}
}
changetosequence method will make new Animation that will be used to update the current TextureRegionDrawable at the update method. resetTime will reset the total time for the animation when you call changeToSequence. You could add the event listener to call changeToSequence method.
Here is the example:
private AnimatedImage _img;
then I add the InputListener like this:
_img.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
_img.changeToSequence(1);
return true;
}
});
Hope it helps.
Use tween engine for this kind of animation. Its well documented and libgdx supports it .. Google about it , and you can find bunch of examples using libgdx .. Hope it will help you !!