Unity Touch phase returning incorrect results - unity3d

In Unity, I am attempting to use Touch.
I am having non-stop issues with it and have decided to just try and get something simple working first.
Whenever i press the screen, i am expecting Touch.phase to return TouchPhase.Began every time. However, it will sometimes return TouchPhase.Stationary when touching the screen for the first time. I have also noticed that it will sometimes not call TouchPhase.Ended or TouchPhase.Canceled when the touch has left the screen. What am i doing wrong?
Here is my very simple code:
void FixedUpdate() {
if(Input.touchCount == 1) {
Touch touch = Input.GetTouch(0);
switch(touch.phase) {
case TouchPhase.Began:
Debug.Log("Began: " + touch.figerId);
break;
case TouchPhase.Stationary:
Debug.Log("Stationary");
break;
case TouchPhase.Moved:
Debug.Log("Moved");
break;
case TouchPhase.Canceled:
Debug.Log("Canceled");
break;
case TouchPhase.Ended:
Debug.Log("Ended");
break;
default:
Debug.Log("Default");
break;
}
}
}

Touch.phase is updated every frame, so you have to check it within the Update() method.
FixedUpdate() is only called every x frames (fixed framerate), that's the reason you are missing some of the touch phases.

Related

Touch.rawPosition - Touch.Position instead of Touch.position - (previously saved) Touch.position?

Let's say my aim is to get the length of a swipe movement using the Touch class.
what is the difference between using
if(touchPhase == touchPhase.Began)
{
touchStart = touch.Position;
}
else if(touchPhase == touchPhase.Ended) {
Vector2 length = touch.Position - touchStart;
}
and
if(touchPhase == touchPhase.Ended) {
Vector2 length = touch.RawPosition - touch.Position;
}
From the documentation ,the rawPosition doesn't change when the touch contact is dragged, so the code should work.
I need a small explanation about that.
Thank you
As I understand the behavior should be equal. As you say yourself Touch.RawPosition is the
first position of the touch contact in screen space pixel coordinates.
Raw position returns the original position of a touch contact and doesn't change as the touch is dragged. If you need the current position of the touch see Touch.position.
Except in your second snippet it should rather be
Vector2 length = touch.Position - touch.RawPosition;
The delta is always the current minus the previous position.
You can simply proof check yourself using e.g.
// In general rather use switch for enums
switch(touchPhase)
{
case TouchPhase.Began:
touchStart = touch.Position;
break;
case TouchPhase.Ended:
Debug.Assert(touchStart == touch.RawPosition, "Not equal :O", this);
Vector2 length = touch.Position - touchStart;
Vector2 length2 = touch.Position - touch.RawPosition;
// Obviously redundant - if the first assert already passed then this will as well
Debug.Assert(length == length2, "Not equal :O", this)
break;
}

unity raycast hit calls three times when item dropped to the ground

