Saturday, September 3, 2011

Getting Started with Android Development, Modifying the Snake Example for Touch Input

Google has done a good job with the Android SDK, especially including documentation. The only problem is, however, that the excess of documentation can be overwhelming. An inexperienced developer may find it difficult to pick out simple items in the wealth of information. Consider this the first of my 'Getting Started with Android Development' posts.
Recently I purchased a newer model Android device, only to find the example games used the keyboard exclusively. Wouldn't you know, my phone doesn't have a keyboard! Let's modify the Snake example to work with touch events.
Implementing touch events can be broken into three pieces,
  1. Create an input listener
  2. Register your listener
  3. Implement your input handling function

The difficult thing is to pick a way to do this. Check here for an overview on the 3 ways to do this. I chose method 2, implementing the event listener in the View.

Creating an Input Listener

For this tutorial, I assume you are able to load the Snake example program. In the /src folder find the SnakeView.java file and open it. First, we must tell the the SnakeView that it will be handling the touch events. Change

...

/**
 * SnakeView: implementation of a simple game of Snake
 * 
 * 
 */
public class SnakeView extends TileView {

...
to this
...
/**
 * SnakeView: implementation of a simple game of Snake
 * 
 * 
 */
public class SnakeView extends TileView implements OnTouchListener {

...
Don't forget to press Ctrl+Shift+O to automagically import the correct packages. By adding
implements OnTouchListener
we are saying that this SnakeView will take care of anything that OnTouchListener requires. In this case, the function
public boolean onTouch (View v, MotionEvent event)

will be handled by SnakeView.

Implementing Your Input Handling Funciton

Go ahead and add the following code somewhere in the SnakeView class. I added it right after my key events because the two are related.

    @Override
    public boolean onTouch (View v, MotionEvent event)
    {
    	float x = event.getX();
    	float y = event.getY();
    	float height = this.getHeight();
    	float width = this.getWidth();
    	float slope = height/width;
    	
    	// Only process DOWN action, so it responds as soon as the
    	// screen is touched.
    	if (event.getAction()==MotionEvent.ACTION_DOWN)
	    {
    		// Touch event UP
	    	if ((y < slope*x) && (y < -slope*x + height)) { 
	            if (mMode == READY | mMode == LOSE) {
	                // At the beginning of the game, or the end of a previous one,
	                // we should start a new game.
	                initNewGame();
	                setMode(RUNNING);
	                update();
	                return (true);
	            }
	
	            if (mMode == PAUSE) {
	                // If the game is merely paused, we should just continue where
	                // we left off.
	                setMode(RUNNING);
	                update();
	                return (true);
	            }
	
	            if (mDirection != SOUTH) {
	                mNextDirection = NORTH;
	            }
	            return (true);
	        }
	    	
	    	// Touch event DOWN
	        if ((y > slope*x) && (y > -slope*x + height)) { 
	            if (mDirection != NORTH) {
	                mNextDirection = SOUTH;
	            }
	            return (true);
	        }
	        
	        // Touch event LEFT
	        if ((y > slope*x) && (y < (-slope*x + height))) {
	        	if (mDirection != EAST) {
	        		mNextDirection = WEST;
	        	}
	        	return (true);
	        }
	        
	        // Touch event RIGHT
	        if ((y < slope*x) && (y > -slope*x + height)) {
	        	if (mDirection != WEST) {
	        		mNextDirection = EAST;
	        	}
	        	return (true);
	        }
	    }
	    	
        return false;
    }

The code above mimics the key event listener. Instead of listening to an arrow key, though, we are listening for touch events in the four areas of the screen. The code above divides the screen from corner to corner, forming an X. Notice, we are only listening for ACTION_DOWN events.

Registering the Input Listener

Next, we need to register our class to the Android device as a listener. Find the Snake.java file in your /src folder. Here, we only need to add one line, that tells the Android device that we have a listener for touch events. Add the following line in the activity's onCreate method.

        // Register the listener
        mSnakeView.setOnTouchListener(mSnakeView);
Here is the entire method
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // No Title bar
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.snake_layout);

        mSnakeView = (SnakeView) findViewById(R.id.snake);
        mSnakeView.setTextView((TextView) findViewById(R.id.text));
        
        // Register the listener
        mSnakeView.setOnTouchListener(mSnakeView);

        if (savedInstanceState == null) {
            // We were just launched -- set up a new game
            mSnakeView.setMode(SnakeView.READY);
        } else {
            // We are being restored
            Bundle map = savedInstanceState.getBundle(ICICLE_KEY);
            if (map != null) {
                mSnakeView.restoreState(map);
            } else {
                mSnakeView.setMode(SnakeView.PAUSE);
            }
        }
    }

Play a game of Snake!

If everything was done correctly, you should have a working Snake example that responds to touch events.

2 comments :

  1. A bit stupid not be able to start game because there is no joystick/pad.. So it's pointles to implement reaction to touch in play mode, without being able to start play.. :P

    click on text to start game is missing.. ;)

    and thanks for nice idea/tutorial

    ReplyDelete
  2. This compose of readiness can be truly specialized and exertion a personal mentor can abuse you coordinate completed drink. java

    ReplyDelete