Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Mathf Max and Min methods not working as intended

Discussion in 'Scripting' started by Gust4voSSM, Mar 9, 2023.

  1. Gust4voSSM

    Gust4voSSM

    Joined:
    Mar 9, 2023
    Posts:
    3
    I was prototyping a simple 2D IK solver and I needed to constraint the distance value that was passed to the method to a Minimun and Maximun value in order to avoid NaN assingment errors that happen when the sistem has no solution. For some reason unknown (to me at least) I keep running into those same errors nonetheless, but as soon as I pause and unpause the game it starts working as intended.
    Vídeo sem título ‐ Feito com o Clipchamp.gif

    Here is the C# class that hadles the IK:
    Code (CSharp):
    1. public class IK : MonoBehaviour
    2. {
    3.     public static Vector2 Solve(Vector2 rootPoint, Vector2 endPoint, float L1, float L2)
    4.     {
    5.         Vector2 P0 = rootPoint;
    6.         Vector2 P1 = endPoint;
    7.         Vector2 direction = (P1 - P0).normalized;
    8.         float distance = (P1 - P0).magnitude;
    9.         distance = Mathf.Min(distance , L1 + L2);
    10.         distance = Mathf.Max(distance, Mathf.Abs(L1 - L2));
    11.         float a; // the distance to the line that passes through the intersection points of two circles of centers PO, P1 and radii L1, L2
    12.      
    13.         a = (square(L1) -square(L2) + square(distance)) / (2 * distance);
    14.         float height = Mathf.Sqrt(square(L1) - square(a));
    15.         Vector2 P2 = P0 + a * direction;
    16.         Vector2 normalDirection = new Vector2(-direction.y, direction.x);
    17.         return P2 + (height * normalDirection);
    18.     }
    19.     static float square(float x)
    20.     {
    21.         return Mathf.Pow(x, 2);
    22.     }
    23. }
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,620
    Bunny83 likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,951
    I see no guarding on line 13: you blindly divide by (2 * distance) and if distance is zero, off you go into NaN land.

    Time to start debugging! Here's how:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Gust4voSSM likes this.
  4. Homicide

    Homicide

    Joined:
    Oct 11, 2012
    Posts:
    656
    haha, can one find 00mpa l00mpas there?

    I digress...
     
    Kurt-Dekker likes this.
  5. Gust4voSSM

    Gust4voSSM

    Joined:
    Mar 9, 2023
    Posts:
    3
  6. Gust4voSSM

    Gust4voSSM

    Joined:
    Mar 9, 2023
    Posts:
    3
    Thank you for your help and patience and sorry for the late reply, I had to study for some tests and dindn't have the time to mess with it. It turns out the problem was in the square root. It was supposed to be zero but i was getting a square of a tiny negative number then the NaN problem (the 2 numbers i'm subtracting look the same on debug though, so it should be zero). using abs before geting the square root solved the problem, but it really baffles me that pausing and unpausing would make the script run normally and I have no idea why.
     
  7. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,381
    By the way, when you view a float value with Debug.Log there is an implicit conversion from float to text, using the default ToString method. This does not show the full precision and might round the value. You can get a more precise read-out calling ToString explicitly with a format string For example:
    Debug.Log(L1.ToString("F8"));


    https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings