Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Multitouch Game

I am currently in the process of making a game where the user controls a ship with an on screen joystick on the left side of the screen and fires by tapping the right side of the screen. However, my attempts at multitouch have been unsuccessful. When the user touches the joystick first and then fires, it works perfectly, but when the user touches the stick while firing, the user is not able to drag the joystick. I am still new to android so any help would be greatly appreciated. I will paste the code below.

@Override
public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction() & MotionEvent.ACTION_MASK;
    int pointerIndex=(event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK) 
    >>MotionEvent.ACTION_POINTER_ID_SHIFT;
    int pI = event.getPointerId(pointerIndex);
    //On screen joystick
    if(event.getX(pI)<pad.getWidth()+(screenWidth*.18)&&event.getX(pI)>0&&event.getY(pI)<(screenHeight)&&event.getY(pI)>(screenHeight-(0.42*screenHeight))){
        sx2=event.getX(pI)-(stick.getWidth()/2);
        sy2=event.getY(pI);
        angle=(Math.atan2((sy2-sy),(sx2-sx)));
    }
    //firing system
    if(event.getX(pI)>screenWidth/3){
        switch(action){
        case MotionEvent.ACTION_DOWN:
            incrementRunnable.run();
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            incrementRunnable.run();
            break;
        case MotionEvent.ACTION_UP:
            handler.removeCallbacks(incrementRunnable);
            break;
        case MotionEvent.ACTION_POINTER_UP:
            handler.removeCallbacks(incrementRunnable);
            break;
        }

    }
    //reset joystick
    if(event.getAction()==MotionEvent.ACTION_UP||event.getAction()==MotionEvent.ACTION_POINTER_UP){
        sx2=sx;
        sy2=sy;
        handler.removeCallbacks(incrementRunnable);
    }
    return true;
}
like image 377
user1229888 Avatar asked Feb 24 '12 04:02

user1229888


1 Answers

Given that you can manipulate the joystick and fire button in isolation, it stands to reason that you're getting the screen dimensions correctly and everything else about detecting a pointer's vicinity to your game object is correct. I've read about issues with certain Android versions and multi touch but let's assume that's not the problem.

The tricky thing with a MotionEvent is that it is fired off for multiple pointers and that if you're interested in touches and movement you need to consider all possible pointers. I think the issue may lie in your approach.

Rather than determine what the user is touching and then figuring out what to do given the different types of events, you should figure out what type of event is occurring and then determine what object the user is interacting with. This will make your code a little cleaner and make it easier to spot problems in the future.

I took your example above and rewrote it as show below. This example will just write text to screen to show what/where the user is touching. It is able to determine joystick touches after the fire button and vice versa.

MultiTouchGame.java

package com.droidhut.stackoverflow;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.TextView;

public class MultiTouchGame extends Activity implements OnTouchListener {
    StringBuilder builder = new StringBuilder();
    TextView textView;

    boolean[] joystickTouched = new boolean[10];
    boolean[] fireButtonTouched = new boolean[10];
    int joyX = 0;
    int joyY = 0;

    int screenHeight;
    int screenWidth;
    Pad pad = new Pad();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        textView = new TextView(this);
        textView.setText("Touch and drag (multiple fingers supported)!");
        textView.setOnTouchListener(this);
        setContentView(textView);

        WindowManager mWinMgr = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        mWinMgr.getDefaultDisplay().getMetrics(dm);
        screenHeight = dm.heightPixels;
        screenWidth = dm.widthPixels;

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction() & MotionEvent.ACTION_MASK;
        int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        int pI = event.getPointerId(pointerIndex);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                joystickTouched[pI] = isPointerOnJoystick(event, pointerIndex);
                fireButtonTouched[pI] = isPointerOnFireButton(event, pointerIndex);
                break;
            case MotionEvent.ACTION_UP:        
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_CANCEL:
                joystickTouched[pI] = false;
                fireButtonTouched[pI] = false;
                break;
            case MotionEvent.ACTION_MOVE:
                joystickTouched[pI] = isPointerOnJoystick(event, pointerIndex);
                fireButtonTouched[pI] = isPointerOnFireButton(event, pointerIndex);
                if (isTouchingJoystick()){
                    int index = getJoystickPointer();
                    if (index != -1 && index < event.getPointerCount()){
                        joyX = (int)event.getX(index);
                        joyY = (int)event.getY(index);
                    }
                }
                break;
        }

        updateTextView();       
        return true;
    }

    private boolean isPointerOnJoystick(MotionEvent event, int pointerIndex){
         return (event.getX(pointerIndex)<pad.getWidth()+(screenWidth*.18)&&event.getX(pointerIndex)>0&&
                 event.getY(pointerIndex)<(screenHeight)&&event.getY(pointerIndex)>(screenHeight-(0.42*screenHeight)));
    }

    private boolean isPointerOnFireButton(MotionEvent event, int pointerIndex){
        return (event.getX(pointerIndex)>screenWidth/3);
    }

    private boolean isTouchingJoystick(){
        for (int i = 0; i < joystickTouched.length; i++){
            if (joystickTouched[i]){
                return true;
            }
        }
        return false;
    }

    private boolean isTouchingFireButton(){
        for (int i = 0; i < fireButtonTouched.length; i++){
            if (fireButtonTouched[i]){
                return true;
            }
        }
        return false;
    }

    private int getJoystickPointer(){
        for (int i = 0; i < joystickTouched.length; i++){
            if (joystickTouched[i]){
                return i;
            }
        }

        return -1;
    }

    private void updateTextView() {
        builder.setLength(0);
        builder.append(String.format("screenWidth[%d], screenHeight[%d]\n",screenWidth, screenHeight));
        builder.append(String.format("joystickTouched[%s]\n", isTouchingJoystick()));
        builder.append(String.format("fireButtonTouched[%s]\n", isTouchingFireButton()));
        builder.append(String.format("joystickMovement[%d,%d]",joyX,joyY));

        textView.setText(builder.toString());
    }

    private static class Pad {
      public int getWidth(){
        return 200;
      }
    }

}
like image 198
Louth Avatar answered Oct 10 '22 23:10

Louth