I can get the coordinates of the touch just fine from:
event.getX();
event.getY();
But I want to start from an origin point of 0,0.
So I can touch anywhere on the screen, and as I drag my finger upwards, it will increase the Y by increments of 1, as I drag my finger to the right, the X will increase by increments of 1. Movement to the left will decrease the X by -1, movement downwards will decrease the Y by increments of -1.
Is there a mathematical way to do this, or better yet a class or function?
Any guidance would be appreciated! Thanks!
just use:
event.getRawX();
event.getRawY();
that results in screen coordinates,
starting at 0,0 (upper left corner)
to width,height (lower right corner)
depending on device, but i think thats not new to you ;)
--- update ---
I think I've missunderstood you, sorry..
then try this:
int saved_x = -1;
int saved_y = -1;
#Override
public boolean onTouchEvent(MotionEvent event)
{
final int action = event.getAction();
final int pointer_index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pid = event.getPointerId(pointer_index);
int x = (int)event.getX();
int y = (int)event.getY();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
saved_x = x;
saved_y = y;
break;
case MotionEvent.ACTION_MOVE:
int relative_x = x - saved_x;
int relative_y = y - saved_y;
//move right --> relative_x increases by 'm' pixels of movement
//move left --> relative_x decreases by 'm' pixels of movement
//move down --> relative_y increases by 'm' pixels of movement
//move up --> relative_y decreases by 'm' pixels of movement
//use it :D
break;
case MotionEvent.ACTION_UP:
saved_x = -1; //-1 indicates "no finger on screen" -- just a feature :)
saved_y = -1; //-1 indicates "no finger on screen" -- just a feature :)
break;
}
return true;
}
I hope this is now what you wanted :)
Related
The following code I wrote does what I want, a touch on the left or right side of the screen to move the sprite left or right and stop at the edge of the phone screen. The issue I'm having is when you do a fast motion of touching the right side of the screen, letting go while using another finger to touch the left side of the screen to change direction will yield a result of the sprite still moving to the right side of the screen despite you wanting to move left. In order to fix this, you need to let go completely for at least 0.5sec then press the other direction to start moving in that direction, which I don't want to have to live with. If anyone has any tips/help for this, please let me know!
MAIN ACTIVITY CLASS METHOD:
public boolean onTouchEvent(MotionEvent event){
int x = (int)event.getX();
switch(event.getAction()) {
case (MotionEvent.ACTION_DOWN):
CharacterSprite.touchedX = x;
break;
case (MotionEvent.ACTION_UP):
CharacterSprite.touchedX = 0;
break;
}
return super.onTouchEvent(event);
}
CHARACTERSPRITE CLASS METHOD:
public void update() {
if (touchedX != 0) {
if (touchedX < screenWidth / 2) {
if (!(xVelocity < 0)) {
xVelocity = xVelocity * -1;
}
if (!(x > 0)) {
touchedX = 0;
return;
}
x += xVelocity;
}
if (touchedX > screenWidth / 2) {
if (!(xVelocity > 0)) {
xVelocity = xVelocity * -1;
}
if (!(x < screenWidth - image.getWidth())) {
touchedX = 0;
return;
}
x += xVelocity;
}
}
}
The way you handling MotionEvent will not work for multitouch events. Each finger (action pointer) data stored as an array and you need to handle each entry separately. Here is the lesson on handling multitouch events:
https://developer.android.com/training/gestures/multi
I'm trying to develop my own game. But I have an issue with the onTouchEvent-Method. Little explanation before showing my code. I want to be able to control a flight with my finger. It Should always follow my finger. For that I implemented the MotionEvent.ACTION_MOVE case. The flight only can move on the left side of the screen. When I touch on the right side of the screen, it should shoot a bullet. And it should be possible to fly around and shoot simultaneously. Here is my Code:
public boolean onTouchEvent(MotionEvent event) {
int maskedaction= event.getActionMasked();
switch (maskedaction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getX() > screenX / 2 && flight.toShoot == 0) {
flight.toShoot++;
}
break;
case MotionEvent.ACTION_MOVE: {
if (event.getX() < screenX / 2 - 100) {
flight.x = (int) event.getX() - 100;
flight.y = (int) event.getY() - 50;
}
break;
}
}
return true;
}
So that's the code. When I touch the left half of the screen, I can fly around with the plane. When I Touch the right side, I can shoot. But I cannot do it at the same time. I want to touch first the left half and fly around. By clicking on the right side, at the same time as i'm moving my finger on the left side, it should shoot a bullet.
I found out that when I click at the same time on both sides with one finger, then the plane shoots one bullet. If i release now the right finger(the finger that shoots when it touches the screen) I can fly around and while I'm flying around I can shoot simultaneously.
You can detect your touch by detecting IDs, https://developer.android.com/training/gestures/multi
You can do something like this :
int leftSideId = 0;
int rightSideId = 1;
public boolean onTouchEvent(MotionEvent event) {
int maskedaction= event.getActionMasked();
// Get the pointer ID
int mActivePointerId = event.getPointerId(0);
switch (maskedaction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getX() > screenX / 2) {
rightSideId = mActivePointerId;
if(flight.toShoot == 0){
flight.toShoot++;
}
}else{
leftSideId = mActivePointerId;
}
break;
case MotionEvent.ACTION_MOVE: {
if (event.getX() < screenX / 2 - 100) {
if (mActivePointerId == leftSideId) {
flight.x = (int) event.getX() - 100;
flight.y = (int) event.getY() - 50;
}
}
break;
}
}
return true;
}
So I found a solution by myself.
public boolean onTouchEvent(MotionEvent event){
int amount=event.getPointerCount();
for (int i=0; i<amount; i++) {
float x = event.getX(i);
float y = event.getY(i);
if (x>screenX/2 && flight.toShoot==0){
flight.toShoot++;
}
if (x<screenX/2 -100 && flyingenabled)
{
flight.x = (int) x - 100;
flight.y = (int) y - 50;
}
}
return true;
}
Thats working for my problem. Easier than I thought.
I am trying to simulate a mouse click when a mousepad in the app is pressed and not moved.
if(isConnected && out!=null){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//save X and Y positions when user touches the TextView
initX =event.getX();
initY =event.getY();
mouseMoved=false;
break;
case MotionEvent.ACTION_MOVE:
disX = event.getX()- initX; //Mouse movement in x direction
disY = event.getY()- initY; //Mouse movement in y direction
/*set init to new position so that continuous mouse movement
is captured*/
initX = event.getX();
initY = event.getY();
if(disX !=0|| disY !=0){
out.println(disX +","+ disY); //send mouse movement to server
}
mouseMoved=true;
break;
case MotionEvent.ACTION_UP:
//consider a tap only if usr did not move mouse after ACTION_DOWN
if(!mouseMoved){
out.println(Constants.MOUSE_LEFT_CLICK);
}
}
}
return true;
}
});
}
I have tried this, but I can't figure out why it won't work. Every time I click on the mousepad the mouse moves. How can I solve this?
try it with an if-else and put the pressing first and the moving in the else-case.
I solved my problem by setting a margin.
int max = 2
int min = -2
case MotionEvent.ACTION_UP:
//consider a tap only if usr did not move mouse after ACTION_DOWN
if(disX <= max && disX >= min && disY <= max && disY >= min){
out.println(Constants.MOUSE_LEFT_CLICK);
mouseMoved=false;
break;
}
}
}
return true;
}
I have custom view control, which looks like this:
Inside my activity I want to be able to move this view around the screen by dragging it on green Arcs (left or right does not matter).
Also want to be able to detect if yellow arc at top is tapped, middle circle or bottom arc.
I'm having trouble to detect where the tap is in which area. This is the code that I'm using inside of my activity:
float dX, dY;
final MyCustomView myCustomView = (MyCustomView)findViewById(R.id.test);
final Boolean[] movable = {false};
myCustomView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
movable[0] = false;
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
int x = (int) event.getX();
int y = (int) event.getY();
if (myCustomView.leftArcRegion.contains(x,y) || myCustomView.rightArcRegion.contains(x,y)){
movable[0] = true;
} else if (myCustomView.topArcRegion.contains(x,y)){
//todo: do something if top arc area is selected
} else if (myCustomView.midRoundedBitmapRegion.contains(x,y)){
//todo: do something if mid bitmap area is selected
} else if (myCustomView.bottomArcRegion.contains(x,y)){
//todo: do something if bottom arc area is selected
}
break;
case MotionEvent.ACTION_MOVE:
if (movable[0]) {
view.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
default:
return false;
}
return true;
}
});
And these are public fields from my custom view control:
public Region topArcRegion;
private Path topArc;
//topArc is my top arc path
RectF rectFTop = new RectF();
topArc.computeBounds(rectFTop, true);
topArcRegion = new Region();
topArcRegion.setPath(topArc, new Region((int) rectFTop.left, (int) rectFTop.top,
(int) rectFTop.right, (int) rectFTop.bottom));
But it looks like it uses rectangular shapes for these regions, not arcs when checking with this "contains" method. And because of that I'm not getting expected results.
So, how can I detect where is initial tap (top arc, bottom arc, side arcs or middle bitmap) in order to apply my app logic?
Since you're only looking to detect touches inside an arc segment, it should't be too complicated.
Each of your arc segments is defined as the space between two concentric circles and between start and end angles. So all you really want to do is do a little trig to determine the distance from the center of the circles to your touch point and the angle from the center to your touch point.
float x = touchevent.getX();
float y = touchevent.getY();
// Transform relative to arc centers
x -= circle1.x;
y -= circle1.y;
double dist = Math.sqrt(x*x + y*y);
double angle = Math.atan2(y,x) * 180 / Math.PI;
// Given an arc segment defined by circle1, circle2, angle1, angle2:
boolean touch = dist > circle1.radius && dist < circle2.radius &&
angle > angle1 && angle < angle2;
You'll probably have to play around a bit depending on whether angle1 > angle2 or vice versa. If there's any chance that any of the angles cross the zero-degree angle, it gets a little trickier.
Meta: For clarity, I used sqrt() to compute distance, but you can optimize this code by skipping the sqrt() and compare distance² instead:
double dist2 = x*x + y*y;
if (dist2 > circle1.radius * circle1.radius &&
dist2 < circle2.radius * circle2.radius &&
...
One more edit: computing trig functions can be expensive; certainly a lot more expensive than computing distance².
In the interest of optimization, you should check the distance against the circle radii before bothering with the trig:
boolean touch = dist > circle1.radius && dist < circle2.radius;
if (touch) {
// This is only a *possible* touch, check the angles now
double angle = Math.atan2(y,x) * 180 / Math.PI;
touch = angle > angle1 && angle < angle2;
}
I have a touch listener that watches for ACTION_DOWN, ACTION_MOVE, and ACTION_UP.
I want to get the number of pixels moved, but I can't find anything in the documentation that allows this.
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
float x2 = motionEvent.getX();
float y2 = motionEvent.getY();
//Logging x2 and y2....
My log outputs pretty big numbers, even though I move very very slightly.
I try to move 1 pixel in either direction with my mouse pointer, but I get results like 42 for x and 75 for y. I'm guessing getX() and getY() do not respond with what I think they respond with.
EDIT:
public boolean onTouch(View v, MotionEvent motionEvent) {
float startX = 0;
float startY = 0;
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startX = motionEvent.getRawX();
startY = motionEvent.getRawY();
Log.e("resize", "action down");
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
Log.e("resize", "action move");
float movedX = motionEvent.getRawX() - startX;
float movedY = motionEvent.getRawY() - startY;
Log.e("", " movement "+movedX+" "+movedY+"");
getX() and getY() are coordinates of point on the view in which motion event was fired, calculated relatively to view's initial size and position. It means that if your view was rotated or scaled, these coordinates are recalculated using rotation and scale matrix.
To get absolute screen coordinates, you should use getRawX() and getRawY() instead.
To obtain vector at which finger moved from the starting point, first you need to remember point at which ACTION_DOWN event was fired:
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
startX = event.getRawX();
startY = event.getRawY();
}
Then, when finger moves, calculate movement coordinates relative to this starting point:
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE){
movedX = event.getRawX() - startX;
movedY = event.getRawY() - startY;
}