So I’ve got this game prototype idea I wanted to try but I needed better multi-touch input support (accurate and comprehensive fingerID tracking) to make it happen.
It works great and has been added to the Proton SDK svn along with a new “Multitouch input test” option in RTSimpleApp.
Some stuff I noticed:
- Tracks 11 fingers on an iPad
- Tracks 4 fingers on an iPod Touch G1 (5 sort of.. but not reliably..)
- Tracks 5 fingers on an iPhone4
- Impossible to confuse it with fast movement, sliding off the screen or fast button mashing. Solid!
- Tracks 1.5 fingers on a Google Nexus One (It’s the HW’s fault. Curious to see the results from a Tab or other new devices though)
For those interested, here is the relevant tracking code to get the “finger id”: (yeah, I could have done it a more Obj-C way, but meh.. also, you may need your file named .mm, not .m for this code to work…)
[php]
const int MAX_TOUCHES= 11; //Oops, it can handle 11, not 10. Thanks @Bob_at_BH
class TouchTrack
{
public:
TouchTrack()
{
m_touchPointer = NULL;
}
void *m_touchPointer;
};
TouchTrack g_touchTracker[MAX_TOUCHES];
int GetFingerTrackIDByTouch(void* touch)
{
for (int i=0; i < MAX_TOUCHES; i++)
{
if (g_touchTracker[i].m_touchPointer == touch)
{
return i;
}
}
//LogMsg("Can’t locate fingerID by touch %d", touch);
return -1;
}
int AddNewTouch(void* touch)
{
for (int i=0; i < MAX_TOUCHES; i++)
{
if (!g_touchTracker[i].m_touchPointer)
{
//hey, an empty slot, yay
g_touchTracker[i].m_touchPointer = touch;
return i;
}
}
LogMsg("Can’t add new fingerID");
return -1;
}
int GetTouchesActive()
{
int count = 0;
for (int i=0; i < MAX_TOUCHES; i++)
{
if (g_touchTracker[i].m_touchPointer)
{
count++;
}
}
return count;
}
// Handles the start of a touch
– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerate through all the touch objects.
for (UITouch *touch in touches)
{
//found a touch. Is it already on our list?
int fingerID = GetFingerTrackIDByTouch(touch);
if (fingerID == -1)
{
//add it to our list
fingerID = AddNewTouch(touch);
} else
{
//already on the list. Don’t send this
//LogMsg("Ignoring touch %d", fingerID);
continue;
}
CGPoint pt =[touch locationInView:self];
ConvertCoordinatesIfRequired(pt.x, pt.y);
GetMessageManager()->SendGUIEx(MESSAGE_TYPE_GUI_CLICK_START,pt.x, pt.y,fingerID);
}
#ifdef _DEBUG
//LogMsg("%d touches active", GetTouchesActive());
#endif
}
– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerate through all the touch objects.
for (UITouch *touch in touches)
{
//found a touch. Is it already on our list?
int fingerID = GetFingerTrackIDByTouch(touch);
if (fingerID != -1)
{
g_touchTracker[fingerID].m_touchPointer = NULL; //clear it
} else
{
//wasn’t on our list
continue;
}
CGPoint pt =[touch locationInView:self];
ConvertCoordinatesIfRequired(pt.x, pt.y);
GetMessageManager()->SendGUIEx(MESSAGE_TYPE_GUI_CLICK_END,pt.x, pt.y, fingerID);
}
}
– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerate through all the touch objects.
for (UITouch *touch in touches)
{
//found a touch. Is it already on our list?
int fingerID = GetFingerTrackIDByTouch(touch);
if (fingerID != -1)
{
g_touchTracker[fingerID].m_touchPointer = NULL; //clear it
} else
{
//wasn’t on our list
continue;
}
CGPoint pt =[touch locationInView:self];
ConvertCoordinatesIfRequired(pt.x, pt.y);
GetMessageManager()->SendGUIEx(MESSAGE_TYPE_GUI_CLICK_END,pt.x, pt.y, fingerID);
}
}
– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerate through all the touch objects.
for (UITouch *touch in touches)
{
//found a touch. Is it already on our list?
int fingerID = GetFingerTrackIDByTouch(touch);
if (fingerID != -1)
{
//found it
} else
{
//wasn’t on our list?!
continue;
}
CGPoint pt =[touch locationInView:self];
ConvertCoordinatesIfRequired(pt.x, pt.y);
GetMessageManager()->SendGUIEx(MESSAGE_TYPE_GUI_CLICK_MOVE,pt.x, pt.y, fingerID);
}
}
[/php]