Are there any multitouch examples? Dispatching touch events?

I was wondering if there are any ofxiPhone example for dispatching touch events for individual objects and what the best practices are.

For example, if there’s a class ‘Circle’ and you want each circle to be dragged simultaneously (multitouch), how do you best approach this? Do you ofRegisterTouchEvents(circle) or ofRegisterTouchEvents(this) in the circle class?

Are there any more advanced examples that show how interaction is used within other classes (besides testApp)?

Hi, the example app iPhoneSpecificExamples/TouchAndAccelExample handles multitouch with individual objects… did you check this one out already?

Yeah, I checked that one.

That doesn’t include how to hitTest objects and provide objects their own multitouch events. That example just moves the circles to fingers with a hardcoded set of what circle goes to what finger. I’m looking for something more complex, like an example that allows for each finger to pick and drag any object (ie. circle), scale it, etc simultaneously. I’m sure people have done this, so I rather not reinvent the wheel if there’s a class that can already be extended. :slight_smile:

Ok, I see what you mean. I don’t know of any classes in OF already for this and when I’ve made the multitouch object handling more complex it’s still been touch event driven - i.e. just adding logic on top of that TouchAndAccel example, and telling the circle objects what to do, rather than giving the circle objects some touch event awareness themselves.

If it helps, for scaling, I made a thread a while back - http://forum.openframeworks.cc/t/gesture-recognizers-iphone-os-3.2-working-in-of/4244/0 - and this has been working nicely, though it’s still a touch event driven class and sends scaling data to the circle class, rather than a method of the circle class itself.

1 Like

When working with multitouch, I usually have a vector where CustomTouch is a subclass of ofTouchEventArgs. Let me give you an example of the CustomTouch class, in this case it’s called ‘POFinger’.

POFinger.h

  
#pragma once  
#include "ofMain.h"  
  
class POFinger: ofTouchEventArgs {  
	  
public:  
	  
	POFinger(int id, float x, float y);  
	POFinger(ofTouchEventArgs &touch);  
	  
	void update(ofTouchEventArgs &touch);  
	  
	int id;  
	float x;  
	float y;  
	float accel;  
	float angle;  
	float prevX;  
	float prevY;  
};  

POFinger.cpp

  
#include "POFinger.h"  
  
POFinger::POFinger(int _id, float _x, float _y){  
	id = _id;  
	x = _x;  
	y = _y;  
	  
	prevX = x;  
	prevY = y;  
	accel = 0;  
	angle = 0;  
}  
  
POFinger::POFinger(ofTouchEventArgs &touch){  
	id = touch.id;  
	x = touch.x;  
	y = touch.y;  
	  
	prevX = x;  
	prevY = y;  
	accel = 0;  
	angle = 0;  
}  
  
void POFinger::update(ofTouchEventArgs &touch){  
	x = touch.x;  
	y = touch.y;  
	accel = ofDist(prevX, prevY, x, y);			// acceleration is the distance between the previous point and this point  
	angle = atan2(prevY - y, prevX - x) + PI;	// atan2 calculates num of radians  
	prevX = x;  
	prevY = y;  
}  

So basically I add the acceleration and angle functionality which can be extremely useful. Then in testApp.h (in this case physOSCApp.h) :

  
vector<POFinger> touches;  

And the three important methods in physOSCApp.mm:

  
//--------------------------------------------------------------  
void physOSCApp::touchDown(ofTouchEventArgs &touch) {  
	if(touches.size() < 5) touches.push_back(POFinger(touch));  
	for(int i = 0; i < particles.size(); i++){  
		if(ofDist(particles[i].x, particles[i].y, touch.x, touch.y) < particles[i].radius){  
			particles[i].fingerIndex = touches.size() - 1;  
			break;  
		}  
	}  
}  
  
