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

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

Related

Unity: LoadScene does not work when fired from timer

in my game, when the player dies, a dying sound is played and once the sound is over, the scene is supposed to be reloaded when the user still has enough lives.
Before I had the sound, the play died instantly upon calling the death() function:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
This worked like a charm.
But now I added a death sound to it. Unfortunately, unity doesnt provide an event handler for when the sound is done playing (I want the scene to be reloaded not instantly anymore, but after the death sound is done playing), so I have decided to take it upon myself to just build a timer. The timer fires right after the death sound is over. This is what this function has become:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = aSDeath.clip.length * 1000;
timer.Start();
timer.Elapsed += delegate
{
timer.Stop();
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
};
}
As you can see, to make sure the timer REALLY fires, I set up a "debug.Log("TIMER")" to see, if it really works. And guess what: it does. The debug now shows "TIMER" in its console. But you know what doesnt work anymore? The two lines of code right beneath that.
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
It's the same exact lines that worked just before - but when fired from the timer, they just get ignored? How is this even possible?
When I change it all back, it works again. Only when the timer fires the two lines, they get ignored.
This is totally odd or am I missing something? Thank you!
Okay I am not an expert on C# and delegate but apparently it creates a separate thread and you can only use SceneManager.GetActiveScene on main thread.
Since i am not so sure about delegate i will offer an easier solution. You can use a coroutine since you know how much you have to wait like this:
public void Death()
{
StartCoroutine(DeathCoroutine());
}
IEnumerator DeathCoroutine()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
// wait for duration of the clip than continue executing rest of the code
yield return new WaitForSeconds(aSDeath.clip.length);
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
What about using a coroutine ? You just start it when the player dies, and yield while your sound is still playing.

Strange If/Else Behavior

Context
I am making a mobile game in which the player is required to touch objects in a specified order. The correct order is determined in a List called clickOrder. To determine the current object the player is supposed to click, currClickIndex is used.
Problem
When touching a correct object, the debug text will display "Correct" for a split second, and will then immediately change to "Wrong." What I am unsure about is why both the if and else blocks are executed when only touching a single object.
Code
void Update()
{
if (Input.touchCount == 1)
{
if (this.enabled)
{
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero);
if (hit != null && hit.collider != null)
{
// check if the touched object is the correct one
if (hit.collider.gameObject == clickOrder[MyData.currClickIndex])
{
debug.text = "Correct";
MyData.currClickIndex++;
}
else
{
debug.text = "Wrong";
}
}
}
}
}
As soon as the correct object is being touched, you do this:
MyData.currClickIndex++;
which moves you forward in the ordered sequence, and from then on, the previously correct object is not correct anymore. But you're still touching it.
If you want to avoid this, you need to move forward in the sequence after you've touched the correct object.
if (there are touches and the correct object is being touched)
{
set a flag;
}
else if (a flag has been set)
{
MyData.currClickIndex++;
reset the flag;
}

UnityScript in Unity wont work correctly

I recently started making a new game and I'm kinda an amateur coder.
var FlashlightOn : boolean = true;
function Update () {
ButtonClicket();
}
function ButtonClicket () {
if (Input.GetButton("Flashlight")) && FlashlightOn == true {
Destroy(Flahslight);
FlashlightOn = false;
}
else
{
Instantiate (Flashlight, Vector3(i * 0, 0, 0), Quaternion.identity);
FlashlightOn = true;
}
}
In the compiler error part it says I need to put brackets at the end and some other junk that doesn't need to be done. What am I doing wrong here?
Having run the code through the compiler myself, the errors it's giving are valid. Your code simply has a syntax problem and a typo:
if (Input.GetButton("Flashlight") && FlashlightOn == true) {
The close parenthesis for the if statement was in the wrong place.
Destroy(Flashlight);
You misspelled 'Flashlight'.
Also, i isn't defined isn't this code snippet, which is fine if it's a global variable, but you may want to double check it.

StopCoroutine not working not even StartCoroutine(string), StopCoroutine(string) in unity3d

I can't understand why.
I already read lots of documents about it and there are lots of comments that
StopCoroutine(string) can only stop the coroutine starts with StartCoroutine(string)
the code is below.
In Class CharTouchControl.cpp
if( Input.GetKeyDown( KeyCode.Q ) )
{
_CharControl.StartCoroutine("useFever", 10);
}
_CharControl is a member of CharTouchControl and of course _CharControl is referencing the CharControl instance below.
And InClass CharControl
public IEnumerator useFever(float _duration = 10)
{
if( m_nUseFever < _nFeverMax )
{
Debug.Log("Stop!!");
StopCoroutine("useFever");
yield return new WaitForEndOfFrame();
}
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
yield return new WaitForEndOfFrame();
} // end of useFever
When m_nUseFever < _nFeverMax is true, i can see "Stop!!" log,
but the coroutine don't stop and simulate paticles.
anybody help for this?
Just as Jerdak mentioned, you should use yield break when your inside the Coroutine.
the coroutine will automatically stop when it finishes its code block. Using yield break, should send it to the end of the code block.
Additionally you could modify your code so that it only runs the code block if the condition is true. Ive done this in the example below. If the condition is false the coroutine will just wait for the end of the frame and then exit.
public IEnumerator useFever()
{
if( m_nUseFever > _nFeverMax )
{
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
}
yield return new WaitForEndOfFrame();
} //Coroutine automatically exits here
EDIT:
Dan Puzey brought up a good point, Are you sure shouldn't be using
Invoke("useFever",10) or InvokeRepeating ("useFever",10,1)
instead? From your code it looks like you just want to run the useFever function in 10 seconds. If thats the case, you should be invoking it instead of running it as a coroutine, and useFever should be a normal function.
Just for reference, there is also CancelInvoke("useFever")

How to add Delay before finding GameObject

I am trying to make a game in where you can stab an enemy, the enemy struggles for about a second and drops dead. (ragdoll);
i think its best to just show my script and you know what I mean:
In an on trigger enter script:
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
and in the update function:
if(Stabbed == true){
StopBleeding ++;
}
if(StopBleeding > 50){
Stabbed = false;
StopBleeding = 0;
currentEnemy ++;
Character.GetComponent("MouseLook").enabled = true;
Character.GetComponent("CharacterMotor").enabled = true;
BloodParticle.emit = false;
}
Now when my knife enters the collision of the enemy the enemy imediatly drops to the floor.
I tried putting the:
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
in the update function in if(StopBleeding > 50).
if I do that I get an error of Null reverance exception becaus the script cand find the enemy. While it can I its in the trigger enter.
Basicly my question is: Is there any way to fix this error to give it a 50 frame delay (all the rest in StopBleeding works)?
Or is there any way I can put a simple delay in before the Ragdoll gets activated?
Thanks in advance
You can use StartCoroutine("DelayDeath"); where DelayDeath is the name of a method. See below.
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
StartCoroutine("DelayDeath");
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
private IEnumerator DelayDeath()
{
//this will return...and one second later re-enter and finish the method
yield return new WaitForSeconds(1.0f);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
}
Since you're asking specifically about Unity JS and not C#, you'll use the yield keyword.
print("foo");
yield WaitForSeconds (5.0); // waits for 5 seconds before executing the rest of the code
print("bar");
On stabbing you could look up the enemy object but save it away in a variable instead of issuing the enemies dead. After the bleeding finishes you don't have to look up the enemy and can trigger the death on the saved one.
Another hint: Don't count frames as frames might be of different length. Add up time from Time.deltaTime until you reach let's say 2 seconds and then trigger the death.
Hope that helps.