Phil Hassey - game dev blog
Phil Hassey as Snidely Whiplash
"You can't buy awesomeness.
You're born that way."

Android Day 4: Video cleanup, Input handling

Whew, day 3 was epic! I’m glad I got through all that! Day 4 (I hope) will be a bit easier. Now that I’ve got things “basically” working, it should be mostly a matter of getting a few more API calls doing what they need to do.

Step 1 – Basic handling of onPause:

First of all, right now when I restart the App without reinstalling it, I get a white screen. I think this is due to some multitasking feature on the Android where it shoves the App into the background and tells it to pause. When unpaused, I need to reload the graphics. Fixing this was pretty trivial, I just added a few lines to the onPause() method to save state and basically shutdown.

Step 2 – Removing the title bar:

When I start my game, there is a title that says “Galcon” in text on the top. I think that is part of the default app generation. I’ll want to remove that. First of all, in “res/layout/main.xml” I commented out the TextView. This had no effect, but at least I cleared out some junk. This page appears to explain how to hide the title bar (I found by adding .Fullscreen it hides the Status Bar as well.)

http://developer.android.com/guide/appendix/faq/commontasks.html – modify AndroidManifest.xml:

<application android:icon=”@drawable/icon” android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”>

Step 3 – Adding onTouchEvent handling:

I really want to start playing the game – so I’m going to add some input event handling. I’ll do this from the top level in my Activity by adding a onTouchEvent handler. The documentation for MotionEvent was a bit opaque, but I worked it out and here’s how to handle events and deal with MultiTouch. It seems like something is severely broken about the API, but this was the only way I could get MultiTouch to work in Galcon. It appears to only work with 2 fingers.

    public boolean onTouchEvent(final MotionEvent e) {
        for (int i = 0; i<e.getPointerCount(); i++) {
            boolean masked = false;
            switch(e.getActionMasked()) {
                case MotionEvent.ACTION_POINTER_DOWN:
                case MotionEvent.ACTION_POINTER_UP:
                    masked = true;
                break;
            }
            if (masked && i != e.getActionIndex()) { continue; }
            float x = e.getX(i); float y = e.getY(i);
            float dx = 0; float dy = 0;
            if (e.getHistorySize()!=0) {
                dx = x - e.getHistoricalX(i,0);
                dy = y - e.getHistoricalY(i,0);
            }
            int pid = e.getPointerId(i);
            int type = 0;
            switch(e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: type=EVT_DOWN; break;
                case MotionEvent.ACTION_MOVE: type=EVT_MOTION; break;
                case MotionEvent.ACTION_OUTSIDE: type=EVT_MOTION; break;
                case MotionEvent.ACTION_POINTER_DOWN: type=EVT_DOWN; break;
                case MotionEvent.ACTION_POINTER_UP: type=EVT_UP; break;
                case MotionEvent.ACTION_UP: type=EVT_UP; break;
                case MotionEvent.ACTION_CANCEL: type=EVT_UP; break;
            }
            event(type,(int)x,(int)y,0,pid+1,(int)dx,(int)dy,0,0);
            if (masked) { break; }
        }
        return true;
    }

This works okay, except my Nexus One has a different screen resolution than my iPhone, so all my code is handling things a bit off. I added a native call in onSurfaceChanged to tell my game the size of the screen. In my event handler I translate for the game.

Step 4 – Keyboard handling:

To play the multi-player game, I need to have the pop-up keyboard work. On the Droid, of course, this isn’t needed, but for the Nexus One and possibly other future devices it is.

This is apparently easier said than done. More on it in day 5!

5 Responses to “Android Day 4: Video cleanup, Input handling”

  1. MichaelWC Says:

    Phil, I’m very excited to see this port happening. I followed a link on a Risk game-request post on a forum and found Galcon. This will satisfy my need for multiplayer for sure.

    I would, however, like to request something that I’m not sure if you already include in your game. I’d like to see a turn based mode that can operate over long periods of time. Most people I’d like to play with have short periods of time (lunch hours, breaks, etc) over the course of a day when a full game just might not work. An epic week-long game would be really cool.

    Also, does Galcon support gaming with particular individuals? Like if I have a few friends across town, can I choose to connect with only with them in a private game?

  2. Chi-Ro Says:

    mMmmmmm, a turn based mode for the Mobile versions of the game sounds great!

    Also, I’m really looking forward to this. I’ll buy it for sure.

  3. tomhiggins Says:

    Oh great, now I will get schooled by ChiRo on the droid and the desktop:)-

  4. Dianne Hackborn Says:

    Hi, yeah that touch handling code is a little odd. 🙂

    There is a blog post about it here:

    http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html

    Basic summary: getActionMasked() returns the action for the entire event. There are two types of down and up. First, ACTION_DOWN and ACTION_UP are for the first and last fingers, respectively. For multitouch, ACTION_POINTER_DOWN and ACTION_POINTER_UP tell you about an additional finger going down or up; for these events you can call getActionIndex() for the *index* of the pointer that has changed.

    Pointer indices are only meaningful for the current event (they are the raw packed current data); pointer identifiers are maintained consistently across events. getPointerId(int) maps from an index to an id; getX(int) and getY(int) retrieve the current position of a current index; getPointerCount() returns the number of indices in that event.

    If you receive an ACTION_MOVE, there has been no change in the number of active fingers, this is just a report in the change in position of all fingers.

    If you only care about the current finger positions at the time of receiving the event, you shouldn’t do anything with getHistoricalXxx(). These allow apps to collect all possible movement data since the last motion event report, if they aren’t keeping up with the hardware reports and actually care about every possible movement. They would be useful, for example, for a handwriting recognizer.

    Also useful is this blog post on writing an app that supports multitouch but also works on pre-2.0 versions of the platform:

    http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html

  5. philhassey Says:

    @Dianne – thanks for the details on all that!