Touch events SDL2 on Android - android

I am developing a Tetris for Android using C++ taking advantage of SDL2 portability, the thing is that i have a lot of delays when i get events from the touch interface, is like the the function SDL_PollEvent() doesn't work like on PC, i have wrote this on my getting events method.
float x = 0, y = 0;
while (SDL_PollEvent(&event)){
switch (event.type) {
case SDL_QUIT: { gameState = false; break;}
case SDL_FINGERDOWN: {
x = event.tfinger.x;
y = event.tfinger.y;
SDL_Log("\nDesplazamiento x: %f desplazamiento y: %f.\n", x, y);
window.get_AbsPixels(&x, &y);
if (x >= keys->U.getX() && x <= (keys->U.getX() + keys->U.getW()) &&
y >= keys->U.getY() && x <= keys->U.getY() + keys->U.getH())
return Up;
if (x >= keys->D.getX() && x <= (keys->D.getX() + keys->D.getW()) &&
y >= keys->D.getY() && x <= keys->D.getY() + keys->D.getH())
return Down;
if (x >= keys->L.getX() && x <= (keys->L.getX() + keys->L.getW()) &&
y >= keys->L.getY() && x <= keys->L.getY() + keys->L.getH())
return Left;
if (x >= keys->R.getX() && x <= (keys->R.getX() + keys->R.getW()) &&
y >= keys->R.getY() && x <= keys->R.getY() + keys->R.getH())
return Right;
break;
}
default: break;
}
return None;
}
but when i debug my app on android the events act delayed despite they should have been returned and should be received before animation, so i guess if they are treated in another thread in Android or something because they act like independient to the animation.
Tried before with this:
float x = 0, y = 0, tmpx = 0, tmpy = 0;
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){ gameState = false; }
switch (event.type) {
case SDL_FINGERMOTION: {
tmpx = event.tfinger.dx;
tmpy = event.tfinger.dy;
window.get_AbsPixels(&tmpx, &tmpy);
x += tmpx; y += tmpy;
tmpx = tmpy = 0;
SDL_Log("\nDesplazamiento x: %f desplazamiento y: %f.\n", x, y);
break;
}
default: break;
}
if ((x > 70 || x < -70) || (y > 70 || y < -70))
return window.process_Dplcmnt(x, y);
}
return None;
..but it gave me also a lot of delays than the new one.
So to have it all clear and could act acording to, could someone explain me how the touch events should be processed using SDL on Android? Thanks in advance.

I already solve it, after every case:, even when no one fit on a condition there was always a returning so the pending events that didn't match kept there not flushing right, just moved the state return None; outside the while. Now it works like on PC.
float x = 0, y = 0;
while (SDL_PollEvent(&event)){
switch (event.type) {
case SDL_QUIT: { board->setGameState(false); break;}
case SDL_FINGERDOWN: {
x = event.tfinger.x;
y = event.tfinger.y;
SDL_Log("\nDesplazamiento x: %f desplazamiento y: %f.\n", x, y);
window.get_AbsPixels(&x, &y);
if (x > keys->U.getX() && x < (keys->U.getX() + keys->U.getW()) &&
y > keys->U.getY() && y < keys->U.getY() + keys->U.getH()) {
SDL_Log("\nRetornado Up\n");
return Up;
}
if (x > keys->D.getX() && x < (keys->D.getX() + keys->D.getW()) &&
y > keys->D.getY() && y < keys->D.getY() + keys->D.getH()) {
SDL_Log("\nRetornado Down\n");
return Down;
}
if (x > keys->L.getX() && x < (keys->L.getX() + keys->L.getW()) &&
y > keys->L.getY() && y < keys->L.getY() + keys->L.getH()) {
SDL_Log("\nRetornado Left\n");
return Left;
}
if (x > keys->R.getX() && x < (keys->R.getX() + keys->R.getW()) &&
y > keys->R.getY() && y < keys->R.getY() + keys->R.getH()) {
SDL_Log("\nRetornado Right\n");
return Right;
}
break;
}
default:
//SDL_PumpEvents();
//SDL_FlushEvent(SDL_FINGERDOWN);
break;
}
}
return None;

Related

Move an ImageView (or png resource) by using the accelerometer

I want to move an image over the screen by the accelerometer detection, but the only example I found on is something like this:
public void onSensorChanged(SensorEvent event){
float x = event.values[0];
float y = event.values[1];
if (Math.abs(x) > Math.abs(y)) {
if (x < 0) {
image.setImageResource(R.drawable.right);
textView.setText("You tilt the device right");
}
if (x > 0) {
image.setImageResource(R.drawable.left);
textView.setText("You tilt the device left");
}
} else {
if (y < 0) {
image.setImageResource(R.drawable.up);
textView.setText("You tilt the device up");
}
if (y > 0) {
image.setImageResource(R.drawable.down);
textView.setText("You tilt the device down");
}
}
if (x > (-2) && x < (2) && y > (-2) && y < (2)) {
image.setImageResource(R.drawable.center);
textView.setText("Not tilt device");
}
}
That code only displays a different image depends on the tilt of the phone, but I want to move the same image like "a ball into the screen".

LibGDX - InputProcessor - if user draggs finger from button which represents moving on X, to button which represents moving on Y

So, i am creating a joystic for a android game, so in my Touching class(implementing InputProcessor) it looks like a :
public class Touching implements InputProcessor{
int y = 0;
int x = 0;
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
x = Gdx.input.getX();
y = Gdx.input.getY();
if (x > 122 && x < 202 && y > 620 && y < 700 )
{
Core.player1.anmov(2); //button 1
}
if ( x > 122 && x < 202 && y > 520 && y < 600)
{
Core.player1.anmov(1); //button 2
}
if (x > 20 && x < 100 && y > 620 && y < 700)
{
Core.player1.anmov(3); //button 3
}
if (x > 222 && x < 302 && y > 620 && y < 700)
{
Core.player1.anmov(4); // button 4
}
return true;
}
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
x = Gdx.input.getX();
y = Gdx.input.getY();
if (x > 122 && x < 202 && y > 620 && y < 700)
{
Core.player1.anmov(7); // button 1
}
if ( x > 122 && x < 202 && y > 520 && y < 600)
{
Core.player1.anmov(8); // button 2
}
if (x > 20 && x < 100 && y > 620 && y < 700)
{
Core.player1.anmov(5); // button 3
}
if (x > 222 && x < 302 && y > 620 && y < 700)
{
Core.player1.anmov(6); // button 4
}
return false;
}
public boolean touchDragged(int screenX, int screenY, int pointer) {
x = Gdx.input.getX();
y = Gdx.input.getY();
return true;
}
so now, if i touch the button which represents moving on X, dragg to button which represents moving on Y, it is still moving on X, until i get my finger out of screen(the touchUP is calling), and then, it it standing, it does not move on Y..
Can anybody help me please? I think this is a very primitive, but i cant find a solution.
I would probably go for something like this in the player class update method itself
//Declare velocity on top so you just have to change this to fine tune speed.
float velocity = 10;
if (Gdx.input.isTouched()) //isTouched should register as long as a screen is touched, you can use pointers for multiple fingers.
{
if (touch within button) //just use Gdx.input.getX / Gdx.input.getY
{
position.X += velocity * Gdx.graphics.getDeltaTime();
{
//do for each button
}
Never used dragging for onscreen buttons myself but theoretically this should work since isTouched registers as long screen is touched. Gdx.input.getX/Y should update. You probably had something in there that only ran once and continued moving your player until a release was registered.

how can i use every devices screen on imageview.setontouchlistener with get x y positions?

This positions are works only 480x800 screens devices. But don't right works 1024x600 device. How can i fix it?
sinif = (ImageView) findViewById(R.id.imageSinif);
sinif.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
Toast.makeText(getApplicationContext(),"x= " +x + " y= " +y, Toast.LENGTH_SHORT).show();
if ((610 < event.getX() && event.getX() < 703)
&& (11 < event.getY() && event.getY() < 128)
&& deger == 0) {
// i want run any method in there. for example:
myAnimation.setVisibility(View.INVISIBLE);
sinif.setEnabled(false);
sinif.setVisibility(View.INVISIBLE);
sorulist.setVisibility(View.VISIBLE);
text1.setOnClickListener(dinle);
text2.setOnClickListener(dinle);
}
return false;
}
});
The problem is you are comparing value of touch X and Y with hard coded values say 601,703,11,128. But as android specification pixel value are device dependent so you need to convert it to device dependent size.
if ((convertSizeToDeviceDependent(610) < event.getX() && event.getX() < convertSizeToDeviceDependent(703))
&& (convertSizeToDeviceDependent(11) < event.getY() && event.getY() < convertSizeToDeviceDependent(128)) && deger == 0) {
// i want run any method in there. for example:
myAnimation.setVisibility(View.INVISIBLE);
sinif.setEnabled(false);
sinif.setVisibility(View.INVISIBLE);
sorulist.setVisibility(View.VISIBLE);
text1.setOnClickListener(dinle);
text2.setOnClickListener(dinle);
}
Put This Method in your Activity
public int convertSizeToDeviceDependent(int value) {
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
return ((dm.densityDpi * value) / 160);
}

Does a line contain a point

I want the user to be able to drag the edges of a square around the canvas. With my current solution it works but has glitches, sometimes an edge cannot be selected. Is there a clean way to tell if a line has been clicked (e.g. passes through a coordinate)? This is how I'm currently testing:
// check edge pressed, edge is the line between to
// coords e.g. (i) & (i = 1)
for (int i = 0; i < coords.size(); i++) {
p1 = coords.get(i);
if ((i + 1) > (coords.size() - 1)) p2 = coords.get(0);
else p2 = coords.get(i + 1);
// is this the line pressed
if (p1.x <= event.getX() + 5 && event.getX() - 5 <= p2.x && p1.y <= event.getY() + 5 && event.getY() - 5 <= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
} else if (p1.x >= event.getX() + 5 && event.getX() - 5 >= p2.x && p1.y >= event.getY() + 5 && event.getY() - 5 >= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
}
}
The code bellow //is this the line pressed is the most important and also most likely the issue. The +5 and -5 are used to give the use a larger area to click on.
Here is the whole on click event:
public void EditEdge() {
//TODO this works like shit
// Detect the two coordinates along the edge pressed and drag
// them
scene.setOnTouchListener(new View.OnTouchListener() {
private int startX;
private int startY;
private Point point1 = new Point(0, 0);
private Point point2 = new Point(0, 0);
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
startY = (int) event.getY();
Point p1;
Point p2;
// check edge pressed, edge is the line between to
// coords e.g. (i) & (i = 1)
for (int i = 0; i < coords.size(); i++) {
p1 = coords.get(i);
if ((i + 1) > (coords.size() - 1)) p2 = coords.get(0);
else p2 = coords.get(i + 1);
// is this the line pressed
if (p1.x <= event.getX() + 5 && event.getX() - 5 <= p2.x && p1.y <= event.getY() + 5 && event.getY() - 5 <= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
} else if (p1.x >= event.getX() + 5 && event.getX() - 5 >= p2.x && p1.y >= event.getY() + 5 && event.getY() - 5 >= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
}
}
break;
case MotionEvent.ACTION_UP:
point1 = new Point(0, 0);
point2 = new Point(0, 0);
// scene.setOnTouchListener(scene.editModeOnTouchListener);
break;
case MotionEvent.ACTION_MOVE:
for (Point p: new Point[] {
point1, point2
}) {
int modX = (int)(p.x + (event.getX() - startX));
int modY = (int)(p.y + (event.getY() - startY));
p.set(modX, modY);
}
SetCoords(coords);
startX = (int) event.getX();
startY = (int) event.getY();
break;
default:
return false;
}
return true;
}
});
}
So is there a easier way to tell is a line is clicked/ passes through a point or is that not the issue?
Thanks
use the line equation y = mx + b to find out if the point is on a line
float EPSILON = 0.001f;
public boolean isPointOnLine(Point linePointA, Point linePointB, Point point) {
float m = (linePointB.y - linePointA.y) / (linePointB.x - linePointA.x);
float b = linePointA.y - m * linePointA.x;
return Math.abs(point.y - (m*point.x+b)) < EPSILON);
}
Great piece of code by #tyczj !
I added a use-case to handle vertical lines, which gives me the following code fragment:
public boolean isPointOnLine(PointF lineStaPt, PointF lineEndPt, PointF point) {
final float EPSILON = 0.001f;
if (Math.abs(staPt.x - endPt.x) < EPSILON) {
// We've a vertical line, thus check only the x-value of the point.
return (Math.abs(point.x - lineStaPt.x) < EPSILON);
} else {
float m = (lineEndPt.y - lineStaPt.y) / (lineEndPt.x - lineStaPt.x);
float b = lineStaPt.y - m * lineStaPt.x;
return (Math.abs(point.y - (m * point.x + b)) < EPSILON);
}
}
Also a piece of code to check if a point lies on a line-segment:
public boolean isPointOnLineSegment(PointF staPt, PointF endPt, PointF point) {
final float EPSILON = 0.001f;
if (isPointOnLine(staPt, endPt, point)) {
// Create lineSegment bounding-box.
RectF lb = new RectF(staPt.x, staPt.y, endPt.x, endPt.y);
// Extend bounds with epsilon.
RectF bounds = new RectF(lb.left - EPSILON, lb.top - EPSILON, lb.right + EPSILON, lb.bottom + EPSILON);
// Check if point is contained within lineSegment-bounds.
return bounds.contains(point.x, point.y);
}
return false;
}
You could define 8 Rect to check against - the 4 sides and 4 corners (so you can move 2 edges at once). The lines of the edge should have a width for the touchable area.
Define a Point centred on your touch event, there are then methods for checking if a rect contains a point.

