Determining a fling from a pan in libgdx - libgdx

I'm developing a game with LibGDX and I'm having trouble determining a fling from a pan.
My GestureListener:
#Override
public boolean fling(float velocityX, float velocityY, int button) {
//if (velocityX > 1000f) {
// I can use this to exclude slow pans from the executing a fling
System.out.println("Flinged - velocityX: " + velocityX + ", button: " + button);
//}
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
// but there doesn't seem to be a way to have this not fire on a fling
System.out.println("Panned - deltaX: " + deltaX);
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
System.out.println("Pan Stop - pointer: " + pointer + ", button: " + button);
return false;
}
The problem is that if both pan and fling fire. I understand that a fling is basically a fast pan, but I need to be able to determine between the two gestures so I can handle each one separately.
A succinct way of asking is, how do I provide unique actions for fling and pan?

The most reasonable solution for this in my opinion is to use longPress to set some boolean flag to 'enter the panning mode' when swiping without long press will only be about making fling.
This is how I see this:
//the flag for checking if pan mode entered
boolean PAN = false;
#Override
public boolean longPress(float x, float y) {
PAN = true;
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
if(!PAN) {
System.out.println("Flinged - velocityX: " + velocityX + ", button: " + button);
}
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
if(PAN) {
System.out.println("Panned - deltaX: " + deltaX);
}
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
if(PAN) {
PAN = false;
System.out.println("Pan Stop - pointer: " + pointer + ", button: " + button);
}
return false;
}
Of course if the longPress is too long for your purposes you can change it by using setLongPressSeconds(float longPressSeconds) method of the GestureDetector instance

Related

how to drag a jpanel with graphics across the jframe

I have the following code for a constructor:
public Building(Graphics g, int xb, int yb, int wb, int lb,boolean chklocb, Point nwlocb) {
x=xb;
y=yb;
w=wb;
l=lb;
chkloc=chklocb;
nwloc=nwlocb;
if(chkloc){
x = (int)nwloc.getX();
y = (int)nwloc.getY();
//System.out.print(i);
}
else{
System.out.print("mhffffff");
}
g.setColor(Color.BLACK);
g.drawRect(x,y,w,l);
g.fillRect(x,y,w,l);
}
And I have tried using setLocation() to move it.
This only made it disappear.
This is how I tried to move it:
public void mouseDragged(MouseEvent e){
//pset=MouseInfo.getPointerInfo().getLocation();
//panel.setVisible(false);
if(panel.contains(MouseInfo.getPointerInfo().getLocation())){
contains=true;
}
if(contains){
//panel=new Building(getGraphics(),(int)ptrck.x,(int)ptrck.y,100,100,contains,pset);
//panel.Nwloc(pset);
// remove(panel);
// constraints.gridx=(int)pset.getX();
// constraints.gridy=(int)pset.getY();
// add(panel);
e.translatePoint(e.getComponent().getLocation().x-x, e.getComponent().getLocation().y-y);
panel.setLocation(e.getX(), e.getY());
z.prnt("testcontain");
}
}
How can I drag it?

How to check if Tree was hit or not in libgdx scene2d?

Basically all I want is to clear selection of the tree if user clicked not on the tree. My current code is:
entityTree.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
if (entityTree.getNodeAt(y) == null) {
entityTree.getSelection().clear();
}
}
});
But it doesn't work for two reasons:
clicked is only called if the tree is actually clicked. If click happens on some button or wherever else, the tree doesn't get a click event.
Current code checks only y-component. It should be combined with code that checks if tree boundaries are hit.
tree.getStage().addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (tree.getStage().hit(x, y, true) != tree || tree.getNodeAt(y) == null)
tree.getSelection().clear();
return false;
}
});

Fix touchDragged logic

