I have a float value that is set from 0 to 100, and I want to register a long click and update a Label progressivly, so that like every 0.25seconds the label's text will be updated. For now I am using a custom made Label that has a method to update the text displayed.
I tried using touchDown like this:
while (Gdx.input.isButtonPressed(Buttons.LEFT)) {
double currentValue = Double.parseDouble(Button.getText()
.toString());
if ((int) currentValue != 0)
currentValue--;
Button.updateText(Double.toString(currentValue));
}
but that doesn't seem to work, how do I update a label while a button is clicked?
Edit: Most of the code for the ClickListener:
#Override
public void enter(InputEvent event, float x, float y, int pointer,
Actor fromActor) {
super.enter(event, x, y, pointer, fromActor);
TextButtonStyle style = ButtonLower.getStyle();
style.font = red;
ButtonLower.setStyle(style);
}
#Override
public void exit(InputEvent event, float x, float y, int pointer,
Actor toActor) {
super.exit(event, x, y, pointer, toActor);
TextButtonStyle style = ButtonLower.getStyle();
style.font = white;
ButtonLower.setStyle(style);
}
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
System.out.println(event.toString());
double currentValue = Double.parseDouble(Button.getText()
.toString());
if ((int) currentValue != 0)
currentValue--;
Button.updateText(Double.toString(currentValue));
}
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
if (Gdx.input.isButtonPressed(Buttons.LEFT)) {
double currentValue = Double.parseDouble(Button.getText()
.toString());
if ((int) currentValue != 0)
currentValue--;
Button.updateText(Double.toString(currentValue));
}
return super.touchDown(event, x, y, pointer, button);
}
without knowing which of your classes implements your InputListener, it's a little hard to tell you exactly what to do to fix your problem. However, in the general sense what you probably want to do is have a boolean flag set to true on your touchDown method, set to false on your touchUp method, and then in some method that gets called every frame (act, draw, etc., depending on your implementation), youll want to update your text.
The code would look something like
private boolean flag = false;
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
if (button == Buttons.LEFT) {
flag = true;
}
//other stuff
return true; //or whatever you want
}
#Override
public boolean touchUp(InputEvent event, float x, float y,
int pointer, int button) {
if (button == Buttons.LEFT) {
flag = false;
}
//other stuff
return false; //or whatever you want
}
#Override
public void act(float delta) {
if (flag) {
double currentValue = Double.parseDouble(Button.getText()
.toString());
if ((int) currentValue != 0)
currentValue--;
Button.updateText(Double.toString(currentValue));
}
//other stuff
}
depending on your targetted audience, you may also have to deal with pointer id's in some way (this code example wont work if the user clicks on the label with two fingers, then releases one but not the other)
Related
I'm developing a game in libGDX and I want to add custom buttons. When the button is pressed, I want to add an action like scaleBy, because it looks better like that in Android. I made a class called Trigger which is an empty actor with a listener that add actions to the actor when the Trigger is pressed, entered, released, exited... So I create a Group with two actors: a TextButton (Touchable.disabled) and the Trigger.
It actually works but I have a problem: I can't add groups in Dialog's button method.
I think a better solution is creating a class which extends TextButton or Button, but I don't know how to do it.
If you want the code, just tell.
Thanks.
EDIT: I tried to make the class:
private Runnable runnable;
private UIScreen screen;
public static TextButtonStyle transformStyle(Skin skin) {
TextButtonStyle s = skin.get(TextButtonStyle.class);
TextButtonStyle style = new TextButtonStyle(s.up, null, null, s.font);
return style;
}
public static TextButtonStyle transformStyle(TextButtonStyle style) {
TextButtonStyle s = new TextButtonStyle(style.up, null, null, style.font);
return s;
}
public DTextButton(String text, Skin skin, UIScreen screen, Runnable runnable) {
super(text, transformStyle(skin));
this.runnable = runnable;
this.screen = screen;
addListener(new ButtonListener());
setOrigin(Align.center);
setTransform(true);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
}
public class ButtonListener extends ClickListener {
private boolean isPressed = false;
private int lastButton = 0;
public void press() {
screen.setButtonPressed(true);
UIFactory.applyPressedAction(DTextButton.this);
isPressed = true;
}
public void release(){
UIFactory.applyReleasedAction(DTextButton.this);
isPressed = false;
}
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if(button == Buttons.LEFT)
press();
return true;
}
#Override
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
lastButton = (Gdx.input.isButtonPressed(Buttons.LEFT)) ? Buttons.LEFT : -1;
if(pointer == 0 && !isPressed && screen.wasButtonPressed())
press();
}
#Override
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
if(toActor == DTextButton.this && lastButton == Buttons.LEFT){
Gdx.app.postRunnable(runnable);
}
if(pointer == 0 && isPressed)
release();
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
lastButton = button;
if(pointer == 0 && isPressed && button == Buttons.LEFT)
release();
screen.setButtonPressed(false);
}
}
UIScreen:
public interface UIScreen {
/**
* Return if any UI is pressed.
* #return return buttonPressed
*/
public boolean wasButtonPressed();
/**
* Set if any UI is pressed.
* #param pressed if pressed or not.
*/
public void setButtonPressed(boolean pressed);
}
UIFactory:
public static void applyPressedAction(Actor actor) {
actor.addAction(Actions.scaleBy(-0.2f, -0.2f, 0.2f, Interpolation.pow2Out));
}
public static void applyReleasedAction(Actor actor) {
actor.addAction(Actions.scaleBy(0.2f, 0.2f, 0.3f, Interpolation.swingOut));
}
So I only used style.up and I added the same Trigger's listener. The listener doesn't work well. Any suggestion?
I think you're over-complicating this. You can merely add an input listener to the button and make sure it's set to transform. And you probably want its origin centered. No need for subclasses or wrapper Groups or anything like that.
Also, you want to scale to, not by, to avoid error building up as you change states multiple times.
Here's a helper method:
public static void makeButtonScale (final Button button, final float hoverScale, final float pressedScale, final float duration){
button.setTransform(true);
button.addListener(new ClickListener(){
void scaleTo (float targetScale){
button.setOrigin(Align.center);
button.clearActions();
button.addAction(Actions.scaleTo(targetScale, targetScale, duration, Interpolation.fade));
}
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
super.touchDown(event, x, y, pointer, button);
scaleTo(pressedScale);
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
scaleTo(isOver() ? hoverScale : 1f);
}
public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) {
super.enter(event, x, y, pointer, fromActor);
scaleTo(isPressed() ? pressedScale : hoverScale);
}
public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) {
super.exit(event, x, y, pointer, toActor);
scaleTo(1f);
}
});
Example usage:
makeButtonScale(myDialogButton, 1.2f, 1.5f, 0.2f);
Note, this will not look very good unless you are using a linear mag filter on your texture atlas.
I'm building a GUI for my game with LibGDX.scene2d.ui and I have a problem when I'm trying to handle inputs. I have the following code to make something happen when button is pressed but it doesn't work:
enterButton.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent e, float x, float y, int p, int b) {
Gdx.app.log("touched", "down");
return true;
}
#Override
public void touchUp(InputEvent e, float x, float y, int p, int b) {
Gdx.app.log("touched", "up");
if(x > enterButton.getX() && x < enterButton.getRight() && y > enterButton.getY() && y < enterButton.getTop()) {
Gdx.app.log("cond", "cursor on actor");
if(validate(loginField.getText(), passField.getText())) {
Gdx.app.log("cond", "validated");
openMenu();
}
}
Gdx.app.log("untouched", "up");
}
});
But practically same code work correctly:
registerButton.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent e, float x, float y, int p, int b) {
return true;
}
#Override
public void touchUp(InputEvent e, float x, float y, int p, int b) {
if(x > registerButton.getX() && x < registerButton.getRight() && y > registerButton.getY() && y < registerButton.getTop()) {
registerWindow.setVisible(true);
baseWindow.setVisible(false);
}
}
});
After single click on the enterButton I'm getting this output made with LibGDX logging:
touched: down
touched: up
untouched: up
What can be wrong?
You can try using a ClickListener to check if the touch is within bounds or not, like so:
enterButton.addListener(new ClickListener() {
#Override
public void touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
if (isOver()) {
if(validate(loginField.getText(), passField.getText())) {
openMenu();
}
}
}
});
You can also try setting the debug flag on the Actor so that you can see where the click bounds actually are by using enterButton.debug();
I have a problem with using scene2d in libgdx. I can't find anywhere a method that allows me to check wheter the actor is touched or not. I can only find methods that told me if actor was touched or released. In my game, when actor is pressed and hold, some things should be done every frame, not only in one moment that I put my finger on it. I want to stop the things when I release my finger.
You can keep track of this in your InputListener. Create a boolean field isTouched, set to true when you get a touchDown, false when you get a touchUp. I use this method in my top-down shooter and it works very well.
you can check your input simply by do this in your render method
gdx.app.log("","touched"+touchdown);
firstly set the input processor..
Gdx.input.setInputProcessor(mystage);
then you can add input listener to your actor in the create method
optone.addListener(new InputListener() {
#Override
public void touchUp(InputEvent event, float x, float y,
int pointer, int button) {
boolean touchdown=true;
//do your stuff
//it will work when finger is released..
}
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
boolean touchdown=false;
//do your stuff it will work when u touched your actor
return true;
}
});
I had the similar problem and moreover I needed to know the current coordinates; So I resolved the issue something like this:
At first we extend the standard listener:
class MyClickListener extends ClickListener {
float x, y = 0;
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
this.x = x;
this.y = y;
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
this.x = x;
this.y = y;
super.touchDragged(event, x, y, pointer);
}
}
Then add an instance to the Actor:
class MyActor extends Actor {
private final MyClickListener listener = new MyClickListener();
MyActor() {
addListener(listener);
}
...
}
And in a draw (act) method use the following:
if (listener.getPressedButton() >= 0)
System.out.println(listener.x + "; " + listener.y);
In this image How can I use touchDragged to drag this in x axis only ??
This is my code to make this action:
iBtnDrag = new Image(tBtnDrag);
iBtnDrag.addListener(new ClickListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
iBtnDrag.setPosition(x, 448, Align.center);
}
});
you should create DragListener
...
float startX;
DragListener listener = new DragListener()
{
public void dragStart(InputEvent event, float x, float y, int pointer)
{
startX = x;
}
public void drag(InputEvent event, float x, float y, int pointer)
{
//x, y are delta from starting point so
iBtnDrag.setPosition(startX + x, 448, Align.center);
}
public void dragStop(InputEvent event, float x, float y, int pointer)
{
//when stopping drag
}
};
buuuut a way better would be to just create the Slider. To achieve it the best would be use skin mechanism
your skin file should be like for example:
com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle:
{
default-horizontal: { background: greenBackground, disabledBackground: sliderDisabled, knob: woodenKnob, disabledKnob: transparent },
},
and then you are creating slider like
music= new Slider(minValue, maxValue, stepSize, isVertical, skin);
music.setWidth( musicSiderWidth );
Slider allows you to get its value by calling
music.getValue();
which is actually very convenient
I want to make a method(addButton) that would all what's now done by the constructor, but taking some variables. Now i'm stuck cause there is an error which says that I need to make the boolean final, but I don't want to do that. How should I go about this?
Here is the code:
public void addButton(Table table,String key,boolean bool){
atlas=new TextureAtlas(Gdx.files.internal("buttons/buttons.pack"));
skin=new Skin(atlas);
buttonStyle.up=skin.getDrawable(key+".up");
buttonStyle.down=skin.getDrawable(key+".down");
button=new Button(buttonStyle);
button.addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
bool=true; //this boolean
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
bool=false; //and this
super.touchUp(event, x, y, pointer, button);
}
});
table1.add(button);
}
There are many ways to do it. If you just want to know if the button is pressed or not, you can use Button.isPressed(), because Button already keeps track of that.
If you want to do something else, you would be better off creating your own MyButton which extends Button. MyButton could have a field private boolean bool and add that ClickListener in the constructor. This click listener will then be able to access the field of the button via MyButton.this.bool and can change it.
public class MyButton extends Button {
private boolean bool;
public MyButton(...) {
addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
MyButton.this.bool=true;
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
MyButton.this.bool=false;
super.touchUp(event, x, y, pointer, button);
}
});
}
}
Another solution would be to keep your current setup, but wrap the primitive value in another class:
public class DataWrapper {
public boolean bool;
}
public void addButton(Table table,String key, final DataWrapper data) {
...
button=new Button(buttonStyle);
button.addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
data.bool=true;
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
data.bool=false;
super.touchUp(event, x, y, pointer, button);
}
});
table1.add(button);
}