Once I’ve faced the problem there is no convenient way to work with multitouch in Unity, I’ve created my own one, not to be as complex as those jet planes in the Asset Store, but to get an obvious way to work with multiple touches, treat them as close as possible to OnMouse events and never ever see Input.touches in my code.
As UT refused to publish it on the asset store, I’ll cut down other touch-related plugins’ sales a bit with publishing my script here, mue-ge-ge. :twisted:
Just copy the code into file.
To add touch input implementation into your application just drag TouchListener script onto your main camera and add it as a script component. Ah, and don’t forget that your objects must have a Collider or Collider2D component for being able to be hit by your input.
Now you can use next methods in any of your scripts that are extensions of the MonoBehaviour class:
OnTouchDown(Touch touch) - called when touch began on an Collider.
OnTouchUp(Touch touch) - called when touch is ended.
OnTouchUpAsButton(Touch touch) - called when the touch is ended on the same Collider as it was began.
OnTouchEnter(Touch touch) - called when moving touch point entered an Collider.
OnTouchExit(Touch touch) - called when moving touch point leaved an Collider.
OnTouchOver(Touch touch) - called every frame touch point is over an Collider.
OnTouchDrag(Touch touch) - called every frame when touch began on an Collider and is still continues.
As you can see, it mimics OnMouse events. If, for example, you will touch two or more different objects simultaneously, each of them will receive corresponding messages from their ‘own’ touches. You also can access actual touch information through ‘touch’ parameter passed.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TouchListener : MonoBehaviour
{
public ColliderMode colliderMode = ColliderMode.Collider;
public enum ColliderMode
{
Collider,
Collider2D
}
private Camera parentCamera;
private List<TrackedObject> trackedObjectList = new List<TrackedObject>();
private class TrackedObject
{
public Touch touch;
public GameObject gameObject;
public TrackedObject(Touch touch, GameObject gameObject)
{
this.touch = touch;
this.gameObject = gameObject;
}
}
private List<TrackedTouch> trackedTouchList = new List<TrackedTouch>();
private class TrackedTouch
{
public int fingerId;
public Vector2 position;
public TrackedTouch(int fingerId, Vector2 position)
{
this.fingerId = fingerId;
this.position = position;
}
}
void Start()
{
this.parentCamera = this.GetComponent<Camera>();
}
void Update()
{
if (enabled)
{
foreach (Touch touch in Input.touches)
{
GameObject objectHit = null;
switch (colliderMode)
{
case ColliderMode.Collider:
{
Ray touchRay = this.parentCamera.ScreenPointToRay(touch.position);
RaycastHit touchHit;
bool isTouchHit = Physics.Raycast(touchRay, out touchHit, this.parentCamera.farClipPlane, this.parentCamera.cullingMask);
objectHit = isTouchHit ? touchHit.collider.gameObject : null;
}
break;
case ColliderMode.Collider2D:
{
Vector3 worldPoint = this.parentCamera.ScreenToWorldPoint(touch.position);
Vector2 touchPosition = new Vector2(worldPoint.x, worldPoint.y);
Collider2D collider = Physics2D.OverlapPoint(touchPosition, this.parentCamera.cullingMask,
this.transform.position.z + this.parentCamera.nearClipPlane,
this.transform.position.z + this.parentCamera.farClipPlane);
objectHit = (collider != null) ? collider.gameObject : null;
}
break;
}
switch (touch.phase)
{
case TouchPhase.Began:
{
if ((objectHit != null) (!this.trackedObjectList.Exists(trObj => trObj.gameObject == objectHit)))
{
this.trackedObjectList.Add(new TrackedObject(touch, objectHit));
objectHit.SendMessage("OnTouchDown", touch, SendMessageOptions.DontRequireReceiver);
}
}
break;
case TouchPhase.Ended:
{
bool isTrackedObjectExists = this.trackedObjectList.Exists(trObj => trObj.touch.fingerId == touch.fingerId);
GameObject trackedObject = isTrackedObjectExists ? this.trackedObjectList.Find(trObj => trObj.touch.fingerId == touch.fingerId).gameObject : null;
if (isTrackedObjectExists)
if (trackedObject == objectHit)
{
trackedObject.SendMessage("OnTouchUpAsButton", touch, SendMessageOptions.DontRequireReceiver);
trackedObject.SendMessage("OnTouchUp", touch, SendMessageOptions.DontRequireReceiver);
}
else
trackedObject.SendMessage("OnTouchUp", touch, SendMessageOptions.DontRequireReceiver);
this.trackedObjectList.RemoveAll(trObj => trObj.touch.fingerId == touch.fingerId);
}
break;
case TouchPhase.Moved:
{
Vector3 touchPointPrev = this.trackedTouchList.Exists(trTch => trTch.fingerId == touch.fingerId) ?
this.trackedTouchList.Find(trTch => trTch.fingerId == touch.fingerId).position : touch.position;
Ray touchRayPrev = this.parentCamera.ScreenPointToRay(touchPointPrev);
RaycastHit touchHitPrev;
bool isTouchHitPrev = Physics.Raycast(touchRayPrev, out touchHitPrev, this.parentCamera.farClipPlane, this.parentCamera.cullingMask);
GameObject objectHitPrev = isTouchHitPrev ? touchHitPrev.collider.gameObject : null;
bool isTrackedObjectExists = this.trackedObjectList.Exists(trObj => trObj.touch.fingerId == touch.fingerId);
GameObject trackedObject = isTrackedObjectExists ? this.trackedObjectList.Find(trObj => trObj.touch.fingerId == touch.fingerId).gameObject : null;
if (isTrackedObjectExists)
{
trackedObject.SendMessage("OnTouchDrag", touch, SendMessageOptions.DontRequireReceiver);
}
if (objectHit == objectHitPrev)
{
if (objectHit != null)
objectHit.SendMessage("OnTouchOver", touch, SendMessageOptions.DontRequireReceiver);
}
else
{
if (objectHit != null)
objectHit.SendMessage("OnTouchEnter", touch, SendMessageOptions.DontRequireReceiver);
if (objectHitPrev != null)
objectHitPrev.SendMessage("OnTouchExit", touch, SendMessageOptions.DontRequireReceiver);
}
}
break;
case TouchPhase.Stationary:
{
bool isTrackedObjectExists = this.trackedObjectList.Exists(trObj => trObj.touch.fingerId == touch.fingerId);
GameObject trackedObject = isTrackedObjectExists ? this.trackedObjectList.Find(trObj => trObj.touch.fingerId == touch.fingerId).gameObject : null;
if (isTrackedObjectExists)
{
trackedObject.SendMessage("OnTouchDrag", touch, SendMessageOptions.DontRequireReceiver);
}
if (objectHit != null)
{
objectHit.SendMessage("OnTouchOver", touch, SendMessageOptions.DontRequireReceiver);
}
}
break;
case TouchPhase.Canceled:
{
this.trackedObjectList.RemoveAll(trObj => trObj.touch.fingerId == touch.fingerId);
}
break;
}
}
this.trackedTouchList.Clear();
foreach (Touch touch in Input.touches)
this.trackedTouchList.Add(new TrackedTouch(touch.fingerId, touch.position));
}
}
}