bamalam - 18 March 2010 04:16 PM
However although now I’m seeing touch points added and removed there is a problem when I hold a touch point and move it around. Although it keeps the ID of the message the touch is blinking on and off as if it is losing some of the alive messages.
In fact I’ve discovered that it sometimes does not pick up on new touch point as well.
Sounds like you’re done, actually. :D This is the correct behavior—Surface does not necessarily update blobs at the same frame rate as your application (this would be very unlikely)—especially with OSC going between Surface and your app. So you are drawing frames faster than you are receiving blob data, hence the flickering. Also, “alive” messages really don’t work as advertised. Instead, use only “set” messages and a “timeout” scheme to keep blobs on screen.
Now that you are maintaining a list of active Surface contacts and receiving updates over UDP, the next step is to create a blob manager. This needs to happen inside your client program. That is, if you are taking Surface data and sending it out to Flash, you need to write a blob manager in Flash.
Here’s a quick overview on how to do that. I’m sticking with C#/XNA for the example, but this should all translate easily to AS3 (I’ve done this in AS3 quite a bit, as well, but that code’s a tad outdated). You’ll need a list of blobs, a Blob class/structure, and a something to keep track of elapsed time. You might want to use a variable to say how long you want a blob to “live” before it’s removed from the screen.
public class myApp : Game
{
int elapsedTime;
int aliveTime = 75;
List<Blob> BlobList;
...
}
public struct Blob
{
int ID;
int LastUpdateTime;
int x;
int y;
}
When you receive a TUIO “set” message, you’ll want to use that data to determine whether you should add a blob or update one. In your XNA game class, you’ll want a packet reading function like this:
/// <summary>
/// Reads OSC packet
/// </summary>
/// <param name="packet">The packet to read</param>
protected void readPacket(OSCPacket packet)
{
// Check packet
if (packet != null)
{
// Iterate through the messages
foreach (OSCMessage message in packet.Values)
{
// Set message
if (message.Values[0].ToString() == "set")
{
// Get the blob's ID and position
// (DISPLAY_W and DISPLAY_H are screen size values I have in my settings)
int blobID = Int32.Parse(message.Values[1].ToString());
int blobX = Decimal.ToInt32(Decimal.Parse(message.Values[2].ToString()) * Properties.Settings.Default.DISPLAY_W);
int blobY = Decimal.ToInt32(Decimal.Parse(message.Values[3].ToString()) * Properties.Settings.Default.DISPLAY_H);
// Set a found flag
bool found = false;
// Iterate through all blobs in list
int blobCount = BlobList.Count;
for (int i = 0; i < blobCount; i++)
{
// Blob found
if (BlobList[i].ID == ID)
{
// Set found flag
found = true;
// Update blob in list
BlobList[i].x = blobX;
BlobList[i].y = blobY;
BlobList[i].LastUpdate = elapsedTime;
}
}
// Blob not found
if (!found)
{
// Create a new blob and set its properties
Blob blob = new Blob();
blob.ID = blobID;
blob.x = blobX;
blob.y = blobY;
blob.LastUpdate = elapsedTime;
// Add the blob to the list
BlobList.add(blob);
}
}
}
}
}
Note that I’m setting the Blob.LastUpdate using the “elapseTime” property I mentioned at the top of this post. Inside of your update function, use GameTime.ElapsedRealTime to updated the class’ “elapsedTime” property, like so…
protected override void Update(GameTime gt)
{
// Update elapsed time
elapsedTime = gt.ElapsedRealTime;
...
}
The last thing to do is to “timeout” a blob. Use “elapsedTime”, “aliveTime”, and Blob.LastUpdate to determine when a blob has gone too long without an update and then remove it. In my experience, 75 - 100ms is a good “alive” time when you take the UDP communication and packet parsing into consideration.
protected override void Update(GameTime gt)
{
// Update elapsed time
elapsedTime = gt.ElapsedRealTime;
// Iterate through all blobs in list
for (int i = 0; i < BlobList.Count; i++)
{
// Remove blob from list if it hasn't
// been updated in "aliveTime"
if (BlobList[i].LastUpdate < elaspedTime - aliveTime) BlobList.RemoveAt(i);
}
...
}
Now iterate through BlobList in your draw routine to draw active blobs. Voila!