- Home /
Possible bug in unity touch phase for android ?
I am pretty new to unity and have been working on my first ever android game. Most of the elements function properly but there is this one little inconvenience which makes playing the game almost impossible. I will try to include all of the important info and explain it as best as I can. Excuse my not-so-good grammar and English as a whole, as it is not my first language.
The name of my game is 'Distance! Please' and it revolves around the idea of maintaining distance from every other game object. The characters are called 'Fluffs' and there is a specific number of fluffs on every level. the characters have a script[RandomPatrol] for random movement on the screen. They also have a DragAndDrop Script which allows the player to drag and change the position of the fluffs.
The problem, however, is that if I drag - release 'Fluff A' and then touch 'Fluff B', Fluff A would randomly teleport over to the position of FluffA resulting in the crash of two game objects hence, a big fat 'Game Over'. This is some kind of glitch, bug, or a hardware issue, I'm not particularly sure about that, as it happens randomly. Sometimes it won't happen and you'll be able to clear the level easily but sometimes it just won't let you advance ahead.
To Further explain my situation I have provided some pics down below and also have provided the two scripts I mentioned above.
DragAndDrop Code
public class DragAndDrop : MonoBehaviour
{
bool moveAllowed;
Collider2D col;
int flag;
private GameMaster gm;
private AudioSource audioSource;
public GameObject selectEffect;
public GameObject deathEffect;
public GameObject electricDeath;
public GameObject poisonDeath;
public GameObject fireDeath;
public GameObject frostDeath;
void Start()
{
gm = GameObject.FindGameObjectWithTag("GM").GetComponent<GameMaster>();
audioSource = GetComponent<AudioSource>();
col = GetComponent<Collider2D>();
}
void Update()
{
if(Input.touchCount > 0 && !IsPointerOverUIObject())
{
Touch touch = Input.GetTouch(0);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
switch (touch.phase)
{
case TouchPhase.Began:
if (col == touchedCollider)
{
Instantiate(selectEffect, transform.position, Quaternion.identity);
audioSource.Play();
//moveAllowed = true;
flag = 1;
}
break;
case TouchPhase.Moved:
if (flag == 1)
{
transform.position = new Vector2(touchPosition.x, touchPosition.y);
}
break;
case TouchPhase.Ended:
flag = 0;
//moveAllowed = false;
break;
case TouchPhase.Canceled:
//moveAllowed = false;
flag = 0;
break;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Planet" || collision.tag == "Projectile")
{
Instantiate(deathEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "ElectricOrb")
{
Instantiate(electricDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "Spiky")
{
Instantiate(poisonDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "FireOrb")
{
Instantiate(fireDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "FreezeOrb")
{
Instantiate(frostDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
}
RandomPatrol Code
public class RandomPatrol : MonoBehaviour
{
private float _speed;
public float minSpeed = 1f;
public float maxSpeed = 2f;
public float minX = -8.15f;
public float maxX = 8.15f;
public float minY = -4.15f;
public float maxY = 4.15f;
public float secondsToMaxDifficulty = 50f;
Vector2 targetPosition;
void Start()
{
Time.timeScale = 1;
targetPosition = GetRandomPosition();
}
void Update()
{
if((Vector2)transform.position != targetPosition)
{
_speed = Mathf.Lerp(minSpeed, maxSpeed, GetDifficultyPercent());
transform.position = Vector2.MoveTowards(transform.position, targetPosition, _speed * Time.deltaTime);
}
else
{
targetPosition = GetRandomPosition();
}
}
Vector2 GetRandomPosition()
{
float randomX = Random.Range(minX, maxX);
float randomY = Random.Range(minY, maxY);
return new Vector2(randomX, randomY);
}
private float GetDifficultyPercent()
{
return Mathf.Clamp01(Time.timeSinceLevelLoad / secondsToMaxDifficulty);
}
}
I have already tried fixing it and looked for a solution for 4 days now. Any kind of help. I have tried playing it on unity remote as well as installed apk, the problem continues to persist.
Any kind of help would be highly appreciated and I'll be more than happy to provide any kind of extra information you may ask/need.
Does it only happen when you are near UI objects? Is the UI check interfering with the touch phase change happening?
Is it always that the touch end doesn't register?
Have you turned on the debugging touches display on your android phone? It is in different locations, but somewhere in the dev settings it should allow you to see exactly where it thinks you are touching, etc. This can really help figure out collider sizes, etc.
@whogas 1. No, it happens randomly. Pretty sure they're not interfering 2. Nope its completely random 3. Yes, i did tried turning them on and look for my self i even recorded the screen and watched it frame by frame but i didn't found anything unusual. Also i was i apologize for the late replies as i was busy with some service work. This is the only bug that is stopping me from publishing my game. Eveything else is in place and working as intended
Since you have the DragAndDrop script on every puff, you aren't making sure that the inputs are being applied to that specific puff. There is a check within the switch statement when the touch begins, but the movement and end don't have any checks. You should probably add the check prior to the switch statement. The way it works right now, it seems like it should all work out in the end, but you may have some weird cross-talk as each puff runs its update.
I would set up a test case and observe that touchphase.ended is firing when you expect it to once you have the touch check tied to the touched puff only.
A note: I would set a variable for Camera.main. Right now, you are searching the entire stack for the camera each update cycle for each puff. This can be avoided by just setting it in Start with the rest of your assignments.
i actually tried something similar but failed miserably with the code. now that u've suggested it, i feel like i should give it another go. I'll let you know the results.
Answer by ArminAhmadi · Sep 16, 2020 at 04:09 PM
Try this and see if your problem gets fixed.
public class DragAndDrop : MonoBehaviour
{
private Collider2D col = null;
private int flag = 0;
private int fingerId = -1;
private GameMaster gm = null;
private AudioSource audioSource;
public GameObject selectEffect;
public GameObject deathEffect;
public GameObject electricDeath;
public GameObject poisonDeath;
public GameObject fireDeath;
public GameObject frostDeath;
private void Start()
{
gm = GameObject.FindGameObjectWithTag("GM").GetComponent<GameMaster>();
audioSource = GetComponent<AudioSource>();
col = GetComponent<Collider2D>();
}
private void Update()
{
if (Input.touchCount > 0 && !IsPointerOverUIObject())
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
if (col == touchedCollider)
{
if (fingerId >= 0)
{
if (fingerId == touch.fingerId)
{
if (touch.phase == TouchPhase.Moved && flag == 1)
{
transform.position = new Vector2(touchPosition.x, touchPosition.y);
}
else if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
flag = 0;
fingerId = -1;
}
}
}
else
{
if (touch.phase == TouchPhase.Began)
{
Instantiate(selectEffect, transform.position, Quaternion.identity);
audioSource.Play();
fingerId = touch.fingerId;
flag = 1;
}
}
}
}
}
else
{
fingerId = -1;
flag = 0;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Planet" || collision.tag == "Projectile")
{
Instantiate(deathEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "ElectricOrb")
{
Instantiate(electricDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "Spiky")
{
Instantiate(poisonDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "FireOrb")
{
Instantiate(fireDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
if (collision.tag == "FreezeOrb")
{
Instantiate(frostDeath, transform.position, Quaternion.identity);
Destroy(gameObject);
gm.GameOver();
}
}
yep this works as i want but the only problem it gave is that it allows multi-touch, i want to keep it as a single touch. im not sure which variable or sign i should change for single touch , also i dont wanna mess it up.
I have noticed that you have a Game$$anonymous$$aster script.
private Game$$anonymous$$aster gm = null;
Create a public int in that script and name it activeFingerId. Then change Update function like this.
private void Update()
{
if (Input.touchCount > 0 && !IsPointerOverUIObject())
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
if (col == touchedCollider)
{
if (fingerId >= 0)
{
if (fingerId == touch.fingerId)
{
if (touch.phase == TouchPhase.$$anonymous$$oved && flag == 1 && gm.activeFingerId == fingerId)
{
transform.position = new Vector2(touchPosition.x, touchPosition.y);
}
else if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
if(gm.activeFingerId == fingerId)
{
gm.activeFingerId = -1;
}
flag = 0;
fingerId = -1;
}
}
}
else
{
if (touch.phase == TouchPhase.Began && gm.activeFingerId < 0)
{
Instantiate(selectEffect, transform.position, Quaternion.identity);
audioSource.Play();
fingerId = touch.fingerId;
flag = 1;
gm.activeFingerId = fingerId;
}
}
}
}
}
else
{
fingerId = -1;
flag = 0;
}
}
Your answer
![](https://koobas.hobune.stream/wayback/20220613011601im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
InputSystem simulated touchscreen stops working from v1.1.0 preview 1 0 Answers
Problem with random chess piece moveplate generator 2 Answers
Infuriating bug: Android build occasionally dropping touch input. 0 Answers
Touch.deltaPosition giving jerky movement on Android in Unity 5 2 Answers
Unity Bug, Letting User To touch two UI Buttons as same time (simultaneously) 1 Answer