- Home /
multi-touch woe, index out of bounds?
I'm making my first attempt at multi-touch controls in Unity, right now I've made a small test scene with a cube that moves according to X/Y values taken from a touch input in the bottom left corner of the screen.
My problem is hard to put into words, but I'll try anyway:
Placing one finger on the control pad works fine, and the object moves. Any other fingers are ignored.
Placing a finger outside the control does nothing, and while holding that finger down touching the control pad with another works fine as well.
The problem occurs when I have two fingers placed on the screen like that, whenever I lift the finger that came first (outside the box) there is an immediate Unityexception: Index out of bounds error, and the fingerID of the touch I want to track for movement gets 'stuck' and won't respond without resetting the scene or pressing the screen with multiple fingers repeatedly.
Here's the code I'm using:
using UnityEngine;
using System.Collections;
public class tushcontrl : MonoBehaviour {
public GameObject obj1;
public GameObject obj2;
private float relativeX;
private float relativeY;
private float rotateX;
private float rotateY;
public int leftControlTouchID;
public int rightControlTouchID;
public int touchCounter;
void Start () {
leftControlTouchID = -1;
rightControlTouchID = -1;
}
void Update () {
touchCounter=Input.touchCount;
//Loop through all touches
foreach (Touch touch in Input.touches){
Debug.Log(touch.fingerId + " " + touch.position);
//Assignment for Left
if(touch.phase == TouchPhase.Began){
if(touch.position.x<Screen.height/2&&touch.position.y<Screen.height/2&&leftControlTouchID<0){
leftControlTouchID = touch.fingerId;}
}
//Do something with it
if(touch.fingerId==leftControlTouchID){
relativeX = Mathf.Clamp(Input.GetTouch(leftControlTouchID).position.x/Screen.height*4 - 1,-1.0f,1.0f);
relativeY = Mathf.Clamp(Input.GetTouch(leftControlTouchID).position.y/Screen.height*4 - 1,-1.0f,1.0f);
obj1.transform.position = obj1.transform.position + 0.5f*new Vector3(relativeX,0,relativeY);
}
//Removal when touch phase ends
if (touch.phase == TouchPhase.Ended){
if(touch.fingerId==leftControlTouchID){
leftControlTouchID=-1;}
}
}
}
void OnGUI () {
GUI.Box(new Rect(0,Screen.height/2,Screen.height/2,Screen.height/2),"");
GUI.Box(new Rect(Screen.width-Screen.height/2,Screen.height/2,Screen.height/2,Screen.height/2),"");
foreach (Touch touch in Input.touches){
GUI.Box(new Rect(touch.position.x-25,Screen.height-touch.position.y-25,50,50),touch.fingerId.ToString());
}
}
}
I can't work out a way to avoid going out of the touch array range, and this issue is preventing me from making a functional 'two-joystick' style control setup. :(
Answer by Mrobertson · Oct 19, 2012 at 07:44 PM
relativeX = Mathf.Clamp(Input.GetTouch(leftControlTouchID).position.x/Screen.height*4 - 1,-1.0f,1.0f);
These lines are your problem, Input.GetTouch() takes the index of the touch not the touch ID, so when your finger of touchID 0 and index 0 leaves your finger of touchID 1 and index 1 now turns to touchID 1 and index0 causing an exception.
I'm gonna include my similar script that has seemed to work for me so far on my twin stick shooter if you want some reference
void Update () {
#if UNITY_IPHONE && !UNITY_EDITOR
moving = false;
for(int i = 0; i < Input.touches.Length; i++)
{
Vector2 pos = new Vector2(Input.touches[i].position.x, sh - Input.touches[i].position.y);
if(Input.touches[i].phase == TouchPhase.Began)
{
if(!GUIManager.ButtonPress(pos))
{
if(pos.x > sw * .5f)
{
aimFinger = Input.touches[i].fingerId;
StartCoroutine(FadeIndicator(false, aimGUI));
aimIndicator.renderer.enabled = true;
if(Vector2.Distance(pos, aimControlPos) > fingerDistFromControl)
{
aimControlPos = pos;
UpdateGUI(aimGUI, aimControlPos);
}
}
else
{
moveFinger = Input.touches[i].fingerId;
StartCoroutine(FadeIndicator(false, moveGUI));
moveIndicator.renderer.enabled = true;
if(Vector2.Distance(pos, moveControlPos) > fingerDistFromControl)
{
moveControlPos = pos;
UpdateGUI(moveGUI, moveControlPos);
}
}
}
}
else if(Input.touches[i].phase != TouchPhase.Ended)
{
if(Input.touches[i].fingerId == moveFinger && Vector2.Distance(pos, moveControlPos) > deadZone)
{
UpdateIndicator(pos, moveControlPos, moveIndicator.transform);
EventManager.instance.QueueEvent(new MoveEvent(moveControlPos - pos));
moving = true;
}
else if(Input.touches[i].fingerId == aimFinger && Vector2.Distance(pos, aimControlPos) > deadZone)
{
UpdateIndicator(pos, aimControlPos, aimIndicator.transform);
EventManager.instance.QueueEvent(new AimEvent(aimControlPos - pos));
}
}
else
{
if(Input.touches[i].fingerId == aimFinger)
{
aimFinger = -1;
StartCoroutine(FadeIndicator(true, aimGUI));
aimIndicator.renderer.enabled = false;
WeaponsManager.instance.StopFireEffect();
}
else if(Input.touches[i].fingerId == moveFinger)
{
StartCoroutine(FadeIndicator(true, moveGUI));
moveIndicator.renderer.enabled = false;
moveFinger = -1;
}
}
}
}
Your answer
Follow this Question
Related Questions
¿Unity messing up fingerIDs? [Android] 1 Answer
Mobile - button press while moving (First Person Controls) 0 Answers
Please confirm: Galaxy Stylus not readable directly in Unity 1 Answer
How to differentiate touches on mobile devices 1 Answer
How do I handle multitouch as Input.GetButtonDown()? 0 Answers