I have an actor called arrow that I want to repeat a sequence action to it.
This arrow points to an actor which if is clicked the arrow should fade out.
Here is my code:
Action moving = Actions.sequence(
(Actions.moveTo(arrow.getX(), arrow.getY() - 35, 1)),
(Actions.moveTo(arrow.getX(), arrow.getY(), 1)));
arrow.addAction(moving);
actor.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
arrow.addAction(Actions.fadeOut(1));
}
});
Code works fine but I want to repeat 'moving' action untile actor is clicked.
I read about RepeatAction in this question Cannot loop an action. libGDX but I didn't know how I can apply
You can use RepeatAction in this case, with Actions.forever():
final Action moving = Actions.forever(Actions.sequence(
(Actions.moveTo(arrow.getX(), arrow.getY() - 35, 1)),
(Actions.moveTo(arrow.getX(), arrow.getY(), 1))));
arrow.addAction(moving);
actor.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
// you can remove moving action here
arrow.removeAction(moving);
arrow.addAction(Actions.fadeOut(1f));
}
});
If you want to remove arrow from Stage after fading out, you can use RunnableAction:
arrow.addAction(Actions.sequence(
Actions.fadeOut(1f), Actions.run(new Runnable() {
#Override
public void run() {
arrow.remove();
}
}))
);
Related
I have a play button like this;
private void drawPlayButton() {
playButton = new ImageButton(new TextureRegionDrawable(playTexture), new TextureRegionDrawable(pressTexture));
stage.addActor(playButton);
playButton.setPosition(UIConstants.PLAY_X, UIConstants.PLAY_Y, Align.center);
playButton.addListener(new ActorGestureListener() {
#Override
public void tap(InputEvent event, float x, float y, int count, int button) {
super.tap(event, x, y, count, button);
game.setScreen(new GameScreen(game));
}
});
}
I want to add scale in and out effect to this button using Actions.
I am not that familiar with Actions,I tried something like this;
float duationsec= 0.5f;
playButton.addAction(Actions.sequence(Actions.scaleBy(0.2f,0.2f,duationsec),
Actions.scaleTo(1f, 1f, duationsec)));
img.setOrigin(Align.center);
stage.addActor(playButton);
But this is not giving any effect to the button also same code works for an Image.Is this because button uses drawable texture?
How can I give this effect to a button using Actions?
Also my code is working for one time only.I am calling it in show().If I call it in render(),it works in an abnormal manner.I want this effect to be displaying forever.
Is it possible to achieve this?
Any help would be appreciated.
For performance reason most scene2d.ui groups have transform set to false by default and ImageButton is part of that ui group so you've to enable transform by using setTransform(..) method.
For more detail you can check
https://github.com/libgdx/libgdx/wiki/Scene2d.ui#rotation-and-scale
float duationsec= 0.5f;
playButton.setOrigin(Align.center);
playButton.setTransform(true); // <-- Enable Transform
stage.addActor(playButton);
playButton.addAction(Actions.sequence(Actions.scaleBy(0.2f,0.2f,duationsec),Actions.scaleTo(1f, 1f, duationsec)));
EDIT
If you want to scale up/down on user Click, Do in this way :
playButton.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
playButton.addAction(Actions.sequence(Actions.scaleBy(0.2f,0.2f,duationsec),Actions.scaleTo(1f, 1f, duationsec), Actions.run(new Runnable() {
#Override
public void run() {
game.setScreen(new GameScreen(game));
}
})));
super.clicked(event, x, y);
}
});
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());
}
}
battleStage.addActor(aPlayer.handCard1);
aPlayer.handCard1.setPosition(300, -256);
aPlayer.handCard1.addAction(Actions.sequence(Actions.delay(0),
Actions.moveTo(300, 50, 1)));
aPlayer.handCard1.getChildren().items[1].addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
aPlayer.handCard1.getChildren().items[1].addAction(Actions.hide());
System.out.println("duh");
}
});
This is included in a method that is called in my render method.
It doesn't get Clicked. Nothing comes up in my console. I debugged the application and "items[1]" is actually there as a child. It's an Image and when I run the application the Image does show up.
Can anyone help? Thanks in advance!
edit
handCard1 is a Group with 2 Image children.
edit
I 'm doing battleStage.addActor(aPlayer.handCard1); in show()
and
aPlayer.handCard1.setPosition(300, 50);
aPlayer.handCard1.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
aPlayer.handCard1.getChildren().items[1].addAction(Actions.hide());
System.out.println("duh");
}
});
in render() and it's working.
Then I'm doing
aPlayer.handCard1.setPosition(300, 50);
aPlayer.handCard1.getChildren().items[1].setHeight(256);
aPlayer.handCard1.getChildren().items[1].setWidth(192);
aPlayer.handCard1.getChildren().items[1].addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
aPlayer.handCard1.getChildren().items[1].addAction(Actions.hide());
System.out.println("duh");
}
});
}
in render() and it's not working.
"This is included in a method that is called in my render method."
You should be adding your actors to the stage in the show() method rather than the render() method.
You need to use actor's setBounds() method set the boundaries for the click event to work. Please check
this link
Are you sure you are doing
Gdx.input.setInputProcessor(battleStage);
and
battleStage.act(delta);
I want to use scene2D, in libGDX, to detect click on object.
I have this simple Game sample :
Stage stage;
#Override
public void create()
{
this.stage = new Stage(1280, 720, true);
MyActor actor = new MyActor();
Gdx.input.setInputProcessor(stage);
actor.setTexture(new TextureRegion(new Texture(Gdx.files.internal("plateau.jpg"))));
actor.setScale(0.1f);
stage.addActor(actor);
actor.addListener(new InputListener()
{
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
System.out.println("down"+Math.random());
return true;
}
});
}
#Override
public void render()
{
stage.act();
stage.draw();
}
MyActor is a simple class extending Actor with a rendertexture.
The Event is working fine at start.
But when resizing the frame, while the Actor is streched as wanted, the coordinates of the click are not updated and thus misplaced.
How to make the stage using the new size of the items as base to the event ?
You need to update the viewport of your stage in resize method of your application like this:
public void resize(int width, int height) {
stage.setViewport(stage.getWidth(), stage.getHeight(), false, 0, 0, width, height);
}
What worked for me was similar to what mentioned above but you have to modify it slightly:
public void resize(int width, int height) {
stage.getViewport().update(width, height);
}
You shouldn't use the Gdx.graphics.width and height but really use what resize() is providing to you.
You have to use camera.project() method for this purpose I think.
camera.project(Vector3 worldPoint);
Does this works for you?
Hello I've been stuck on an issue for a while trying to create a simple game using the Libgdx framework.
I have a stage with a background Image actor and a stick figure image actor that is placed in the center of the stage.
I cant seem to understand, after reading many posts on stackoverflow and the libgdx wiki on event handling, how events such as fling and pan are passed to the actor to simply move it my stickman around the screen.
I would greatly appreciate any help or explanations on how exactly this works.
I just don't know how to get the integer values from pan and the velocity values from fling into my actor's Vector2 position variable so that it can move around every time the render method is called.
Here is some of my code:
My GestureDetection Class:
public class GestureDetection implements GestureListener{
public GestureDetection(){
}
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
System.out.println("tapped");
return false;
}
#Override
public boolean longPress(float x, float y) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2,
Vector2 pointer1, Vector2 pointer2) {
// TODO Auto-generated method stub
return false;
}
}
My Game class
public class Game implements Screen{
StickFlick game;
SpriteBatch batch;
Texture gameBackground;
Stage stage;
GestureDetector gd;
InputMultiplexer im;
WalkingEnemy testEnemy;
public Game(StickFlick game){
this.game = game;
testEnemy = new WalkingEnemy("basic", 100, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//enemy1.update(delta);
System.out.println("");
stage.act(Gdx.graphics.getDeltaTime());
batch.begin();
stage.draw();
batch.end();
}
#Override
public void resize(int width, int height) {
stage = new Stage(width, height, true);
stage.clear();
gd = new GestureDetector(new GestureDetection());
im = new InputMultiplexer(gd, stage);
Gdx.input.setInputProcessor(im);
Texture gameBackground = new Texture("data/gameBackground.png");
Image backgroundImage = new Image(gameBackground);
backgroundImage.setWidth(Gdx.graphics.getWidth());
backgroundImage.setHeight(Gdx.graphics.getHeight());
stage.addActor(backgroundImage);
stage.addActor(testEnemy.getImage());
stage.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(1)));
}
#Override
public void show() {
batch = new SpriteBatch();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
}
}
Ok, so at start you have to make some variables where you will keep X and Y coords of your stick man. Set some initial values to them, i.e. x should be half of screen width and y half of screen height to have your stick man at the center of the screen.
Then you have to use information you are getting in your GestureListener implementation to move your stick man, that is to change it's coordinates. Your current implementation does absolutely nothing - methods are empty, so when some gesture happens your code is not reacting to it.
So, you can i.e. inside of your pan method use deltaX and deltaY to change stick man coordinates for those values. Something like:
X+=deltaX;
y+=deltaY;
Or you can multiply deltaX and deltaY with some constant if you want faster or slower movement and/or multiply deltaY with -1 if movement is in opposite way from what you want it to be.
Or if you want to use fling use those variables that method provides - velocityX and velocityY - add them to you stick man x and y to move it.
So basically, you are always drawing stick man at x,y coords and from some method of GestureListener interface you implemented you should change stick man coords and make him move.