I'm making a game where swiping and justTouched do different things. My problem is that when I swipe on the screen obviously the touchDown() method is also being triggered.
Im extending GestureAdapter:
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
//move when screen is touched
if(life == 1 && overlaps == false) {
timeState = 0;
velocity.y = -120;
velocity.x = 100;
}
return super.touchDown(x, y, pointer, button);
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
if(velocityX > 10)
//do something
return super.fling(velocityX, velocityY, button);
}
You should not use just touched in this case because when player touched first time you cant know will it be just touch or swipe.
You must use justtouched with touch up method like this
when player justtouched save touched coordinates.
Check coordinates when player touched up.
If distance between this 2 points less than 50 pixels (or what limit you want to set) then you can assume its justtouched otherwise its swipe and you can do calculations about swiping.
Related
I'm trying to close a dialog on background touch but it always goes in the else condition
stage.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if(stage.hit(x,y,true).equals(bg)) {
System.out.println("in th if");
dialog.addAction(rotateTo(90, .30f, Interpolation.smooth2));
dialog.hide();
}
else {
System.out.println("int the else");
}
return true;
}
});
I think this will work, but didn't test.
Dialog is already set up to receive all touchDown input while it's visible, even if the touch is outside its bounds, so simply give it a listener that hides it if the touch is outside its bounds:
dialog.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
if (x < 0 || x > dialog.getWidth() || y < 0 || y > dialog.getHeight()){
dialog.hide();
}
return true;
}
});
This assumes dialog is final or a member field so you can access it from the listener.
I think the reason your code doesn't work is that stage.hit(...) will always return the dialog regardless of coordinates since Dialogs are set up to absorb all input.
I just started a small project with libgdx and I noticed that the camera is lagging behind the mouse a bit. I am moving it like that: (I have cut out everything else)
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
screenXlast = screenX;
screenYlast = screenY;
if (button == Input.Buttons.RIGHT || pointer > 0) {
rightMouseKlicked = true;
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if (button == Input.Buttons.RIGHT) {
rightMouseKlicked = false;
}
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (rightMouseKlicked) {
gamecam.translate((screenXlast - screenX) * gamecam.zoom, (screenY -
screenYlast) * gamecam.zoom);
}
screenXlast = screenX;
screenYlast = screenY;
return false;
}
The game runs at 60fps but it seems like the output is delayed by a few frames. (the mouse cursor does not stay at the same position on the map while moving it around)
Is there an other way of doing it, so that the camera stays up with the mouse?
As far as I know, events in libgdx go into a stack. It is possible to receive the event a few ms after it actually happened.
You can see that if you draw an actor or a texture of the position of the touch dragged event - if you drag fast you will see that the drawn texture is always behind your mouse (or finder on phones).
As #Jankapunkt said, you can try multiplying the position by the delta time (Gdx.graphics.getDeltaTime()) but I am not sure that it will help
You are calculating the screen pixels moved, but not scaling to the size of your camera's viewport. Modify it as shown:
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (rightMouseKlicked) {
float scale = gamecam.zoom * gamecam.viewportWidth / (float)(Gdx.graphics.getWidth);
gamecam.translate((screenXlast - screenX) * scale , (screenY -
screenYlast) * scale );
}
screenXlast = screenX;
screenYlast = screenY;
return false;
}
Also keep in mind that a typical mouse's update rate is pretty low (about 10 FPS I think). If you find camera movement too jerky, you'll have to calculate mouse movement speed and extrapolate the mouse's position and add a smoothing algorithm on top of that. See here for discussion (3D but still generally applies).
public boolean touchDragged(int screenX, int screenY, int pointer) {
if(check) {
sprite.setPosition(screenX - sprite.getWidth() / 2, Gdx.graphics.getHeight() - screenY - sprite.getHeight() / 2);
rect.setPosition(screenX - sprite.getWidth() / 2, Gdx.graphics.getHeight() - screenY - sprite.getHeight() / 2);
}
return false;
}
this is my method in the my custom input processor class i use Input multiplexer in my main because i have 2 classes . Simultaneous drag won't move the sprite i can only move one sprite at a time.
My intention is to drag 2 sprites at the same time.
Thanks for your help and sorry for my bad English.
I don't know if this is the best approach, but a kinda-solution could be something like this:
1. Add a constant that let you know how many object you will allow to move at the same time:
private static final int MAX_TOUCHES = 4;
2. Add a collection with a fixed size, with this you'll manage all sprite that are currently being possible moving:
private final Array<Sprite> sprites = new Array<Sprite>(MAX_TOUCHES);
3. Now, in your class where you are handling touches, implement the touchDown(), touchDragged() and touchUp():
/**
* In the touchDown, add the sprite being touched
**/
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
// Just allow 4 sprites to move at same time
if(pointer >= MAX_TOUCHES) return true;
// Get the sprite at this current position...
Sprite sprite = getSpriteAtThisPosition(screenX, screenY);
// If sprite found, add to list with current pointer, else, do nothing
if(sprite != null) {
sprites.set(pointer, sprite);
}
return true;
}
getSpriteAtThisPosition() is just a method that return the first current sprite in that position, could return null.
/**
* In the touchDragged, move this sprite
**/
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
// Just allow 4 sprites to move at same time
if(pointer >= MAX_TOUCHES) return false;
// Get the sprite with the current pointer
Sprite sprite = sprites.get(pointer);
// if sprite is null, do nothing
if(sprite == null) return false;
// else, move sprite to new position
sprite.setPosition(screenX - sprite.getWidth() / 2,
Gdx.graphics.getHeight() - screenY -
sprite.getHeight() / 2);
return false;
}
/**
* In the touchUp, remove this sprite from the list
**/
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
// Just allow 4 sprites to move at same time
if(pointer >= MAX_TOUCHES) return true;
// remove sprite at pointer position
sprites.set(pointer, null);
return true;
}
The InputMultiplexer is not for dealing with two classes of object to move but to handle two input processors (or more) that you want to have - for example when you have more than one Stage and want to interact with player with each of them.
What you should do here would be to remember what pointer is attached to the touched object and then move it according to the pointer movement. The pointer is just id of for example finger enumerated from 0. So when you will touch screen with first finger it is 0 pointer, second one is 1 - BUT! If you will leave first finger keeping second the second is still 1 so it is perfect for this usage.
To handle remembering pointer id you also need to implement touchDown listener method
The code example would be like:
HashMap<Integer, Sprite> ids = new HashMap<Integer, Sprite>();
...
public boolean touchDown (int x, int y, int pointer, int button)
{
Sprite sprite = getSprite(x, y); //getSprite should iterate over all sprites in your game checking if x/y is inside one of them - you need to implement this one
ids.put(pointer, sprite);
return true;
}
public boolean touchUp (int x, int y, int pointer, int button)
{
ids.remove(pointer); //removing from hashmap
return false;
}
public boolean touchDragged (int x, int y, int pointer)
{
Sprite sprite = ids.get(pointer);
if(sprite != null)
{
sprite.setPosition... //and so on
}
return false;
}
For getting more information about multitouch handling you can check out this tutorial.
I want to drag an Actor around with the Mouse in LibGDX.
My code:
// overrides in the ClickListener
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
touching = true;
prevTouchPosition = new Vector2(x, y);
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchDragged(InputEvent event, float x, float y,
int pointer) {
dragging = true;
lastTouchPosition = new Vector2(x, y);
super.touchDragged(event, x, y, pointer);
}
#Override
public void touchUp(InputEvent event, float x, float y,
int pointer, int button) {
touching = false;
super.touchUp(event, x, y, pointer, button);
}
// the update method
#Override
public void act(float delta) {
super.act(delta);
if(dragging){
Vector2 diff = new Vector2(lastTouchPosition).sub(prevTouchPosition);
translate(diff.x, diff.y);
prevTouchPosition = new Vector2(lastTouchPosition);
dragging = false;
}
}
The more I move the Actor around the worse it gets.
The idea is to keep the last two Mouse positions and use the difference between them to update the position of the Actor.
Anything incremental like this is going to suffer from roundoff errors. Moreover, I think you don't need to update prevTouchPosition every frame; in the absence of roundoff errors, it should not be changing. Note that your code only works if the object is not rotated or scaled.
A more robust drag algorithm works as follows:
upon touch down, touch point L in object-local coordinates:
G := L
upon touch move, touch point L in object-local coordinates:
setPosition(toGlobal(L) - toGlobal(G) + getPosition())
Note that we never update G during the drag operation; it is used to remember the point on the object where it was "grabbed", and we continuously align the object so that this point is under the current touch. Here, toGlobal(L) - toGlobal(G) gives you the "delta" vector in global coordinates, which we add to the current position.
Note that I'm assuming there's no object hierarchy, so the current position is itself in global coordinates. Otherwise you'll need to take the parent's transform into account as well.
I'm using an actors with a stage as buttons. I can detect when touchDown/touchUp events occur just fine over the actor, but when the user taps on the actor and then proceeds to drag their finger off the actor, the touchUp event never fires. I tried to use the exit event instead, but it never fires. In my program the touchUp/touchDown events determine movement and also button color which depend on whether the button is being pressed or not. So I' left with a permanently "depressed" button until it's clicked down/up again.
Example of the code I'm using:
stage.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Actor actor = stage.hit(x, y, true);
if (actor != null){
System.out.println("touchDown: " + actor.getName().toString());
}
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
Actor actor = stage.hit(x, y, true);
if (actor != null){
System.out.println("touchUp: " + actor.getName().toString());
}
}
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor){
System.out.println("exit");
}
});
If you change
stage.addListener(new InputListener() {});
to
stage.addListener(new ClickListener() {});
it will recognize the TouchUp call. And it still will be able to handle the TouchDown, and Exit calls.
I had the same problem. I fixed it by creating boolean isDown variable as a field of my GameScreen class. Whenever touchDown occures on my background Image I make isDown variable true and when touchUp occures - isDown = false. That way touchUp will always occur. Then still in my GameScreen in render method i check if isDown is true, if it is, I check if the touch intersects with my actor:
if (isDown) {
if (pointIntersection(myActor, Gdx.input.getX(), Gdx.input.getY())) {
// do something
}
} else {
// reverse the effect of what you did when isDown was true
}
where pointIntersection method is:
public static boolean pointIntersection(Image img, float x, float y) {
y = Gdx.graphics.getHeight() - y;
if (img.x <= x && img.y <= y && img.x + img.width >= x && img.y + img.height >= y)
return true;
return false;
}
It's the only workaround I found to that. Still, it's not very pretty but works for me.