Strange touch behavior?

Strange touch behavior?

I have some code below and I cannot seem to work out where I am going wrong. Have spent the good part of two weeks testing many different combinations and I am starting to pull out when little hair I have left. Any help much appreciated.

I am trying to reliably spawn a prefab and get it to track under a finger position and when finger removed the prefab is destroyed. To do this I setup a prefab with a script that has a finger ID set when Instantiated. This ID is used to track the specific finger. Its also used to destroy the prefab if the same ID is matched with the fingerIDActive array.

Main Game Script

#pragma strict
var fingerPointPrefab : GameObject;
static var maxTouches : int = 11;
static var touchPos : Vector2[];
static var fingerIDActive : int[];
private var touchPhase : TouchPhase[];

function Start()
{
	touchPos = new Vector2[ maxTouches ];
	touchPhase = new TouchPhase[ maxTouches ];
	fingerIDActive = new int[ maxTouches ];
}

function Update () {
	var count = Input.touchCount;
	
	for ( var i : int = 0;i < count; i++) {
		var touch : Touch = Input.GetTouch( i );
		var figID = touch.fingerId;
		
		// Cache touch data.
		touchPos[ figID ] = touch.position;
		touchPhase[ figID ] = touch.phase;	
		
		// End finger marker 
		if (touchPhase[ figID ] == TouchPhase.Ended){ 
		 	fingerIDActive[ figID ] = 0;
		}
		
		// Spawn finger marker 
		if ((touchPhase[ figID ] == TouchPhase.Began) && (fingerIDActive[ figID ] == 0)){  
			Instantiate(fingerPointPrefab, touch.position, Quaternion.identity);
			fingerPointPrefab.GetComponent(JSFingerTracker).finderNumber = figID;
			var PFname: String = ("FingerID" + figID);
			fingerPointPrefab.name = PFname;
			fingerIDActive[ figID ] = 1;
		}
	}
}

Prefab Script

#pragma strict
var finderNumber : int = 0;
private var fingerPos: Vector3;
private var worldPos: Vector3;

function Update () {
	fingerPos = JSGameControler.touchPos[ finderNumber ];
	fingerPos.z = 10;
	worldPos = Camera.main.ScreenToWorldPoint(fingerPos);
	transform.position = worldPos;

	if (JSGameControler.fingerIDActive[finderNumber] == 0) {
		Destroy(gameObject);
	}	
}

Expected behavior:
Should create a prefab under finger, track finger when moved and if finger removed the prefab should be destroyed.

Observed behavior: (When compiled on iPad1)
Prefabs are not spawned or destroyed reliably.
Many times when an additional finger is added, the previous finger placed gets its prefab spawned correctly under it.
And this is the strangest behavior and does not seem to happen 100% but it seems the more fingers you place down the more you get random jittering. This seems to get worse when fingers are placed in a line horizontally on the iPad when held in landscape mode. This gets so bad that they pop all over the screen appearing and disappearing randomly. Have even seen it spawning phantom finger points. Maybe my iPad is possessed!! lol

Note, I am fairly new to JavaScript and still have much to learn.

This may help … drop this on something and run.

Play with three fingers on the screen … it might help demonstrate what the hell is going on!

function Update()
	{
	
	if ( Input.touches.Length == 1 )
		Debug.Log("    " +Input.touches[0].fingerId);
	
	if ( Input.touches.Length == 2 )
		Debug.Log("    " +Input.touches[0].fingerId
				+"    " +Input.touches[1].fingerId
				);
	
	if ( Input.touches.Length == 3 )
		Debug.Log("    " +Input.touches[0].fingerId
				+"    " +Input.touches[1].fingerId
				+"    " +Input.touches[2].fingerId
				);
	
	}

#Next step!
.

Next step you have to process each touch based on it’s Unity touchId:

function Update()
	{
	for ( var t:int=0; t<Input.touches.Length; ++t )
		processATouchPerFingerCodeNumber(
		      Input.touches[t], Input.touches[t].fingerId );
	}

So in the next function you have a touch to deal with, and it’s Unity code number. Try this code, and extensively play with your iPad. You will really see how it works, it’s great.

