Welcome to my Programming Blog...

I am currently working on a couple of projects: An original game called "Implosion" which I am porting from Flash to the iPad, and a remake of Q*bert in Python (pygame), as part of the class I am teaching. Please feel free to use the "Labels" (at right) to follow a specific project or theme. If you are one of my Python students, I recommend that you check out the Python thread.

Tuesday, January 18, 2011

Multi-touch, part 2

So in the intervening time since I had to break from the first part of my multitouch post, I've done some more reading and had a revelation:

In your code, to handle touch events, you have to implement several different methods:
touchBegan, touchMoved, touchEnded, and touchCanceled (in case the phone rings - instead of the user picking up their fingers.) And in each case, you are sent a "UITouch" variable and a "UIEvent" variable.

And it's the same UITouch variable each time, from when the touch begins to when it ends. Oh, sure, there are things about it that change - the location of the touch for instance, or the status (begin/move/stationary/end/cancel) of the touch. But the memory location of the touch will be the same when you receive it as a touchBegan as it is when you receive it as a touchEnded!

Why does this matter? Well, frankly it doesn't, if you are using a single-touch model. But it is vital if you go to multi-touch. Because when the user touches the screen with two fingers, you get a touch object for the index finger and a touch object for the thumb. And those two touch objects will remain locked to those fingers until the user lets go. So you can track what each finger is doing.
For example:
User touches screen with index and thumb.touchesBegan --> touch1 and touch2
User moves index fingertouchesMoved --> touch1
User touches screen with pinkietouchesBegan --> touch3
User swipes all three fingerstouchesMoved --> touch1, touch2, and touch3
User lifts thumbtouchesEnded --> touch2
User lifts index and pinkietouchesEnded --> touch1 and touch 3

One subtle difference you may notice is that instead of touchBegan (and its ilk), which is singular, this table includes touchesBegan (et al) - the plural. This is another difference with multitouch.

Let's step back a sec. In order to receive multitouch information, you first have to tell the view that is receiving the touches that it should receive multitouch info. As I mentioned in an earlier post, in Cocos2d-iOs, this can be done in the AppDelegate's applicationDidFinishLaunching: method, by adding the following:
[glView setMultipleTouchEnabled:YES];
right after the glView variable is initialized.

Then, in your Layer class, you still need to have the registerTouchDispatcher function:
-(void)registerTouchDispatcher
{
   [[CCTouchDispatcher sharedTouchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}

Then you still need to write your responsive functions for when touch events arrive, just the plural version. So instead of the single-touch "began" responder:
-(BOOL)ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
you will write the multi-touch, plural version:
-(BOOL)ccTouchesBegan:(NSSet*)touches withEvent(UIEvent*)event

Note that in this case, you get an NSSet of touches, rather than a single UITouch. A set is a collection of several things in no particular order, so in this case, you'd get a set of one or more touch objects.

In their book, iPhone Programming: the Big Nerd Ranch Guide, Joe Conway and Aaron Hillegass have an elegant demonstration of how to use these sets of touch objects to maintain an NSDictionary of touches - and draw several lines at once. I won't recreate the whole thing here, but I will give an overview of what they did:

  • They created a Line class that kept track of a starting point and an ending point.
  • They had a member variable for the class that was an NSMutableDictionary.
  • When the calls came into ccTouchesBegan, they encapsulated the UITouch pointers in NSValues so they could be used as keys in the dictionary and set new Line objects as the matching values, with both the start and end set to the touches' locations.
  • Then when ccTouchesMoved came in, those touch objects were re-encapsulated in NSValues and used to look up the lines in the dictionary, and the end points of the lines adjusted to the new locations.
  • Finally, when the ccTouchesEnded or ccTouchesCanceled came in, those touch objects were used again to look up the Lines in the dictionary. These entries in the dictionary were removed, and the Lines were transferred to more permanent storage in the program.
For the details, you should probably buy their book! It's definitely a good one for general iPhone programming.

No comments:

Post a Comment