Android multitouch glitches

I've just made a quick system that has two joysticks (one for movement, one for shooting) and they work with multitouch.
However, when you use both at the same time they interfere with each other (You slow down, turn weirdly, etc) and am wondering whether this is an issue with my phone (Nexus One, 2.3.6) or an issue with the code:
public void handleEvent(MotionEvent event) {
final int action = event.getAction();
switch(action & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN: {
pointerID = event.getPointerId(0);
int tx = (int) event.getX(event.findPointerIndex(pointerID));
int ty = (int) event.getY(event.findPointerIndex(pointerID));
boolean reset = true;
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
reset = false;
}
}
if(reset) pointerID = -1;
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
if(pointerID == -1) {
final int pointerIndex = event.getActionIndex();
pointerID = event.getPointerId(pointerIndex);
int tx = (int) event.getX(pointerIndex);
int ty = (int) event.getY(pointerIndex);
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
}
}
}
break;
}
case MotionEvent.ACTION_MOVE: {
if(pointerID != -1) {
final int pointerIndex = event.findPointerIndex(pointerID);
int tx = (int) event.getX(pointerIndex);
int ty = (int) event.getY(pointerIndex);
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
}
}
}
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = event.getActionIndex();
final int id = event.getPointerId(pointerIndex);
if(id == pointerID) {
dy = 0;
dx = 0;
pointerID = -1;
}
break;
}
case MotionEvent.ACTION_UP: {
if(-1 != pointerID) {
dy = 0;
dx = 0;
pointerID = -1;
}
break;
}
}
}
Important notes:
Each joystick is a class, and the handleEvent method is called for each joystick.
pointerID is an int belonging to each joystick
dy and dx are just the distance from the center of the joystick.
What you are missing is that if there are multiple touches happening at the same time, that one MotionEvent contains them all (and if one of the touches is of the type ACTION_MOVE, it also contains a history of that movement).
Use a loop over event.getPointerCount() (if it is >1) as indexes to get ID's for each touchpoint, which you can then use to track the touch and get the touch's x/y/other information.
Now the thing to realise is that the pointerID not only tracks the touch ... but it also can change if a touch point goes away (finishing with an ACTION_UP event); a POINTER_DOWN event will always add that touch with an ID at the end (so if you have two touches it will get the ID 2), but on a POINTER_UP (or POINTER_2_UP if it''s the second touch point), the points with a higher ID change ID by moving down.
So if you have touches with ID 0, 1 and 2, and the second touch (ID 1) goes POINTER_UP, you have to realise that pointerID 2 will change into ID 1. And if you have two touches (0 and 1), if ID 0 goes up, all of the sudden ID 1 becomes ID 0!
The trick is to keep track of this with some global variables (leftJoyStickID and rightJoyStickID) and some code in action_down and action_up. With just two touchpoints, the ternary operator is your friend:
if (IDofActionUpEvent == leftJoyStickID)
{
rightJoyStickID = IDofActionUpEvent == 0 ? 1 : 0;
}

Categories

Resources