How do I detect if a sprite was touched in Java libGDX? - java

In the past few days I've been porting my game (Apopalypse) to the Android Mobile platform. I've did a quick search on Google of sprite touch detection but didn't find anything helpful. Each balloon will pop once touched and I just need to detect if it's touched.
Here's my balloon spawning code:
Rendering (x, y, width, and height are randomized):
public void render() {
y += 2;
balloon.setX(x);
balloon.setY(y);
balloon.setSize(width, height);
batch.begin();
balloon.draw(batch);
batch.end();
}
Spawning in main game class:
addBalloon(new Balloon());
public static void addBalloon(Balloon b) {
balloons.add(b);
}

in your class having the render method use can do following code:
Vector3 touchPoint=new Vector3();
void update()
{
if(Gdx.input.justTouched())
{
//unprojects the camera
camera.unproject(touchPoint.set(Gdx.input.getX(),Gdx.input.getY(),0));
if(balloon.getBoundingRectangles().contains(touchPoint.x,touchPoint.y))
{
// will be here when balloon will be touched
}
}
}

This is how I did it, but depending on the scene you are using and the elements that can be touched, there can be slightly more optimized ways of doing this:
public GameScreen implements Screen, InputProcessor
{
#Override
public void show()
{
Gdx.input.setInputProcessor(this);
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
float pointerX = InputTransform.getCursorToModelX(windowWidth, screenX);
float pointerY = InputTransform.getCursorToModelY(windowHeight, screenY);
for(int i = 0; i < balloons.size(); i++)
{
if(balloons.get(i).contains(pointerX, pointerY))
{
balloons.get(i).setSelected(true);
}
}
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button)
{
float pointerX = InputTransform.getCursorToModelX(windowWidth, screenX);
float pointerY = InputTransform.getCursorToModelY(windowHeight, screenY);
for(int i = 0; i < balloons.size(); i++)
{
if(balloons.get(i).contains(pointerX, pointerY) && balloons.get(i).getSelected())
{
balloons.get(i).execute();
}
balloons.get(i).setSelected(false);
}
return true;
}
public class InputTransform
{
private static int appWidth = 480;
private static int appHeight = 320;
public static float getCursorToModelX(int screenX, int cursorX)
{
return (((float)cursorX) * appWidth) / ((float)screenX);
}
public static float getCursorToModelY(int screenY, int cursorY)
{
return ((float)(screenY - cursorY)) * appHeight / ((float)screenY) ;
}
}

i made a little class that i use for my games to detect is Sprite is touched
public class SpriteTouchable extends Sprite {
public SpriteTouchable(Texture texture) {
super(texture);
}
public SpriteTouchable(Sprite sprite) {
set(sprite);
}
public static float xTrans(float x)
{
return x*Gdx.graphics.getWidth()/480;
}
public static float yTrans(float y)
{
return y*Gdx.graphics.getHeight()/320;
}
private boolean isTouched;
/**
* Type: Input Listener function
* listen if this sprite button was pressed (touched)
* #param marge : the extra touchable space out of sprite
* #param x : x position touched by user
* #param y : y position touched by user
*
* return true : Sprite touched
* return false : Sprite not touched
*/
public boolean isPressing(int marge,int x, int y) {
if((x>getX() -xTrans(marge))&& x<getX() +getWidth()+xTrans(marge)) {
if((y>getY() -yTrans(marge))&& y<getY()+getHeight()+yTrans(marge)) {
return true;
}
}
return false;
}
}
public boolean isTouched() {
return isTouched;
}
here how i use it
Gdx.input.setInputProcessor(new GameInputListener() {
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDown(int x, int yy, int pointer, int button) {
int y = Gdx.graphics.getHeight() - yy;
// if sprite + 10 of px marge is touched
if(mySpriteTouchable.isPressing(10, x, y)) {
// sprite is touched down
}
return false;
}
}
with the same logic you can detect sprite releasing and also you can customize it for effect size when the sprite is touched and more...
hope this was helpfull !

You have Gdx.input.getX() and Gdx.input.getY(). The X and Y coordinates of the last touch.
Just compare them with balloon frame.

You could add a tiny 1x1 pixel rectangle to your mouse and check if it intersects or contains other boxes. You do need to use boxes for all your objects you want to make clickable this way.

i have a simple solution
it's like that create a small rectangle 1 pixel by one pixel
Rectangle rect;
rect = new Rectangle(0, 0, 1, 1);
then make a method called
touching_checking();
in this method we will do three things
first check if screen is touched
second put the rectangle where you touch the screen
then at last check if your rectangle overlaps with the sprite rectangle.
like that
private void touching_checking() {
if (Gdx.input.isTouched()) {
rect.setPosition(Gdx.input.getX(), Gdx.input.getY());
if (rect.overlaps(back.getBoundingRectangle())) {
//do what you want here
}
}
}
i have an array of sprites called levels i check which one i pressed like that
private void touching_checking() {
if (Gdx.input.isTouched()) {
rect.setPosition(Gdx.input.getX(), Gdx.graphics.getWidth() - Gdx.input.getY());
for (int i = 0; i < levels.size; i++) {
if (rect.overlaps(levels.get(i).getBoundingRectangle())) {
//do what you want here
}
}
}
}

Here is what i use in my sprite class. I give it the vector where i clicked camera.unproject(new Vector3().set(x,y,0));. returns true if clicked in the area of the sprite.
/***
*
* #param v3 Vector with MouseClickPosition
* #return true if click was inside rectangle x --> x + width, y --> y +
* height
*/
public boolean clicked(Vector3 v3){
Rectangle rec = getBoundingRectangle();
if(v3.x >= rec.x && v3.x < rec.x + getWidth()){
if(v3.y >= rec.y && v3.y < rec.y + getHeight()){
System.out.println("click_on\t" + v3.x + ", " + v3.y);
return true;
}
else{
return false;
}
}
else{
return false;
}
}

Related

Libgdx - How to use "Long Press"?

I have tried finding an answer to solve the problem, but I think that I don't seem to understand how to use the long press in Libgdx.
I want my character to move right when I long press on the right half of the screen and left when I long press on the left half of the screen.
I have searched and tried.
Here is my InputHandler class :
public class InputHandler implements InputProcessor {
private MainCharacter myMainCharacter;
public InputHandler(MainCharacter mainCharacter) {
myMainCharacter = mainCharacter;
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
myMainCharacter.onClick();
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
And here is my MainCharacter class :
public class MainCharacter {
private Vector2 position;
private Vector2 velocity;
private Vector2 acceleration;
private float rotation;
private int width;
private int height;
public MainCharacter(float x, float y, int width, int height) {
this.width = width;
this.height = height;
position = new Vector2(x, y);
velocity = new Vector2(0, 0);
acceleration = new Vector2(0, 460);
}
public void update(float delta) {
velocity.add(acceleration.cpy().scl(delta));
if (velocity.y > 200) {
velocity.y = 200;
}
position.add(velocity.cpy().scl(delta));
}
public void onClick() {
if (Gdx.input.getX() <= 135) {
Gdx.app.log("TAG", "LEFT");
position.x--;
} else if (Gdx.input.getX() >= 137) {
Gdx.app.log("TAG", "RIGHT");
position.x++;
}
}
public float getX() {
return position.x;
}
public float getY() {
return position.y;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
public float getRotation() {
return rotation;
}
}
I used onClick() method as a replacement until I find a solution for the problem. It works fine but it doesn't have the same effect as the long press. My character moves left when I click on the left side of the screen and right when I click on the right side of the screen. But of course it doesn't work when I long press.
So how can I use 'Long Press' ?
I would really appreciate your help.
Gokul gives a nice overview of the GestureListener but I do not believe this is what you are looking for. LongPress indeed only registers after some seconds of pressing and you want to have a touch control the character immediately.
There is no out of the box method in the listeners to keep detecting touched but you can create it yourself.
if (Gdx.input.isTouched())
{
//Finger touching the screen
// You can actually start calling onClick here, if those variables and logic you are using there are correct.
if (Gdx.input.getX() >= screenSize / 2)
{
//Right touched
}
else if (Gdx.input.getX() < screenSize / 2)
{
//Left touched
}
}
Just check for this every frame and do your logic.
You can implement the long press by implementing the GestureListner interface.
GestureDetector will let you detect the following gestures:
touchDown: A user touches the screen.
longPress: A user touches the screen for some time.
tap: A user touches the screen and lifts the finger again. The finger must not move outside a specified square area around the initial touch position for a tap to be registered. Multiple consecutive taps will be detected if the user performs taps within a specified time interval.
pan: A user drags a finger across the screen. The detector will report the current touch coordinates as well as the delta between the current and previous touch positions. Useful to implement camera panning in 2D.
panStop: Called when no longer panning.
fling: A user dragged the finger across the screen, then lifted it. Useful to implement swipe gestures.
zoom: A user places two fingers on the screen and moves them together/apart. The detector will report both the initial and current distance between fingers in pixels. Useful to implement camera zooming.
pinch: Similar to zoom. The detector will report the initial and current finger positions instead of the distance. Useful to implement camera zooming and more sophisticated gestures such as rotation.
A GestureDetector is an event handler. To listen for gestures, one must implement the GestureListener interface and pass it to the constructor of the GestureDetector. The detector is then set as an InputProcessor, either on an InputMultiplexeror as the main InputProcessor:
public class MyGestureListener implements GestureListener{
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean zoom (float originalDistance, float currentDistance){
return false;
}
#Override
public boolean pinch (Vector2 initialFirstPointer, Vector2 initialSecondPointer, Vector2 firstPointer, Vector2 secondPointer){
return false;
}
#Override
public void pinchStop () {
}
}
You have to set the GestureDetector that contains your GestureListener as the InputProcessor:
Gdx.input.setInputProcessor(new GestureDetector(new MyGestureListener()));
For more details, check out the link below
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/input/GestureDetector.GestureListener.html

Rectangle Wall collision in Java

I really could use some help in order to find a working solution for my game.
My game is almost done, but the walls in my game are still not working as they should.
I have tried to find a solution on the internet for this problem, but i still haven't found a simple way to stop a rectangle just before it will collide with a wall (another rectangle).
Right now i have implemented a collision detection between the player rectangle and the wall rectangle and then stopped it to move, but then it gets stuck inside a wall when it hits.
Want it to stop just before, so it still can move. The code i have done this with so far is here:
Pacman Class
public class Pacman {
private String pacmanup = "pacmanup.png";
private String pacmandown = "pacmandown.png";
private String pacmanleft = "pacmanleft.png";
private String pacmanright = "pacmanright.png";
private int dx;
private int dy;
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image imageup;
private Image imagedown;
private Image imageleft;
private Image imageright;
public Pacman() {
ImageIcon i1 = new ImageIcon(this.getClass().getResource(pacmanup));
imageup = i1.getImage();
ImageIcon i2 = new ImageIcon(this.getClass().getResource(pacmandown));
imagedown = i2.getImage();
ImageIcon i3 = new ImageIcon(this.getClass().getResource(pacmanleft));
imageleft = i3.getImage();
ImageIcon i4 = new ImageIcon(this.getClass().getResource(pacmanright));
imageright = i4.getImage();
width = imageup.getWidth(null);
height = imageup.getHeight(null);
visible = true;
x = 270;
y = 189;
}
public int getDx() {
return dx;
}
public void setDx(int dx) {
this.dx = dx;
}
public int getDy() {
return dy;
}
public void setDy(int dy) {
this.dy = dy;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public Image getImageup() {
return imageup;
}
public Image getImagedown() {
return imagedown;
}
public Image getImageleft() {
return imageleft;
}
public Image getImageright() {
return imageright;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public boolean isVisible() {
return visible;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public void move() {
x += dx;
y += dy;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -2;
dy = 0;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 2;
dy = 0;
}
if (key == KeyEvent.VK_UP) {
dx = 0;
dy = -2;
}
if (key == KeyEvent.VK_DOWN) {
dx = 0;
dy = 2;
}
}
Here i have created a Rectangle getBounds method which i use to create an rectangle of the pacman and place an image over it.
Barrier class / Wall class
public class Barrier {
private String barrier = "barrier.png";
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image image;
public Barrier(int x, int y) {
ImageIcon ii = new ImageIcon(this.getClass().getResource(barrier));
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
visible = true;
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public void setVisible(Boolean visible) {
this.visible = visible;
}
public Image getImage() {
return image;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
This class also have the Rectangle getBounds class which i use to detect collision.
The last code i show is how i do the collision detection so far:
Code inside Board class
Rectangle r3 = pacman.getBounds();
for (int j = 0; j<barriers.size(); j++) {
Barrier b = (Barrier) barriers.get(j);
Rectangle r4 = b.getBounds();
if (r3.intersects(r4)) {
System.out.println("Wall hit");
pacman.setDx(0);
pacman.setDy(0);
}
}
Well, what i do, if there is a collision between r3 and r4, i gonna set Dx and Dy to 0.. what i want to find another solution so it detect for collision but i wont get stuck inside a wall, but i don't know how to :/
Hope someone will help.
There are two approaches you can follow. One is ugly but easier, the other one requires a deeper redesign of your classes.
1) Ugly/Simple Approach
In the ugly one, you keep moving your guy before doing the collision checks. Simply move your pacman back to the point where it was not stuck. You accomplish that by inverting the last directions used:
Code inside Board class
Change your reaction in case you find a collision: just walk the same distance, backwards.
if (r3.intersects(r4)) {
System.out.println("Wall hit, move back");
pacman.setDx(-pacman.getDx());
pacman.setDy(-pacman.getDy());
// Possibly need to call move() here again.
pacman.move();
break;
}
Ugly, but should work.
Not recommended to coding perfectionists with OCD and heart disease, though.
2) Redesign
In this approach, you test the position pacman will occupy before doing any actual moves. If that spot is not into any barrier, then perform the movement for real.
Code inside Pacman class
Add this method, so that you can check for collisions against the new bounds.
public Rectangle getOffsetBounds() {
return new Rectangle(x + dx, y + dy, width, height);
}
Code inside Board class
// Strip the call to pacman.move() prior to this point.
Rectangle r3 = pacman.getOffsetBounds(); // Check against the candidate position.
for (int j = 0; j<barriers.size(); j++) {
Barrier b = (Barrier) barriers.get(j);
Rectangle r4 = b.getBounds();
if (r3.intersects(r4)) {
System.out.println("Wall hit");
pacman.setDx(0);
pacman.setDy(0);
// Quit the loop. It's pointless to check other barriers once we hit one.
break;
}
}
// Now we're good to move only in case there's no barrier on our way.
pacman.move();
Particularly I prefer this approach, but it's up to you to pick the best one.

LibGDX: How to get the same coordinates in tiled map for tile with and without zoom

I am a beginner with LibGDX. I am trying to create an android game based fixed size tiled map (33x21 tiles). Tiles I am using are 32x32px. So far I managed to load the map created with Tiled and add touch gestures like zoom in/out and panning. The game character movement will be turn based tile by tile, so I need to have a possibility to select specific tile in order to perform some action. I tried solution from here: LibGDX: How to make tiled map tiles clickable? and it works perfectly fine, until the screen is not zoomed in.
Without zoom, the left-bottom corner coordinates shows that it is (0,0), which is correct. When I zoom in, the left-bottom corner of the visible part of the map instead of keeping it's correct coordinates (i.e. (480, 320)) it becomes (0,0) again. I tried to use camera.unproject(Vector3), but I was unsuccessful. Probably used it wrong. I am also not really convinced, that the way in which I try to get tiles is the most appropriate one. Can you help me get tiles coordinates properly? Below is the code that I am using:
public class TiledTest extends ApplicationAdapter {
public TiledMap tiledMap;
OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
GestureDetector gesture;
InputMultiplexer myInputMultiplexer;
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
public static final float PAN_RATE = (float) 0.01;
private static final float ZOOM_SPEED = (float) 0.009;
int columns, rows;
TiledMapTileLayer grid_layer;
#Override
public void create () {
gesture =new GestureDetector(new MyGestureListener());
myInputMultiplexer = new InputMultiplexer();
float unitScale = 1 / 32f;
camera = new OrthographicCamera();
camera.setToOrtho(true, 33,21);
tiledMap = new TmxMapLoader().load("tiled_map.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
grid_layer = (TiledMapTileLayer)tiledMap.getLayers().get(0);
Stage stage = new TiledMapStage(tiledMap);
myInputMultiplexer.addProcessor(gesture);
myInputMultiplexer.addProcessor(stage);
Gdx.input.setInputProcessor(myInputMultiplexer);
}
#Override
public void render () {
tiledMapRenderer.setView(camera);
tiledMapRenderer.render();
camera.update();
}
public class TiledMapActor extends Actor {
private TiledMapTileLayer.Cell cell;
public TiledMapActor(TiledMap tileMap, TiledMapTileLayer tiledLayer, TiledMapTileLayer.Cell cell) {
tiledMap = tileMap;
grid_layer = tiledLayer;
this.cell = cell;
}
}
public class TiledMapClickListener extends ClickListener {
private TiledMapActor actor;
public TiledMapClickListener(TiledMapActor actor) {
this.actor = actor;
}
#Override
public void clicked(InputEvent event, float x, float y) {
int a = (int) actor.getX();
int b = (int) actor.getY();
System.out.println(actor.cell + " has been clicked.");
System.out.println("x = " + a + "y = " + b );
}
}
public class TiledMapStage extends Stage {
private TiledMap tiledMap;
public TiledMapStage(TiledMap tiledMap) {
this.tiledMap = tiledMap;
for (MapLayer layer : tiledMap.getLayers()) {
TiledMapTileLayer tiledLayer = (TiledMapTileLayer)layer;
createActorsForLayer(tiledLayer);
}
}
private void createActorsForLayer(TiledMapTileLayer tiledLayer) {
for (int x = 0; x <= tiledLayer.getWidth(); x++) {
for (int y = 0; y < tiledLayer.getHeight(); y++) {
TiledMapTileLayer.Cell cell = tiledLayer.getCell(x, y);
TiledMapActor actor = new TiledMapActor(tiledMap, tiledLayer, cell);
actor.setBounds(x * tiledLayer.getTileWidth(), y * tiledLayer.getTileHeight(), tiledLayer.getTileWidth(),
tiledLayer.getTileHeight());
addActor(actor);
EventListener eventListener = new TiledMapClickListener(actor);
actor.addListener(eventListener);
}
}
}
}
public void resize(float width, float height) {
}
public class MyGestureListener implements GestureListener{
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
float effectiveViewportWidth = camera.viewportWidth * camera.zoom;
float effectiveViewportHeight = camera.viewportHeight * camera.zoom;
camera.position.x = MathUtils.clamp(camera.position.x, effectiveViewportWidth / 2f, 33 - effectiveViewportWidth / 2f);
camera.position.y = MathUtils.clamp(camera.position.y, effectiveViewportHeight / 2f, 21 - effectiveViewportHeight / 2f);
if (camera.zoom < 1) {
camera.translate(-deltaX * PAN_RATE, -deltaY * PAN_RATE, 0);
camera.update();
}
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
//Gdx.app.log("Text", "panstop");
return false;
}
#Override
public boolean zoom (float originalDistance, float currentDistance){
float ratio = originalDistance/currentDistance;
camera.zoom += ZOOM_SPEED * ratio;
if (camera.zoom < 0.3)
{
camera.zoom = (float) 0.3;
}
else if (camera.zoom > 1)
{
camera.zoom = 1;
}
System.out.println(camera.zoom);
return false;
}
#Override
public boolean pinch (Vector2 initialFirstPointer, Vector2 initialSecondPointer, Vector2 firstPointer, Vector2 secondPointer){
camera.zoom -= .01;
camera.update();
return false;
}
}
}
So you want to transfer the screen coordinates to world coordinates.
For example:
#Override
public void clicked(InputEvent event, float x, float y) {
Vector3 touch = new Vector3(x, y, 0);
camera.unproject(touch);
System.out.println("Screen coordinates translated to world coordinates: "
+ "X: " + touch.x + " Y: " + touch.y);
}
}
Above clicked function does not worked for me, but you led me to the answer. I dumped whole assigning actors for tiles and used camera.unproject in MyGestureListener in touchDown.
If someone is interested I just leave it here :)
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 temp_coord = new Vector3(x,y,0);
Vector3 coords = camera.unproject(temp_coord);
x =(int) coords.x;
y =(int) coords.y;
writerX = x;
writerY = y;
System.out.println("Screen coordinates translated to world coordinates: "
+ "X: " + x + " Y: " + y);
return false;
}

Issues with touchDragged on libgdx

below is my code which I am trying to add touchDragged, I am trying to use the drag method to make an object move left and right by using the touchDragged feature.
Problem is that when i swipe on the right side of the screen be it left or right swipe the object moves right only. when i swipe on the left side be it left or right the object moves left only.
is there something I am missing?
input class and below that the object class.
also is the Tilt action same as this or is that something different?
it will be nice if that can be explained.
Input class is as
public class Input implements InputProcessor
{
private Kame myKame;
public Input(Kame kame) {
myKame = kame;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
myKame.onClick();
return true; // Return true to say we handled the touch.
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
myKame.onClick();
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
myKame.onSwipe(screenX, screenY, pointer);
return true;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
and Kame class is as :
public class Kame
{
private Vector2 position;
private Vector2 velocity;
private Vector2 acceleration;
private int width;
private int height;
public float x;
public Kame(float x, float y, int width, int height) {
this.width = width;
this.height = height;
position = new Vector2(x, y);
velocity = new Vector2(0, 0);
acceleration = new Vector2(0, 460);
}
public void update(float delta) {
}
public boolean onSwipe(int velocityX, int velocityY, int delta) {
position.add(position.cpy().scl(delta));
// if (Math.abs(velocityX) < Math.abs(velocityY)) {
if (velocityX > 136) {
position.x += 3;//x cordinate
velocity.y += 10;
} else if (velocityX < 136) {
position.x -= 3;
velocity.y += 10;
} else {
// Do nothing.
}
// } else {
// Ignore the input, because we don't care about up/down swipes.
// }
return true;
}
public float getX() {
return position.x;
}
public float getY() {
return position.y;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
}
This call to onSwipe:
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
myKame.onSwipe(screenX, screenY, pointer);
return true;
}
does not seem to match this implementation of onSwipe:
public boolean onSwipe(int velocityX, int velocityY, int delta) {
There are a couple problems here.
The screenX and screenY parameters passed to touchDragged are screen coordinates. They range between 0 and the width (or height) of the screen. onSwipe says it expects a "velocity" (though the algorithm inside doesn't seem to treat it as such).
The pointer in the touchDragged signature is the id number of the cursor (think about using 4 fingers on a touchpad, the "pointer" identifies which finger is which). You're using is as a 'delta'.
You can probably just compare the screenX to pos.x, and add or subtract 3 from pos.x depending on if screenX is less than or greater than pos.x.
Computing an actual velocity will require tracking the change in location (which means keep track of the previous touch location), and then scaling it by the frame rate (the delta passed to render).
change the code from
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
myKame.onSwipe(screenX, screenY, pointer);
return true;
}
#Override
public boolean touchDragged(int screenX, int screenY, int button) {
myKame.onSwipe(screenX, screenY, pointer);
return true;
}
try that

touch scrolling with libgdx

I'm trying to implement touch scrolling in a libgdx game. I have a wide image that is a panorama of a room. I want to be able to scroll the image so the user can see around the room. I have it so that I can scroll a certain distance but when a new touchDragged event is registered the image is moved back to the original position.
This is how I'm implementing it
public class AttackGame implements ApplicationListener {
AttackInputProcessor inputProcessor;
Texture backgroundTexture;
TextureRegion region;
OrthographicCamera cam;
SpriteBatch batch;
float width;
float height;
float posX;
float posY;
#Override
public void create() {
posX = 0;
posY = 0;
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
backgroundTexture = new Texture("data/pancellar.jpg");
region = new TextureRegion(backgroundTexture, 0, 0, width, height);
batch = new SpriteBatch();
}
#Override
public void resize(int width, int height) {
cam = new OrthographicCamera();
cam.setToOrtho(false, width, height);
cam.translate(width / 2, height / 2, 0);
inputProcessor = new AttackInputProcessor(width, height, cam);
Gdx.input.setInputProcessor(inputProcessor);
}
#Override
public void render() {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(backgroundTexture, 0, 0, 2400, 460);
batch.end();
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
backgroundTexture.dispose();
}
}
And in the InputProcessor
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
cam.position.set(screenX, posY / 2, 0);
cam.update();
return false;
}
I got this far with help from this question LibGdx How to Scroll using OrthographicCamera?. However it doesn't really solve my problem.
I think the problem is with the touchDragged corodinates not being world coordinates but I have tried unprojecting the camera with no effect.
I have been struggling with this for a few weeks and I would really appreciate some help on this.
Thanks in advance.
I recently did something as what you want. This is my Input class that I use for move the map, you only need to change my 'stage.getCamera()' for your 'cam':
public class MapInputProcessor implements InputProcessor {
Vector3 last_touch_down = new Vector3();
...
public boolean touchDragged(int x, int y, int pointer) {
moveCamera( x, y );
return false;
}
private void moveCamera( int touch_x, int touch_y ) {
Vector3 new_position = getNewCameraPosition( touch_x, touch_y );
if( !cameraOutOfLimit( new_position ) )
stage.getCamera().translate( new_position.sub( stage.getCamera().position ) );
last_touch_down.set( touch_x, touch_y, 0);
}
private Vector3 getNewCameraPosition( int x, int y ) {
Vector3 new_position = last_touch_down;
new_position.sub(x, y, 0);
new_position.y = -new_position.y;
new_position.add( stage.getCamera().position );
return new_position;
}
private boolean cameraOutOfLimit( Vector3 position ) {
int x_left_limit = WINDOW_WIDHT / 2;
int x_right_limit = terrain.getWidth() - WINDOW_WIDTH / 2;
int y_bottom_limit = WINDOW_HEIGHT / 2;
int y_top_limit = terrain.getHeight() - WINDOW_HEIGHT / 2;
if( position.x < x_left_limit || position.x > x_right_limit )
return true;
else if( position.y < y_bottom_limit || position.y > y_top_limit )
return true;
else
return false;
}
...
}
This is the result: http://www.youtube.com/watch?feature=player_embedded&v=g1od3YLZpww
You need to do a lot more computation in the touchDragged callback, you can't just pass whatever screen coordinates were touched on to the camera. You need to figure out how far the user has dragged their finger, and in what direction. The absolute coordinates are not immediately useful.
Consider dragging down from the top-right or dragging down from the top-left. In both cases you want (I presume) to move the camera the same distance, but the absolute values of the screen coordinates will be very different in the two cases.
I think the simplest thing is to just track previousX and previousY (initialize them in the touchDown method. Then invoke cam.translate() with the delta (deltaX = screenX - previousX, for example), during touchDragged. And also update the previous* in touchDragged.
Alternatively, you can look at some of the fancier InputProcessor wrappers libgdx provides (see https://code.google.com/p/libgdx/wiki/InputGestureDetection).
Simple answer:
Declare 2 fields to hold the new and old drag location:
Vector2 dragOld, dragNew;
When just touched you set both of these equal to the touched location or your cam will jump.
if (Gdx.input.justTouched())
{
dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
dragOld = dragNew;
}
Update dragNew each frame and simply subtract the vectors from each other to get the x and y for translating the camera.
if (Gdx.input.isTouched())
{
dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
if (!dragNew.equals(dragOld))
{
cam.translate(dragOld.x - dragNew.x, dragNew.y - dragOld.y); //Translate by subtracting the vectors
cam.update();
dragOld = dragNew; //Drag old becomes drag new.
}
}
This is all I use to drag my ortho cam around, simple and effective.
Used drinor's answer but added the line on "touchDown) function so it doesn't reset the camera every time you start dragging again:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
last_touch_down.set( screenX, screenY, 0);
return false;
}
I have not used it myself, but I would start by looking at the code of:
Have you looked at the code of http://libgdx.l33tlabs.org/docs/api/com/badlogic/gdx/scenes/scene2d/ui/FlickScrollPane.html
See: touchDragged

Categories

Resources