- Home /
Unity crashes on event of specific code
I am working right now on the movement in a sort of turn-based game and am almost done configuring it, I have this code, but I want something more complex so I could see the movement occur instead of the player just jumping to the position he needs:
rb.MovePosition(Vector3.MoveTowards(Player.transform.position,BattleGrid[2,1].position,200f));
it works, but I want to see the movement occur and smoothly, so I made this code to replace the previous code:
float sqrRemainingDistance = (Player.transform.position - BattleGrid[2,1].position).sqrMagnitude;
while(sqrRemainingDistance > 0) {
Vector3 newPostion = Vector3.MoveTowards(rb.position, BattleGrid[2,1].position, inverseMoveTime * Time.deltaTime);
rb.MovePosition (newPostion);
sqrRemainingDistance = (Player.transform.position - BattleGrid[2,1].position).sqrMagnitude;
The issue is, this code makes the entire unity freeze up while playing, just when I do the thing that activates this code (or the previous code when I tried earlier).
There isn't any error or warning popping up... Does anyone know why this code makes the unity freeze up???
Answer by Eudaimonium · Sep 10, 2015 at 11:15 AM
Problem is, your While loop never finishes.
Explanation why: Distance between two points, which is your distance, is never less than zero. Your "destination" is never precisely hit. Suppose your player is at one frame 0.1 distance from destination, and it moves at 0.07 units per frame.
Next frame he will be 0.03 units from the destination.
Next frame he will not be -0.06 units away. He will be 0.06 units away. Distance is never negative.
How to solve this:
Idea #1: Within the code that initiates the move command (a click or some other input, I assume), aside from starting the loop that moves the player, also first remember the initial distance the player has to travel.
Then, within the loop that moves the player, keep track of distance traveled so far. Once the distance traveled so far is equal or larger than initial distance that needed traversing, stop the player.
Idea #2: This is a bit quicker but less robust solution:
Instead of checking if sqrRemainingDistance is larger than zero, simply check if it's larger than some fine tuned value. For example, move if distance is > 0.5, or such.
Additional problem: Even if your While loop were to finish normally, you would STILL see the player teleport to the destination.
This is because the Render of the scene happens once per frame, once all scripts have finished their execution. You have calculated and moved your player the entire distance within one While loop that executes fully within that one frame.
Instead of While loop, simply use the Update function of your script. This function executes one per frame. So, move your code from our while loop, into the Update loop (without While or other own loops). That way, each frame (each Update pass) your player will move for some small distance.
Code example
public Vector3 playerDestination;
public bool NeedsTravelling;
//[...]
//At the event that starts to move the player:
playerDestination = positionOnYourGridThatYouNeedToMoveTo;
NeedsTravelling = true;
//[...]
public void Update()
{
if (NeedsTravelling)
{
Vector3 actualDistance = playerDestination - Player.transform.position;
if (actualDistance.sqrMagnitude > 0.5)
{ //Note: You will need to calibrate the Speed value, since it's used differently now, it will have to be some small value such as 0.01 or so I assume.
actualDistance.Normalize();
Player.transform.position += actualDistance * speed;
}
else
{ //If we're close enough, do not travel anymore:
NeedsTravelling = false;
}
}
}
Thanks for the feedback :D
I implemented this to work with how the game works and it is just as I need it to be, so thanks a lot for the creative idea (knew it had something to do with endless loop couldn't figure out how to fix thx)!
I am encountering the last issue to fix th movement entirely though
I need the game to wait for a few seconds till beginning to do the movement which works great.
Problem is I can't use WaitForSeconds to do this in update nor in an IEnumerator.
Do you know by any chance a way to make it happen? thanks!
Answer by Wiebren-de-Haan · Sep 09, 2015 at 07:16 PM
I'm not an expert on explaining things, and my english is not great, but i will try to explain it :)
If you do this in a while loop, it wants to do this in that one frame it starts in. And the code only continuous when the sqrRemainingDistance == 0. This will loop infinite (can't explain why).
You can try to use this: Vector3 newPosition = Vector3.Lerp(rb.position, BattleGrid[2, 1].position, Time.deltaTime * speed); rb.position = newPosition;
Then you just check with an if statement if the rb.position == BattleGrid[2, 1], and if that is correct, you can continu with other stuff
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Movement Jumping Help 0 Answers
A* freezes unity 1 Answer