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;
}
this problem is driving me up the wall. I'm sure I'm doing something wrong but I can't figure it out.
I have a static OnTouchListener which I attach to the TextView of a number of identical compound view objects contained within a linearlayout. This listener is in a helper class.
public static View.OnTouchListener getValueTouchListener() {
return new View.OnTouchListener() {
private int lastY;
private int lastX;
#Override
public boolean onTouch(View v, MotionEvent event) {
TextView view = (TextView)v;
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
view.setBackgroundResource(R.drawable.cog_pressed);
lastY = (int)event.getY();
lastX = (int)event.getX();
return true;
case MotionEvent.ACTION_MOVE:
//calc size of movement
int deltaY = lastY - (int)event.getY();
int deltaX = lastX - (int)event.getX();
// pass gesture up to parent if it's a big x movement - assumes user wishes to scroll parent
if (Math.abs(deltaX) > TOUCH_SLOP *2) {
return false;
}
lastX = (int)event.getX();
//process movement if larger than a touch slop
if (StrictMath.abs(deltaY) > TOUCH_SLOP) {
// reset last touch position
lastY = (int)event.getY();
//get direction of movement
int dir = (deltaY < 0)? -1 : 1;
//change index if within min and max limits
int min = (view.getTag() == Chainring.KEY)? Chainring.MIN_COG : Sprocket.MIN_COG;
int max = (view.getTag() == Chainring.KEY)? Chainring.MAX_COG : Sprocket.MAX_COG;
int value = Integer.valueOf(view.getText().toString());
if ((dir == -1 && value > min) || (dir == 1 && value < max)) {
value = value + dir;
view.setText(String.valueOf(value));
view.playSoundEffect(SoundEffectConstants.CLICK);
}
}
return true;
case MotionEvent.ACTION_UP:
view.setBackgroundResource(R.drawable.cog_unpressed);
return true;
case MotionEvent.ACTION_CANCEL:
view.setBackgroundResource(R.drawable.cog_unpressed);
return false;
default:
return false;
}
}
};
}
I hook up this listener to my TextView in a class that extends linear layout
mValueTextView.setOnTouchListener(CogPickerHelper.getValueTouchListener());
My problem is the method doesn't seem to execute the return command in the ACTION_DOWN, ACTION_UP and ACTION-MOVE cases. For example, with an ACTION_DOWN, the code executes as far as the return command but then steps directly to the default case and returns false - even though Logcat still reports the action as being ACTION-DOWN.
If I try to set a breakpoint on the return commands, IntelliJ says: "No executable code found at line X in class com.amb.GearBuddyV2.views.CogPickerHelper$2"
Does anyone know what I'm doing wrong here?
Your code seems to be working fine, the OnTouch return value is being returned correctly.
And yes, adding a break at a return statement will lead the debugger to complain about missing executable code.
onTouch method of my View:
public boolean onTouch(View view, MotionEvent event) {
Log.d("Touch", "Touch");
int mNewX = (int) Math.floor(event.getX());
int mNewY = (int) Math.floor(event.getY());
boolean isPositionFree = isPositionFree(mNewX, mNewY);
if (!isPositionFree) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
invalidate();
break;
}
i++;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
Point p = new Point(mNewX, mNewY, point.TYPE);
points.add(i, p);
invalidate();
break;
}
i++;
}
}
}
}
There are multiple items in the canvas. Their positions are saved in "points". They get drawn to the canvas in a onDraw method via the position of those "points", means Point point.x and point.y.
Now, when I click an item (a point on the canvas), it should disappear.
Then, when the MotionEvent.ACTION_MOVE is true, I want to move the point, depending on the event.getX() and event.getY().
the method "isPositionFree(newX,newY)" checks if the point.x and point.y equals newX and newY (the position I just touched on the screen).
if the position is taken (means, there is an item where I just clicked), I'll get to the motionevent-IFs.
Here comes the problem:
my code removes the point before I can actually move it. I didnt find any way I could fix this problem for hours. :/ I find it difficult, since the onTouch is always called from the beginning, means ACTION_DOWN and ACTION_MOVE never take place at the same time.
Do you know any fix for this?
thanks in advance, Sebastian
Got it to work!
For everbody having the same issue, feel free to take this sample code as a help :)
Stuff I declared in the beginning
Vector<Point> points = new Vector<Point>();
Bitmap[] monsterTypes = new Bitmap[3];
Vector<Integer> distanceMovedX = new Vector<Integer>();
Vector<Integer> distanceMovedY = new Vector<Integer>();
int mNewX = -1;
int mNewY = -1;
OnTouch-Method
public boolean onTouch(View view, MotionEvent event) {
mNewX = (int) FloatMath.floor(event.getX());
mNewY = (int) FloatMath.floor(event.getY());
boolean touchedPoint = touchedPoint(mNewX, mNewY);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
distanceMovedX.add(mNewX);
distanceMovedY.add(mNewY);
break;
case MotionEvent.ACTION_UP:
isMoveEvent = isMoveEvent();
if (isMoveEvent) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
i++;
}
} else {
if (touchedPoint) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
}
}
}
distanceMovedX.clear();
distanceMovedY.clear();
return true;
}
return true;
}
touchedPoint-Method
public boolean touchedPoint(int mNewX, int mNewY) {
boolean touchedPoint = false;
int height = 0;
int width = 0;
for (Point point : points) {
height = monsterTypes[point.TYPE - 1].getHeight();
width = monsterTypes[point.TYPE - 1].getWidth();
if (point.x + width < mNewX || point.x > mNewX + width
|| point.y + height < mNewY || point.y > mNewY + height) {
touchedPoint = false;
point.spotted = false;
} else {
touchedPoint = true;
point.spotted = true;
return touchedPoint;
}
}
return touchedPoint;
}
isMoveEvent-Method
public boolean isMoveEvent() {
boolean isMoveEvent = false;
boolean isMoveEventX = false;
boolean isMoveEventY = false;
for (int i = 0; i <= (points.size() -1); i++) {
Log.d("point", "for loop entered");
if (!distanceMovedY.isEmpty()) {
Log.d("point.x", "distanceMovedY is not empty");
int dMY = distanceMovedY.get(distanceMovedY.size() - 1) - distanceMovedY.get(0);
if ((dMY > 50 || dMY <= 0) && dMY != 0) {
Log.d("point.y", "is move event");
Log.d("point.y", "dMY: " + dMY);
isMoveEventY = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMY: " + dMY);
isMoveEvent = false;
return isMoveEvent;
}
}
if (!distanceMovedX.isEmpty()) {
Log.d("point.x", "distanceMovedX is not empty");
int dMX = distanceMovedX.get(distanceMovedX.size() - 1) - distanceMovedX.get(0);
if (dMX <= 50 && dMX >= -50 && dMX != 0) {
Log.d("point.x", "is move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEventX = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEvent = false;
return isMoveEvent;
}
}
if (isMoveEventX && isMoveEventY) {
Log.d("point", "is move event");
isMoveEvent = true;
return isMoveEvent;
}
}
Log.d("point", "is no move event");
return isMoveEvent;
}
Point Class
class Point {
int x, y;
int TYPE;
boolean spotted;
boolean halfSpotted;
public Point() {
}
public Point(int x, int y, int t) {
this.x = x;
this.y = y;
this.TYPE = t;
}
#Override
public String toString() {
return x + ", " + y;
}
}
EXPLANATION:
Point:
we got a class Point. All those points declared in the Vector are x- and y-coordinates on your canvas. They help us to check the position we clicked.
monsterTypes:
its the different graphics I use. If you only use one graphic that you draw onto the canvas, change it to your needs
distanceMovedX & Y:
saves all the X and Y Coordinates of your "ACTION_MOVE". From pos 0 (the first touched point) to pos Z (the last touched point, where ACTION_UP occurs). Though its not the original X and Y position. Its the result of posZ - pos0.
With these values you can determine, after what distance travelled you wanna invoke "onMove" and BELOW which distance "onClick" should be invoked.
mNewX & Y:
the currently position of your onTouch-Method. Everytime you move your finger, newX & Y become overwritten.
Methods:
onTouch():
First, we'll overwrite mNewX and Y to the current position touched. Then we check if we clicked on an existing spot (in my case some 48px*48px area)
Next we record the taken distance in ACTION_MOVE.
After that we continue with ACTION_UP, where we check if we just performed some moveEvent or clickEvent.
touchedPoint():
calculates if we touched some existing point on the canvas, or not. returns true or false
isMoveEvent():
checks if we moved the certain distance. in my case i wanna move down, 50px or more. though im not allowed to move sidewards -50px or +50px. If its NOT a move event, the last spot touched still has to be on the in the giving distance (in my case in the 48px*48px range of the point).
Thats it. took me days to only figure out that option ;/ ashamed of that ... though I coded it pretty fast, what makes me feeling better again :D
I'm just suggesting some walk-around :
Instead of removing the point when clicking it,
make a privata Point in your class, where you currently remove the point, just set your new Variable Point to the Point you would remove...
Then, after using it in action or action move, the last place you would use it,
check if your private variable is not null, if so, remove it, then, set it to null.
try using a switch case statement:
switch finger_action:
case(ACTION_MOVE)
{
//move code
return false;
}
case(ACTION_TOUCH)
{
//dissappear code
return false;
}
note the up above code is pseudo code, but what it does it checks to see if you are moving the dot before just touching it. this way the dot will attempt a move first instead of being removed first.
thanks,
Alex
here is my code now:
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
switch(action)
{
case MotionEvent.ACTION_DOWN:
// Do click work here ...
Y -= 10;
Yopen = 1;
break;
case MotionEvent.ACTION_UP:
// Do release work here ...
Yopen = 0;
break;
}
return super.onTouchEvent(event);
}
But I want to make only three different areas to perform different code.
Can some one help me, some good tutorial on the internet.
Add this code to your onTouchEvent to figure out where the user touched and respond appropriately:
//Grab the current touch coordinates
float x = event.getX();
float y = event.getY();
//If you only want something to happen then the user touches down...
if (event.getAction() != MotionEvent.ACTION_UP) return true;
//If the user pressed in the following area, run it's associated method
if (isXYInRect(x, y, new Rect(x1, y1, x2, y2)))
{
//Do whatever you want for your defined area
}
//or, if the user pressed in the following area, run it's associated method
else if (isXYInRect(x, y, new Rect(x1, y1, x2, y2)))
{
//Do whatever you want for your defined area
}
Here's the isXYinRect method:
//A helper method to determine if a coordinate is within a rectangle
private boolean isXYInRect(float x, float y, Rect rect)
{
//If it is within the bounds...
if (x > rect.left &&
x < rect.right &&
y > rect.top &&
y < rect.bottom)
{
//Then it's a hit
return true;
}
//Otherwise, it's a miss
return false;
}