function processATouchPerFingerCodeNumber( t:Touch, n:int )
	{
	
	if ( t.phase == TouchPhase.Began )
		{
		Debug.Log("A finger has ARRIVED.  it's arbitrary +"
					"code number is: " + n);
		return;
		}
	if ( t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled )
		{
		Debug.Log("Well that's it. A finger went away .. being "+
					"arbitrary code number: " + n);
		Debug.Log("(Don't get confused .. the code numbers "+
					will be resued, perhaps immediately.)");
		return;
		}
	
	// you can also process .Moved and/or .Stationary here
	}

when you have that down, add this clause to the processing function

if ( t.phase == TouchPhase.Moved )
    {
    Debug.Log("You moved this finger: " + n);
    return;
    }

Now it, carefully moving one finger at a time.

OK so you’ve got that. Now here’s an important point. On many systems those id numbers are just arbitrary, like 343243. (Or you don’t even get an id number, it’s just a pointer.)

So let’s say it was 343243. Now, you have an array of say ten of the image of the red spot - you want to put a red spot under each finger.

Again - the next id number happens to be 343243, and you ave the array of ten.

So what you have to do is, take the “first available” red spot image in the array of red spot images. Let’s say it’s number 2 currently. So, you have to associate “343243” with YOUR array item 2. (Using a dictionary, lookup, whatever.)

Next time when processATouchPerFingerCodeNumber is called, and the number is “343243” THEN, IN FACT, you have to “look up” what your number it is. (In fact 2 in the example.)

So that’s what you normally have to do …


#BUT
.

very conveniently, Unity ensures thas the id code numbers, will run from 0-10. (I"m not sure what the max is on different platforms, but it doesn’t matter. YOU should impose a maximum of six, ten or however many fingers you wish to be the maximum.)

Again NORMALLY you MUST do a mapping between the CODE NUMBER (say 424234) and your OWN array (which runs from 0 to 9.)

BUT VERY HAPPILY in the specific Unity case, you don’t need to do that. Because Unity guarantees to recycle them, and they always stay below 10, you can and should … SIMPLY USE THAT ID NUMBER, as your own array number.

So in short, your code for processATouchPerFingerCodeNumber will look precisely like this.

function processATouchPerFingerCodeNumber( t:Touch, n:int )
	{
	
	if ( t.phase == TouchPhase.Began )
		{
		// a new finger has arrived!  fortunately WE KNOW it's
		// perfectly OK here in Unity to simply use that same number,
		// "our" array. in most systems, at this stage you would
		// "find an empty slot" and make a note of the mapping from
		// 424341 (or whatever) to our slot. again Unity GUARANTEES
		// to recycle them and always stays low so it is absolutely
		// OK to use it. but it's extremely important to realize
		// you can't normally do this - it's just Unity!!
		
		if ( t >= 7 ) return;
		// we enforce a maximum of seven (say) images, if someone
		// puts more than that many fingers on the screen, they can
		// go to hell
		
		myImages[ t ].showTheImageNow();
		myImages[ t ].positionImageAt( t.position );
		// it's that easy
		return;
		}
	if ( t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled )
		{
		myImages[ t ].hideTheImageNow();
		// it's that easy
		return;
		}
	if ( t.phase == TouchPhase.Moved )
		{
		myImages[ t ].positionImageAt( t.position );
		// it's that easy
		// nb as with any touch code, it's always tricky to know
		// how much to move it, you may have to convert from glass
		// to real world, scale, do a raycast, whatever.
		return;
		}
	
	// you can also process .Stationary here if relevant,
	// perhaps spin it or whatever is relevant to you
	}

Hopefully this helps you or someone else reading. Cheers.

The bit about Unity clamping to 0 - 9, it doesn’t at all.

Do a simple Android app just to print out the ID’s, press however many fingers on the screen, say 5 so you get ID’s 0 - 4. Hit the home button, then go back into the app again, you’ll see the ID’s are now 5 - 9, keep doing this with 5 fingers, and it will keep increasing.

So it is a bit of a pain really.