My raycast from a ball to ground calls three times on every touch to ground.
I need only one time and toptup animation.
call is this:
private void FixedUpdate()
{
if (!Physics.Raycast(transform.position, -Vector3.up, distanceground + 0.1f))
{
Debug.Log("intheair");
}
else {
dropped = true;
Debug.Log("dropped");
if (dropped && !GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsTag("topup"))
{
GetComponent<Animator>().SetTrigger("topup");
Debug.Log("trigged");
}
}
This may solve your issue.
if (!Physics.Raycast(transform.position, -Vector3.up, distanceground + 0.1f) && !dropped)
{
Debug.Log("intheair");
}
else {
dropped = true;
Debug.Log("dropped");
if (dropped && !GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsTag("topup"))
{
GetComponent<Animator>().SetTrigger("topup");
Debug.Log("trigged");
}
}
Once your object is within
distanceground + 0.1f
Then
if (!Physics.Raycast(transform.position, -Vector3.up, distanceground + 0.1f))
Will return false every FixedUpdate() and defer to your else block, so the issue is not with the Raycast.
The issue most likely lies within the fact that you're checking GetCurrentAnimatorStateInfo(0) in FixedUpdate(). At lower framerates, FixedUpdate() can be called several times for every Update(), causing
if (dropped && !GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsTag("topup"))
to evaluate true because the visual animation state may not have had time to update yet.
I would recommend moving it all into Update().

can checking the hits from a raycast cause the game to crash?

so i am trying to detect if i click on a object with tag "solarsystem" and if so, then load that solarsystem onto the other scene. this code worked perfectly fine before, but now it crashes in such a way that i have to end unity from the task manager with the end task button to even close it. it just stops responding completely.
here is the code where i believe to have found the error after messing around with many Debug.log s to find where the code stopped and therefore find out where unity stops responding:
RaycastHit[] hit = Physics.RaycastAll(cursorPosition, Vector3.forward,15f);
Debug.Log("test2");//this is printed to the console - code crashes below this line
for(int i = 0; i < hit.Length; i++)
{
Debug.Log("hit"); // this is never printed to console - code crashes above this line
if(currentScene == "Universe")
{
if(hit[i].collider.gameObject.tag == "SolarSystem")
{
ChangeScene("SolarSystem");
SolarSystem clickedSolarSystem = hit[i].collider.gameObject.GetComponent<SystemObjectLink>().LinkedClass;
SolarSystem LoadedSolarSystem = SolarSystemCamera.GetComponent<SolarSystem>() as SolarSystem;
LoadedSolarSystem = clickedSolarSystem;
Debug.Log("generating system clicked on");
if (LoadedSolarSystem.preGenerated == false)
{
LoadedSolarSystem.Generate();
}
else
{
LoadedSolarSystem.Regenerate();
}
break;
}
}
if(currentScene == "SolarSystem")
{
if (hit[i].collider != null)
{
if (hit[i].collider.gameObject.tag == "Planet")
{
Target = hit[i].collider.gameObject;
break;
}
else if (hit[i].collider.gameObject.tag == "Moon")
{
Target = hit[i].collider.gameObject;
break;
}
Target = hit[i].collider.gameObject;
}
}
}
i had an for(;;) statement with a hardcoded
if(<state>){
break:
}
statement to break the infinite loop. but as i click on an object in the game. it checks the code for any errors before running it. when it does this it gets caught in the infinite loop and so to fix it i did this
for(;errorIndex<99; errorIndex++){
}
my mistake and what i learned:
never use a while(true) loop or a for loop without a way of getting out of itself (for(;;))
if the unity engine/editor ever stops responding it is because it is cought in an infinite loop- look over your code and ensure there is no possible way any of your loops can go on forever

OnDragListener not working properly

Hello everybody and thanks in advance.
I have a strange issue with one of my apps. This app is a MasterMind game which uses drag & drop, dragging coloured circles to holes.
This has been worked right with lots of devices, but recently I tried in a Galaxy S7 and Note 4 where the views(holes) have triggered the ACTION_DRAG_ENTERED outside the view.
Take a look at this screenshots to have a clearer idea...
< RIGHT BEHAVIOUR >
< WRONG BEHAVIOUR >
This is my listener...
class MiDragListener implements OnDragListener
{
#Override
public boolean onDrag(View v, DragEvent event)
{
int accion = event.getAction();
switch (accion)
{
case DragEvent.ACTION_DRAG_STARTED:
case DragEvent.ACTION_DRAG_EXITED:
v.setScaleX((float)1.0);
v.setScaleY((float)1.0);
break;
case DragEvent.ACTION_DRAG_ENTERED:
v.setScaleX((float)2.0);
v.setScaleY((float)2.0);
break;
case DragEvent.ACTION_DRAG_ENDED:
v.setScaleX((float)1.0);
v.setScaleY((float)1.0);
break;
case DragEvent.ACTION_DROP:
break;
default:
break;
}
return true;
}
} // end MiDragListener
although my code has not been changed.
Any help will be appreciated, thanks for your time and attention.

How do I load previous scene on unity3d

I have a total of five levels in the build setting . I need to load. When the player dies . The scene switch to restart scene. I have the restart scene code . So it only restart the current scene. I don't want it to do that. I need to reload the previous . I need to do same with the other levels . Here is my code :
{
#pragma strict
import UnityEngine.SceneManagement;
#script AddComponentMenu ("EGUI/UI_Elements/Button")
// public class EGUI_Button extends EGUI_Element {}
// List of built-in functionality types
public enum ButtonAction
{
None, // Do nothing
Custom, // Call function (name in callFunction) with parameter for actionRecipient object (this gameObject is default)
LoadLevel, // Load level with index/name in parameter
RestartLevel, // Restart current level
ExitGame, // Close application
SetQuality, // Set quality level according to parameter (Fastest, Fast, ... Fantastic)
DecQuality, // Decrease quality level
IncQuality, // Increase quality level
SetResolution, // Set screen resolution according to parameter (1024x768, 1920x1080 ... etc)
OpenURL, // Open URL specified in parameter
CloseEverything, // Close/disable whole GUI manager and all related GUI-elements.
Resume, // Close parent GUI-element and set time-scale to 1
ShowAnother, // Show GUI-element specified in actionRecipient
ShowPrevious, // Show previous GUI-element
HideThis, // Hide parent GUI-element
HideThis_ShowAnother, // Hide parent GUI-element and show window specified in actionRecipient
HideThis_ShowPrevious, // Hide parent GUI-element and show previous window
SoundSwitch, // Enable/Disable all sounds in the scene
LoadPreviousLevel, // Load the previous level if there is one else load load the current one
};
var onClickAction: ButtonAction; // Action preset to perform onClick
var actionRecipient: GameObject; // Optional link to action recipient object
var callFunction: String; // Optional name of custom function to call
var parameter: String; // Optional parameter to send/use in the Action
//=====================================================================================================
// Overload parent OnClick function to Perform built-in actions
function OnClick ()
{
// super.OnClick();
PerformAction ();
}
//----------------------------------------------------------------------------------------------------
// Perform built-in actions according to selected type (onClickAction)
function PerformAction ()
{
switch (onClickAction)
{
case ButtonAction.None:
break;
case ButtonAction.Custom:
if(!actionRecipient)
actionRecipient = gameObject;
if(parameter.Length > 0)
actionRecipient.SendMessage (callFunction, parameter, SendMessageOptions.DontRequireReceiver);
else
actionRecipient.SendMessage (callFunction, SendMessageOptions.DontRequireReceiver);
break;
case ButtonAction.LoadLevel:
Time.timeScale = 1;
try
SceneManager.LoadScene(int.Parse(parameter));
catch(error)
SceneManager.LoadScene(parameter);
break;
case ButtonAction.RestartLevel:
Time.timeScale = 1;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
break;
case ButtonAction.LoadPreviousLevel:
Time.timeScale = 1;
if (SceneManager.GetActiveScene().buildIndex > 0) // if not the first scene load the prvious scene
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
else
SceneManager.LoadScene(0);
break;
}
}
case ButtonAction.ExitGame:
Application.Quit();
break;
case ButtonAction.SetQuality:
switch (parameter)
{
case "Fastest":
QualitySettings.SetQualityLevel(QualityLevel.Fastest);
break;
case "Fast":
QualitySettings.SetQualityLevel(QualityLevel.Fast);
break;
case "Simple":
QualitySettings.SetQualityLevel(QualityLevel.Simple);
break;
case "Good":
QualitySettings.SetQualityLevel(QualityLevel.Good);
break;
case "Beautiful":
QualitySettings.SetQualityLevel(QualityLevel.Beautiful);
break;
case "Fantastic":
QualitySettings.SetQualityLevel(QualityLevel.Fantastic);
break;
}
break;
case ButtonAction.IncQuality:
QualitySettings.IncreaseLevel();
break;
case ButtonAction.DecQuality:
QualitySettings.DecreaseLevel();
break;
case ButtonAction.SetResolution:
Screen.SetResolution ( int.Parse(parameter.Substring(0,parameter.IndexOf("x"))), int.Parse(parameter.Substring(parameter.IndexOf("x")+1)), Screen.fullScreen);
break;
case ButtonAction.OpenURL:
Application.OpenURL(parameter);
break;
case ButtonAction.CloseEverything:
GetGUIManager().gameObject.SetActive(false);
break;
case ButtonAction.Resume:
Time.timeScale = 1;
transform.parent.gameObject.SendMessage("Disable");
break;
case ButtonAction.ShowAnother:
if(actionRecipient) actionRecipient.GetComponent(EGUI_Element).SetActivation(true, transform.parent.gameObject);
break;
case ButtonAction.ShowPrevious:
if(senderObject) senderObject.SetActive(true);
break;
case ButtonAction.HideThis:
transform.parent.gameObject.SendMessage("Disable");
break;
case ButtonAction.HideThis_ShowAnother:
if(actionRecipient) actionRecipient.GetComponent(EGUI_Element).SetActivation(true, transform.parent.gameObject);
transform.parent.gameObject.SendMessage("Disable");
break;
case ButtonAction.HideThis_ShowPrevious:
if(senderObject) senderObject.SetActive(true);
transform.parent.gameObject.SendMessage("Disable");
break;
case ButtonAction.SoundSwitch:
if(actionRecipient) actionRecipient.GetComponent(AudioListener).enabled = !actionRecipient.GetComponent(AudioListener).enabled;
break;
}
}
//----------------------------------------------------------------------------------------------------
}
Firstly,
Application.LoadLevel & Application.loadedLevel are obsolete.
See:
Application.LoadLevel Reference
Application.loadedLevel Reference
Instead, Unity recommends you use the SceneManager class in the Scene Management API.
My recommendation would be to do something like this in order to reload a current scene:
// reload the current scene
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
// load the previous scene
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
Use this C# Script to make your task much easier.
private List sceneHistory = new List(); //running history of scenes
//The last string in the list is always the current scene running
void Start()
{
DontDestroyOnLoad(this.gameObject); //Allow this object to persist between scene changes
}
//Call this whenever you want to load a new scene
//It will add the new scene to the sceneHistory list
public void LoadScene(string newScene)
{
sceneHistory.Add(newScene);
SceneManager.LoadScene(newScene);
}
//Call this whenever you want to load the previous scene
//It will remove the current scene from the history and then load the new last scene in the history
//It will return false if we have not moved between scenes enough to have stored a previous scene in the history
public bool PreviousScene()
{
bool returnValue = false;
if (sceneHistory.Count >= 2) //Checking that we have actually switched scenes enough to go back to a previous scene
{
returnValue = true;
sceneHistory.RemoveAt(sceneHistory.Count -1);
SceneManager.LoadScene(sceneHistory[sceneHistory.Count -1]);
}
//
return returnValue;
}