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
Related
How can the coords returned from GestureListener (TouchDown method for example) be converted into world-unit coords.
EG. My device screen is 1080p, my game is set up to use 540x960 (portrait).
In my current example project (code below) the paddle moves along x-axis twice as quickly as my finger, hence the position being set is given in screen-pixels.
Of course in this exact example, I could easily just divide it by 2 as I know the gameworld-units are exactly half of the device-pixels, however what if I wanted to make my world size 150x150 units --or if I was testing on a device with different screen sizes??
package com.moneylife.breakingass;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;
public class BreakingAss extends ApplicationAdapter {
SpriteBatch batch;
Sprite bgSprite, bgCoverSprite, menu1Sprite;
Paddle paddle;
enum ScreenState { StartScreen, PlayScreen, GameOverScreen }
ScreenState currentScreenState;
public int DeviceScreenWidth, DeviceScreenHeight;
public int WorldWidth = 540, WorldHeight = 960;
public OrthographicCamera camera;
int zAxis = 0;
MyGestureDetector myGestureDetector;
#Override
public void create () {
currentScreenState = ScreenState.StartScreen;
batch = new SpriteBatch();
DeviceScreenWidth = Gdx.graphics.getWidth();
DeviceScreenHeight = Gdx.graphics.getHeight();
myGestureDetector = new MyGestureDetector();
bgSprite = new Sprite(new Texture("bentoverass.jpg"));
bgCoverSprite = new Sprite(new Texture("half1080coverup.png"));
menu1Sprite = new Sprite(new Texture("menu1.jpg"));
menu1Sprite.setSize(WorldHeight * DeviceScreenWidth / DeviceScreenHeight,WorldHeight);
menu1Sprite.setPosition(0,0);
camera = new OrthographicCamera(WorldWidth, WorldHeight);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, zAxis);
camera.update();
paddle = new Paddle(WorldWidth, WorldHeight);
Gdx.input.setInputProcessor(new GestureDetector(myGestureDetector));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
paddle.update();
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (currentScreenState == ScreenState.StartScreen){
menu1Sprite.draw(batch);
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.draw(batch);
}
batch.end();
}
#Override
public void dispose () {
batch.dispose();
}
public class MyGestureDetector implements GestureDetector.GestureListener {
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
if (currentScreenState == ScreenState.StartScreen) {
if (x > 0) {
currentScreenState = ScreenState.PlayScreen;
}
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
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) {
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
return false;
}
#Override
public void pinchStop() {
}
}
}
Getting input coordinates always yields the coordinates of the screen. Logically because the input does not (need to) know about your game world. The camera is responsible for what is being drawn to the screen and the camera can be used to transform your screen coordinates to the coordinates of your world.
//Get screen coordinates
Vector3 mousePosition = new Vector3(Gdx.input.getX, Gdx.input.getY, 0);
//Transform to world coordinates using the correct camera
camera.unproject(mousePosition);
//The mousePosition vector is changed in the above method and now contains the game world coordinates of the camera you used.
PS.
For your paddle you can make a transform method so you can use the deltaX and deltaY in the pan method. Since the delta's hand you the change in "pan"there is no need at all to transform between screen and world.
By following Kilbolt's Zombie Bird tutorial I created in my project a class to represent all buttons:
public class SimpleButton {
private float x, y, width, height;
private TextureRegion buttonUp;
private TextureRegion buttonDown;
private Rectangle bounds;
private boolean isPressed = false;
public SimpleButton(float x, float y, float width, float height,
TextureRegion buttonUp, TextureRegion buttonDown) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.buttonUp = buttonUp;
this.buttonDown = buttonDown;
bounds = new Rectangle(x, y, width, height);
}
public boolean isClicked(int screenX, int screenY) {
return bounds.contains(screenX, screenY);
}
public void draw(SpriteBatch batcher) {
if (isPressed) {
batcher.draw(buttonDown, x, y, width, height);
} else {
batcher.draw(buttonUp, x, y, width, height);
}
}
public boolean isTouchDown(int screenX, int screenY) {
if (bounds.contains(screenX, screenY)) {
isPressed = true;
return true;
}
return false;
}
public boolean isTouchUp(int screenX, int screenY) {
// It only counts as a touchUp if the button is in a pressed state.
if (bounds.contains(screenX, screenY) && isPressed) {
isPressed = false;
return true;
}
// Whenever a finger is released, we will cancel any presses.
isPressed = false;
return false;
}
}
Whenever I want to create a button I do it in my InputProcessor class by creating a SimpleButton object and after filling its parameters I add it to List list.
My current problem is that I'm trying to create a sound button, which I did create and it work fine, but what I'm struggling with is making the button change TextureRegion between ON and OFF states.
This is an example of how I create a button(actually I created the sound button) and put it in the list:
soundButton = new SimpleButton(
136 / 2 - (AssetLoader.soundOnNotClicked.getRegionWidth() / 0.25f),
midPointY - 102, 15, 15, AssetLoader.soundOnNotClicked,
AssetLoader.soundClicked);
gameButtons.add(backButton);
I tried using the same condition that when sound ON is on it will put inside the parameters "AssetLoader.soundOnNotClicked" and when it's OFF "AssetLoader.soundOFFNotClicked", but it just show the first TextureRegion in the condition. Can someone help me figure out how I can change TextureRigions when sound is ON and OFF?
EDIT WITH CHANGES:
First created a second constractor:
public SimpleButton(float x, float y, float width, float height,
TextureRegion buttonUp, TextureRegion buttonDown, TextureRegion buttonOn) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.buttonUp = buttonUp;
this.buttonDown = buttonDown;
this.buttonOn = buttonOn;
bounds = new Rectangle(x, y, width, height);
}
Then changed a bit the isClicked method:
public boolean isClicked(int screenX, int screenY) {
if (isOn == false) {
isOn = true;
}else {
isOn = false;
}
return bounds.contains(screenX, screenY);
}
Then changed the draw method:
public void draw(SpriteBatch batcher) {
if (isPressed) {
batcher.draw(buttonDown, x, y, width, height);
} else {
if (isOn == false) {
batcher.draw(buttonUp, x, y, width, height);
}else{
batcher.draw(buttonOn, x, y, width, height);
}
}
}
Lastly I changed the creation of the button by adding the textureRegion of the OFF sound:
soundButton = new SimpleButton(
136 / 2 - (AssetLoader.soundButtonOff.getRegionWidth() / 0.25f),
midPointY - 102, 15, 15, AssetLoader.soundButtonOff,
AssetLoader.soundButtonOn, AssetLoader.soundButtonOffX);
menuButtons.add(soundButton);
Make another boolean called isOn just like isPressed
Add another TextureRegion called buttonOn just like buttonDown
Add TextureRegion buttonDown to your constructor and set it there like you do with buttonDown
Flip the boolean whenever the button is clicked in isClicked(). (isOn = !isOn)
Add the condition in your draw method to draw the buttonOn texture if isOn is true.
That should pretty much do it.
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;
}
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;
}
}
Im trying to add drag and drop functionality to several images in Libgdx. I have looked at this example: https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/DragAndDropTest.java but Its still not working. The images do not drag and drop. Would anyone be able to give me some pointers in why its not working?
Thanks
private void createButton() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
skin = new Skin();
skin.add("up", new Texture(Gdx.files.internal("assets/data/up.png")));
skin.add("def", new Texture(Gdx.files.internal("assets/data/Goal.png")));
final Image up = new Image(skin, "up");
up.setBounds(1090, 630, 40, 40);
stage.addActor(up);
Image def = new Image(skin, "def");
def.setBounds(1090, 585, 40, 40);
stage.addActor(def);
DragAndDrop dragAndDrop = new DragAndDrop();
dragAndDrop.addSource(new Source(up) {
public Payload dragStart (InputEvent event, float x, float y, int pointer) {
Payload payload = new Payload();
payload.setObject(payload);
payload.setDragActor(up);
payload.setDragActor(new Label("up", skin));
Label validLabel = new Label("up", skin);
validLabel.setColor(0, 1, 0, 1);
payload.setValidDragActor(validLabel);
return payload;
}
});
dragAndDrop.addTarget(new Target(def) {
public boolean drag (Source source, Payload payload, float x, float y, int pointer) {
getActor().setColor(Color.GREEN);
return true;
}
public void reset (Source source, Payload payload) {
getActor().setColor(Color.WHITE);
}
public void drop (Source source, Payload payload, float x, float y, int pointer) {
System.out.println("Accepted: " + payload.getObject() + " " + x + ", " + y);
}
});
render();
}
public void render () {
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
Table.drawDebug(stage);
}
I implemented your code on a project of mine.
I removed your render and used the one below. Also, you shouldn't need the assets/ prefix to your image import.
skin.add("up", new Texture(Gdx.files.internal("images/coin.png")));
skin.add("def", new Texture(Gdx.files.internal("images/coin.png")));
#Override
public void render(float delta) {
super.render(delta);
stage.draw();
stage.act(Gdx.graphics.getDeltaTime());
}
Another way to do drag in a better way...
public class CaveInterection implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture bgTexture;
private Sprite sprite;
private Stage stage;
private Texture mirrTexture;
private MyActor mirrorActor;
Sprite img1,img2;
#Override
public void create() {
camera = new OrthographicCamera(1024, 550);
camera.position.set(1024 / 2, 550 / 2, 0);
batch = new SpriteBatch();
stage = new Stage(1024, 550, false);
//bgTexture = new Texture(Gdx.files.internal("data/cave.jpg"));
//bgTexture = new Texture(Gdx.files.internal("data/bg.jpg"));
mirrTexture = new Texture(Gdx.files.internal("data/mirror.png"));
mirrTexture
.setFilter(TextureFilter.Linear, TextureFilter.Linear);
mirrorActor = new MyActor(new TextureRegion(mirrTexture));
mirrorActor.setPosition(700, 400);
mirrorActor.setOrigin(mirrorActor.getWidth()/2, mirrorActor.getHeight()/2);
stage.addActor(mirrorActor);
// finally stage as the input process
Gdx.input.setInputProcessor(stage);
}
#Override
public void dispose() {
batch.dispose();
//bgTexture.dispose();
}
#Override
public void render() {
// clear the screen, update the camera and make the sprite batch
// use its matrices.
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
//batch.draw(bgTexture, 0,0);
// Gdx.app.log("arvind","X :"+mirrorActor.getX()+ " Y :"+mirrorActor.getY());
//batch.draw(bgTexture, 0, 0);
batch.end();
// tell the stage to act and draw itself
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
public class MyActor extends Actor {
TextureRegion region;
float lastX;
float lastY;
public MyActor (TextureRegion region) {
this.region = region;
setWidth(region.getRegionWidth());
setHeight(region.getRegionHeight());
addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("arv", "pointer1+"+pointer);
// we only care for the first finger to make things easier
if (pointer != 0) return false;
// record the coordinates the finger went down on. they
// are given relative to the actor's corner (0, 0)
Gdx.app.log("arvind", "touchDown");
Gdx.app.log("arv", "pointer2+"+pointer+""+x+"::::"+y);
lastX = x;
lastY = y;
return true;
}
public void touchDragged (InputEvent event, float x, float y, int pointer) {
// we only care for the first finger to make things easier
if (pointer != 0) return;
Gdx.app.log("arv", "touchDragged");
// adjust the actor's position by (current mouse position - last mouse position)
// in the actor's coordinate system.
translate(x - lastX, y - lastY);
// rotate(2);
// save the current mouse position as the basis for the next drag event.
// we adjust by the same delta so next time drag is called, lastX/lastY
// are in the actor's local coordinate system automatically.
lastX = x - (x - lastX);
lastY = y - (y - lastY);
}
});
}
#Override
public void draw (SpriteBatch batch, float parentAlpha) {
//batch.draw(region, getX(), getY());
batch.draw(region, getX(), getY(), mirrorActor.getOriginX(), mirrorActor.getOriginY(), mirrorActor.getWidth(), mirrorActor.getHeight(), 1, 1,getRotation(), true);
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}