//--------------------------------------------------------------  
void physOSCApp::touchMoved(ofTouchEventArgs &touch) {  
	int indexOfMovedTouch = -1;  
	for(int i = 0; i < touches.size(); i++){	// find touch in vector of touches by id  
		if(touches[i].id == touch.id) indexOfMovedTouch = i;  
	}	  
	if(indexOfMovedTouch != -1){  
	 	touches[indexOfMovedTouch].update(touch);   // update the touch  
	}  
	  
	for(int i = 0; i < particles.size(); i++){  
		if(particles[i].fingerIndex == indexOfMovedTouch){  
	float tempXVel = cos(touches[indexOfMovedTouch].angle) * touches[indexOfMovedTouch].accel;  
	float tempYVel = sin(touches[indexOfMovedTouch].angle) * touches[indexOfMovedTouch].accel;  
	particles[i].updatePos(touches[indexOfMovedTouch].x, touches[indexOfMovedTouch].y, tempXVel, tempYVel);  
			break;  
		}  
	}  
}  
  
//--------------------------------------------------------------  
void physOSCApp::touchUp(ofTouchEventArgs &touch) {  
	int indexOfReleasedTouch = -1;  
	for(int i = 0; i < touches.size(); i++){  
		if(touches[i].id == touch.id) indexOfReleasedTouch = i;  
	}  
	if(indexOfReleasedTouch != -1) touches.erase(touches.begin() + indexOfReleasedTouch);		// erase the touch  
	  
	for(int i = 0; i < particles.size(); i++){  
		if(particles[i].fingerIndex == indexOfReleasedTouch){  
			particles[i].fingerIndex = -1;  
			break;  
		}  
	}  
}  

So I have a class POParticle, which has a member called fingerIndex. If a new touch is within the radius of the particle, fingerIndex is set to the index of the new touch. If the fingerIndex of a particle matches the index of a moved or released touch, the particle is updated accordingly. I placed some break-statements to prevent multiple particles being bound to a single touch, I’ve noticed that most users are content with the random nature of picking one of two particles at the same position.

This system of organizing touches gives me the idea that I’m in control of it. If you have lots of ‘touchable’ or ‘draggable’ objects, it would of course be wise to make a superclass ‘touchable’ and let all of your classes inherit from that class.

2 Likes

That’s a great example daanvanhasselt! Thank you for posting it.

I talked to someone else who’s going to be posting an addon or superclass for things such as this.

In the meantime, I implement something somewhat similar.

In the superclass of object(s) I want to move I have:

Constructor

  
//Register touch events  
ofRegisterTouchEvents(this);  
bDrag = false;  
touchID = -1;  
  

functions:

  
  
//--------------------------------------------------------------  
void Node::touchDown(ofTouchEventArgs &touch){  
	  
        //see if the current touch is on this object  
        //if it is, set the touchID to the touch, move object to point and set bDrag = true  
	if(isUnder(touch.x, touch.y)){		  
		touchID = touch.id;  
		x = touch.x;  
		y = touch.y;  
		bDrag = true;  
	}  
}  
  
//--------------------------------------------------------------  
void Node::touchMoved(ofTouchEventArgs &touch){  
	//if we're dragging and it's the same touch ID, move object to touch point  
	if(bDrag && touch.id == touchID)  
	{  
		x = touch.x;  
		y = touch.y;	  
	}  
}  
  
//-----------------------------------------------------------  
void Node::touchUp(ofTouchEventArgs &touch){  
	//if there's an up event with this touch ID, we can't possibly still be dragging it  
	if(touch.id == touchID){  
		bDrag = false;  
	}  
}  
  
bool Node::isUnder(float px, float py){  
	if (px < x - width/2 || px > x + width) return false;  
    if (py < y - width || py > y + width) return false;  
    return true;  
}  
  

The above doesn’t account for 2 objects on top of each other (it’ll drag both) or for oddly shaped objects (since it’s only checking the bounding box), but it seems to work for a simple class. It would probably be better to include a list of object depths to be able to choose only the top most object in the future.

Since dragging, rotating, scaling, etc are all common events, it’d be great to create an addon just for such things instead of reinventing the wheel.

daanvanhasselt thanks again for the example. I learned some new things I can try in the future.

1 Like

sorry, old post but I just wanted to share my enthusiasm on this one.
Daan & Seth, those stuff just works very fine !

1 Like