I’ve been struggling with simple control I’m writing for my 2D Game, this is how the control look like so you can get a reference of what I’m doing:
The control works fine but once in a while if I press left and right too fast while jumping what happens is that my character keeps walking in one direction so it moveLeft or moveRight never get set back to false which happens in TouchPhase.Ended. See my code below:
I would love some feedback I have two days stuck on this thanks guys!!!
if (Input.touchCount > 0) {
var touchCount = Input.touchCount;
for (var i = 0; i < touchCount; i++) {
var t = Input.GetTouch (i);
if (t.phase == TouchPhase.Began) {
if (guiLeft.HitTest (t.position, Camera.main))
moveLeft = true;
if (guiRight.HitTest (t.position, Camera.main))
moveRight = true;
if (guiJump.HitTest (t.position, Camera.main))
{
Debug.Log("Jump pressed");
if (groundHit !stickmanIsDead) {
anim.SetBool ("Ground", false);
rigidbody2D.AddForce (new Vector2 (0, jumpForce));
}
//Record start time only once
holdJumpDownStartedAt = Time.time;
}
}
//Fall from Platforms
if(t.phase == TouchPhase.Stationary){
if (guiJump.HitTest (t.position, Camera.main)){
if(Time.time - holdJumpDownStartedAt > dropPlatformAt){
Debug.Log(string.Format("Holded for {0} second :) ",dropPlatformAt.ToString()));
holdJumpDownStartedAt = 0.0f;
#region Falling Keystroke
var playerFalling = Physics2D.Linecast (transform.position, groundCheck.position, 1 << LayerMask.NameToLayer ("Floor-Air"));
//Fall Key
if (playerFalling)
StartCoroutine (Fall ());
#endregion
}
}
}
if (t.phase == TouchPhase.Ended) {
if (guiLeft.HitTest (t.position, Camera.main))
moveLeft = false;
if (guiRight.HitTest (t.position, Camera.main))
moveRight = false;
}
}
}
I was able to pin point the issue. So what happens is as I press right to move my character in the right direction and then move left without lifting my finger, TouchPhase.Ended never executes for my Right Arrow Texture which is true, but how can I detect that in code?
It works a bit better but still when pressing jump couple of times and left and right fast it gets to a point when moveLeft or moveRight do not get set to false.
How are you “checking” to see if this works? Are you testing to a build on a device, or using remote?
From your last thread on this topic, I tried out your code, and played around with the states and how the fire.
The problem is that you are looping through the all the touches in the same place. But each touch has a unique id that is assigned in order the touch occurs. What can happen is that since you are checking them all in the loop, and don’t actually determine if a touch is related to a string of particular event’s you won’t (always) be checking the correct touch for the ended.
So to check for touch.Ended, you have to ensure that you are actually checking on the touch that started it. Which now may be gone from that loop, or replaced by another. A quick solution that I tried that worked out well, was to have a touch variable for each button/touch. If found just store it there, and check it there. That way if the index changes, the touch object will still be accurate.
Alternately, you could it with storing the touches by finderId, or even just attaching scripts to each object that allows them to check/store touch details themselves, so there is no mixing up ids/collision.
Create a separate script and put the following script in the Update(). The code itself is trivial but the thing that made it work for me was putting it in a separate script.
using UnityEngine;
using TMPro; //I used textmeshpro to display the text on my android
void Update()
{
TextMeshPro ShowTouch = GetComponent<TextMeshPro>();
if (ShowTouch != null)
{
ShowTouch.text = Input.GetTouch(0).phase.ToString();
}
}
I don’t have a technical explanation as to why it worked for me but I’ll just say what I think happened.
Based off of many answers that I came across related to this issue, it’s got something do with how the the cycle of the script fails to catch the moment the state changes to Touchphase.Ended, thus leaving it at Touchphase.Move or whatever. Since my script was pretty long (my Update() was full of private methods), I tried creating a new script that only carried the touch detection logic.
…you can also store the phase using an if condition.
using UnityEngine;
using TMPro; //I used textmeshpro to display the text on my android
private bool _IsTouchZeroEnded = false;
void Update()
{
TextMeshPro ShowTouch = GetComponent<TextMeshPro>();
if (ShowTouch != null)
{
ShowTouch.text = Input.GetTouch(0).phase.ToString();
}
// if condition that sends the touch phase to a
// public void (TouchphaseGetter(bool Phase)) that
// was created in your main script (YourScript)
if(Input.GetTouch(0).phase == Touchphase.Began)
{
IsTouchZeroEnded = true;
YourScript somevariablename = GameObject.Find("GameObjectName").GetComponent<YourScript>();
if(somevariablename != null)
{
somevariablename.TouchphaseGetter(_IsTouchZeroEnded);[/INDENT]
}
}
}