I am trying to implement gestures on Actors in LibGdx using ActorGestureListener. The following code draws the actor, but the pan method is not called. Am I missing something?
I am using LibGdx 1.3.1.
public class MyApp extends ApplicationAdapter {
private Stage stage;
#Override
public void create() {
stage = new Stage(new ExtendViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()));
Gdx.input.setInputProcessor(stage);
final Shape circle = new Circle(); // Actor that draws a texture
stage.addActor(circle);
circle.addListener(new ActorGestureListener(){
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
Gdx.app.log("", "pan");
event.getTarget().moveBy(deltaX, deltaY);
}
});
circle.setTouchable(Touchable.enabled);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
}
If you inherit from Actor, you need to set the bounds or it will not be click/touch-able!.
Simply set the bounds to match the texture your Actor contains.
//add this Set bounds the x, y, width, and height
circle.setBounds(0, 0,texture.getWidth(),
texture.getHeight());
//add this Sets the origin position which is relative to the actor's bottom left corner.
circle.setOrigin(0, 0);
stage.addActor(circle);
Related
I'm designing a game that requires generating a vast array of buttons, with different combinations of background colors and outlines. I already have a Sprite for the background and a Sprite for the outline and apply tints to each.
I've already tried to join both on a SpriteBatch but have had no luck converting it to a structure that ImageButton supports.
Thanks in advance.
You could make your own version of an ImageButton by extending the Actor class and implementing your own methods for drawing. The example below isn't tested but should give you and idea on how to make your own Custom button:
private class LayeredButton extends Actor{
private int width = 100;
private int height = 75;
private Texture backGround;
private Texture foreGround;
private Texture outline;
public LayeredButton(Texture bg, Texture fg, Texture ol){
setBounds(this.getX(),this.getY(),this.width,this.height);
backGround = bg;
foreGround = fg;
outline = ol;
addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
// do something on click here
return true;
}
});
}
#Override
public void draw(Batch batch, float alpha){
// draw from back to front
batch.draw(backGround,this.getX(),this.getY());
batch.draw(foreGround,this.getX(),this.getY());
batch.draw(outline,this.getX(),this.getY());
}
#Override
public void act(float delta){
// do stuff to button
}
}
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());
}
}
I want an actor that draws a drawable, but clips it to the size of the actor. I'm deriving this class from Widget, and using some hard-coded values as a simple test:
public class MyWidget extends Widget {
public MyWidget(Drawable drawable) {
setDrawable(drawable);
setSize(100, 100);
}
public void draw(Batch batch, float parentAlpha) {
clipBegin(getX(), getY(), 20, 20);
drawable.draw(batch, getX(), getY(), 500, 500);
clipEnd();
}
}
No clipping is performed though, the drawable spills out of the bounds of the actor. This actor is part of a Table, if it matters. I believe I am using the clipBegin() / clipEnd() methods incorrectly. What is the right way to do this?
Thanks
This is what I found based on the comments and my own experimentation. It's important to flush the batch before starting the clip and after drawing to ensure the proper drawing gets clipped.
public void draw(Batch batch, float parentAlpha) {
batch.flush();
if (clipBegin(getX(), getY(), 20.0f, 20.0f)) {
//do your drawing here
drawable.draw(batch, getX(), getY(), 500, 500);
batch.flush();
clipEnd();
}
}
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.