What i want:
I want allow the user to drag and drop the actors he puts on the screen
1) An actor (32x32 pixel) can be put in a certain area defined by me (a centered rectangle 5x5, 32 pixel each cell)
2) The actors are snapped to an imaginary grid of the screen when added to the stage.
3) This snap to grid is needed also during the drag and drop
4) An actor can't be moved on another one
5) An actor must be rotated by 90 degrees when the user clicks on it
6) The actor can't be moved outside the bounds
What actually i get:
1) ok
2) ok
3) ok (with bugs)
4) not implemented yet
5) ok (with bugs)
6) not implemented yet
The bugs are:
1) The rotations is applied in any case. I don't want this behavior. I don't want to rotate an actor if the user is just doing drag and drop. (i know that this happens because i put this part of the code in the touchDown method)
2) This is hard to describe with my english, i'll try.
I put an actor and i can move it (when i say "move" i mean drag and drop).
I put a second actor and i can move it.
Now, if i try to move the first actor i put, the second one moves over the first (overlapping to it) and starts moving along with it!
Now the code:
Events in the GameStage
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
translateScreenToWorldCoordinates(screenX, screenY);
// check if the user clicked or not in the center area
if(!centerArea.contains(touchPoint.x, touchPoint.y)) {
return true;
}
// rotation
Iterator<Square> squareIterator = squares.iterator();
while(squareIterator.hasNext()) {
Square nextSquare = squareIterator.next();
if(nextSquare.getBounds().contains(touchPoint.x, touchPoint.y)) {
nextSquare.rotate();
return true;
}
}
// add an Actor
touchPoint.set(touchPoint.x - Constants.SQUARE_SIZE / 2, touchPoint.y - Constants.SQUARE_SIZE / 2, 0f);
float snapX = Math.round((touchPoint.x / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
float snapY = Math.round((touchPoint.y / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
Square square = new Square(snapX, snapY);
squares.add(square);
addActor(square);
return true;
}
public boolean touchDragged(int screenX, int screenY, int pointer) {
Vector3 newTouchPoint = new Vector3(screenX, screenY, 0f);
getCamera().unproject(newTouchPoint.set(screenX, screenY, 0f));
Square next = null;
Iterator<Square> squareIterator = squares.listIterator();
while(squareIterator.hasNext()) {
next = squareIterator.next();
if(next.getBounds().contains(newTouchPoint.x, newTouchPoint.y)) {
next.setX(newTouchPoint.x - Constants.SQUARE_SIZE / 2);
next.setY(newTouchPoint.y - Constants.SQUARE_SIZE / 2);
continue;
}
}
newTouchPoint.set(newTouchPoint.x - Constants.SQUARE_SIZE / 2, newTouchPoint.y - Constants.SQUARE_SIZE / 2, 0f);
float snapX = Math.round((newTouchPoint.x / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
float snapY = Math.round((newTouchPoint.y / Constants.SQUARE_SIZE)) * Constants.SQUARE_SIZE;
next.setX(snapX);
next.setY(snapY);
return true;
}
private void translateScreenToWorldCoordinates(int x, int y) {
getCamera().unproject(touchPoint.set(x, y, 0f));
}
Actor
public class Square extends GameActor {
private float rotation;
private ShapeRenderer shapeRenderer;
public Square(float x, float y) {
super(x, y);
shapeRenderer = new ShapeRenderer();
}
#Override
protected void initializeSprite() {
texture = new Texture(Gdx.files.internal(Constants.SQUARE_LOCATION));
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void updateBounds() {
bounds.setPosition(x, y);
}
public void rotate() {
rotation -= 90;
if(rotation <= -360) {
rotation = 0;
}
setRotation(rotation);
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
/*shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.RED);
shapeRenderer.rect(bounds.getX(), bounds.getY(), Constants.SQUARE_SIZE, Constants.SQUARE_SIZE);
shapeRenderer.end();*/
//batch.begin();
batch.draw(texture, x, y, texture.getWidth() / 2, texture.getHeight() / 2,
texture.getWidth(), texture.getHeight(), 1, 1, rotation, 0, 0, Constants.SQUARE_SIZE, Constants.SQUARE_SIZE, false, false);
}
}
I hope you can help me, i'm new to Libgdx, thank you.
UPDATE
I fixed the rotation bug moving its logic inside the touchUp method.

KeyUp/KeyDown is only caught once

I am trying to display a Dialog every time the keys BACK or SCAPE are pressed. However the event is only been caught once, dialog is shown but if I close it by pressing my button NO, then it will never appear again until I go to another screen.
This is how I catch the KeyUp event:
#Override
public boolean keyUp(int keycode) {
if (keycode == Keys.BACK || keycode == Keys.ESCAPE) {
dialog.setVisible(true);
}
return false;
}
This is my button inside of the Dialog:
btnNo.addListener(
new ClickListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
return true;
}
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
dialog.setVisible(false);
}
});
If you have any idea ,please let me know...
Check out the following site they have clear description on how to use Dialog in LibGDX http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Dialog.html
My issue has been resolved with the following block code in the Render():
if (Gdx.input.isKeyPressed(Keys.BACK) || Gdx.input.isKeyPressed(Keys.ESCAPE)){
Gdx.input.setCatchBackKey(true);
dialog.setVisible(true);
}

How to perform drag and drop operation on sprite fetched from array and present on screen ?

I want to perform drag and drop operation on these image.
How can i make it possible with the following code.
void storeLocation::changescene()
{
this->removeAllChildren();
//CCDirector::sharedDirector()->replaceScene(storeLocation::scene());
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
//CCScene* scene=CCScene::create();
storeLocation *layer = storeLocation::create();
CCSprite *k=CCSprite::create("background.png");
this->addChild(k,0);
k->setPosition(ccp(visibleSize.width/2+ origin.x, visibleSize.height/2 + origin.y));
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(storeLocation::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width ,
origin.y + pCloseItem->getContentSize().height/2));
pCloseItem->setScale(1.5);
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
this->addChild(pMenu, 1);
this->setTouchEnabled(true);
int l=5;
int posx=0,posy=0;
int count=0,r,j=-1,i=0,flag=0;
int x=20;
int b[30],a[30];
while(count<=5)
{
srand(time(0));
r=rand()%x+1;
flag=checktag(b,r,j);
if(flag==1)
{
b[i]=r;
i++;
count++;
j++;
}
}
int t;
CCObject* jt=NULL;
CCARRAY_FOREACH(images, jt)
{
// CCSize winSize = CCDirector::sharedDirector()->getWinSize();
//float i=winSize.width;
CCSprite *image = dynamic_cast<CCSprite*>(jt);
t=image->getTag();
for(i=0;i<l;i++)
{
if(t==b[i])
{
this->addChild(image);
image->setPosition(ccp(100+posx,100));
posx=posx+120;
}}}
To drag and drop images from one point to another on screen you have to use touch delegate methods
bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
Detect image on user touch in ccTouchBegan method, for this you can store all image objects in a array and check if touch is in rect of any image by using for loop.
To move the image with user touch change position of touched image(save touched image object in a global object) in ccTouchMoved.
And in ccTouchEnded method do whatever you want to do on droping image.
the easiest way to catch drag and drop events is by implementing the onTouchBegan and onTouchMoved and onTouchEnded methods like this:
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, sprite);
bool HelloWorld::onTouchBegan(Touch* touch, cocos2d::Event* event){
// this method is not needed but in order to implement the onTouchMoved you have to first implement onTouchBegan then the onTouchMoved
return true;
}
void HelloWorld::onTouchMoved(Touch* touch, cocos2d::Event* event){
if (sprite->getBoundingBox().containsPoint(touch->getLocation()))
{
sprite->setPosition(sprite->getPosition() + touch->getDelta());
}
}
void HelloWorld::onTouchEnded(Touch* touch, cocos2d::Event* event){
if (sprite->getBoundingBox().containsPoint(touch->getLocation()))
{
log("Sprite Drop Event");
}
}