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. Dismiss Notice

Checking to see whether the Bounds value's of two game objects equal each other

Discussion in 'Scripting' started by egonspengler_84, May 3, 2021.

  1. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    Hi there,

    So basically I have two game objects in a scene - one is just a rectangle shaped game object and the other is a wall. Both game object have BoxCollider2D components attached to them. The rectangle has a Dynamic Rigidbody2D attached to it.

    Basically I have code that makes the rectangle travel horizontally to the right towards the wall. I have an if statement that states when the X value of the Bounds.Max position of the rectangle touches the X value of the Bounds.Min position of the wall I message should pop up in the console.

    Here is the code that I have:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerNew : MonoBehaviour
    6. {
    7.     private Rigidbody2D _rb;
    8.     private BoxCollider2D _col2D;
    9.     private float X_force = 25f;
    10.     public Vector2 newPosition;
    11.     public Vector2 bottomRight;
    12.    
    13.     public Vector2 wallBoundsMin;
    14.    
    15.  
    16.     // Start is called before the first frame update
    17.     void Start()
    18.     {
    19.      
    20.       _rb = GetComponent<Rigidbody2D>();  
    21.       _col2D  = GetComponent<BoxCollider2D>();
    22.       wallBoundsMin = GameObject.Find("Wall").GetComponent<BoxCollider2D>().bounds.min;
    23.  
    24.     }
    25.  
    26.     // Update is called once per frame
    27.     void Update()
    28.     {
    29.        
    30.         bottomRight = new Vector2(_col2D.bounds.max.x,_col2D.bounds.min.x);
    31.        
    32.  
    33.  
    34.         newPosition = new Vector2(X_force,0);
    35.        _rb.MovePosition(_rb.position + newPosition * Time.deltaTime);
    36.  
    37.  
    38.       if(bottomRight.x == wallBoundsMin.x){
    39.         Debug.Log("Bounds have collided with one another");
    40.       }
    41.      
    42.        
    43.     }
    44. }
    45.  
    However nothing appears in the console when the rectangle crosses the wall. But the message actually does appear in the console if I change the if statement to the following:

    Code (CSharp):
    1. if(bottomRight.x >= wallBoundsMin.x){
    2.         Debug.Log("Bounds have collided with one another");
    3.       }

    I'm confused as to why the message wont appear when I just check to see when the two X value's equate to one another? I don't think I've written the code incorrectly? Here is a video of the issue:


    Any help would be appreciated.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    Never compare floating point numbers for equality. They will rarely be identical due to floating point imprecision.

    Instead use Mathf.Approximately or make your own notion of an epsilon term.
     
  3. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153

    Okay so I've tried to rewrite the if statement as follows:


    Code (CSharp):
    1.    if (Mathf.Approximately(bottomRight.x , wallBoundsMin.x))
    2.         {
    3.             Debug.Log("Bounds have collided with one another");
    4.         }
    But I still can't get the Debug.Log message to appear in the console in Unity? I don't think I've written it wrong?
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    Don't waste any more time: start printing out the actual data and seeing for yourself!!!!
     
  5. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    I don't understand? What data specifically would I need to print to the console that would help me understand the issue? All of the relevant variables in my code are declared publicly so I can see them in the inspector already.
     
  6. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    he means output both the bottomRight.x and wallBoundsMin.x and he is right, these will NEVER be the same as they are floatingpoint numbers and unity only calculates them per Update(). In one Update() you box's x will be lower than the frame's minx while in the next Update() it will be already higher. they will be equal sometimes inbetween when your code does not run because your computer is busy drawing the next picture on your monitor. that's why >= works and == does not

    if you stop running the code when the collision happens, you will see that it will be a nice collisiondetection as the difference will be minimal
     
    Kurt-Dekker and stain2319 like this.
  7. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    The fact that floating point numbers will never be the same has been explained to me already by Kurt Decker in his first response to my post. He then suggested that I use "Mathf.Approximately" which I then implemented into my existing code. I assumed this would fix my issue but as I explained already it hasn't solved the problem.

    I'm a bit confused as to why he would suggest to use Mathf.Approximately in the first place? Why is he telling me to output the float values to the console(which I already have) after he's told me that using Mathf.Approximately would solve my issue?

    I've implemented the function in my code as suggested and then after I have explained that it hasn't solved the issue I am told to output the float values?? Are you now saying that the Mathf.Approximately function WONT work in my case?
     
    Last edited: May 4, 2021
  8. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    because that does kinda what you want BUT it uses a very small difference. if the difference between box's x and minx is bigger than mathf.epsilon, then approximate will not be true. its more useful for floating point rounding errors anyway, not really for your problem but was worth a shot

    because you have already told that mathf.approximate did not work and he tried an other approach. this is how programming works. we try many things if the first ones does not work...

    yes, thats what Im saying. just stick to the >= because there is no more precise solution. whatever you wanna do in your game, you have to do it in the first frame when box's x will be >= to the frame's minx
     
  9. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    Okay, so based on what you've said I've re-written the code to say the following:

    Code (CSharp):
    1.  
    2.         if(bottomRight.x >= wallBoundsMin.x){
    3.  
    4.          Debug.Log("Bounds have collided with one another");
    5.      
    6.  
    7.         }else{
    8.  
    9.           _rb.MovePosition(_rb.position + newPosition * Time.deltaTime);
    10.  
    11.         }
    12.  
    And although the rectangle stops when it hits the wall it does not stop precisely at the point where it should stop every time I run the game.

    Here is a video I've uploaded that can better explain the issue:


    You can see that every time I run the project the rectangle does not stop at the exact same position every time. Would this have something to do with the fluctuating frame rate? Is there a way I could fix this?
     
  10. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    Yes, this is the expected behaviour and is caused by the framerate, more explicitly the drawing time of the last frame before it stops. there isnt a way to fix it. what you can do is to set the position of your box to the last acceptable position after you stopped the box.

    something like if(bottomr.x >= min.x) box.x = min.x - box.width / 2.

    it will jump the box back a bit so it will look like it stopped at the right place and it should be invisible to the eye
     
  11. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    I've changed the if statement to the following:


    Code (CSharp):
    1.         if(bottomRight.x >= wallBoundsMin.x){
    2.  
    3.          Debug.Log("Bounds have collided with one another");
    4.          transform.position = new Vector2(_wallCol2D.bounds.min.x -_col2D.bounds.extents.x,transform.position.y);
    5.      
    6.  
    7.         }else{
    8.  
    9.           _rb.MovePosition(_rb.position + newPosition * Time.deltaTime);
    10.  
    11.         }
    12.  
    13.  
    So basically I'm saying that when the X float value of the rectangle's MAX position crosses with the X float value of the walls MIN position the X value of the rectangle's transform position should equal the wall's MIN position X value minus the extents.x of the rectangle's Bounding Box.

    That was a very convoluted way of explaining what I had written but it seems to have worked as shown here:




    Even though this seems to work I'm just wondering whether this is a very ungraceful way of doing things? Am I doing anything extremely wrong by creating a collision in this way?
     
  12. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    yes :D this is a very ungraceful way but sadly there aren't many better ones.

    you have to get used to compromise with these graphical engines that turned the logic inside out. in my days we had a core logic that run all our calculations as main threads and the graphics was only a visualisation layer on top of it. Now, due to the time requirement of drawing a frame, the graphics runs on the main thread and the core logic is written in fragments that is calculated in the free time between the frames. that's where you have to solve everything. the only way I can think would yield a better picture if you would start a background thread. in that background thread you would calculate the movement of a virtual box with the precision you need and yield the positions and collisions every so often and in the update you would use the background calculated position to move the visual box. this is the same what unity does, but unity does a lots of other things in its background thread, you could just focus on moving the box. on the other hand, I don't think its worth the effort. still if you want to try or experience with it, google async yield thread...
     
  13. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    I'm just going over the last couple of posts you made regarding floating point imprecision.

    This may be a stupid question but does the imprecision of floating points affect how accurate raycasts are? If a raycast is being fired the corner of a game object and hits another game object that has a LayerMask would the distance information stored in that raycast be imprecise? Would "RaycastHit.point" be imprecise also?
     
  14. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    everything that uses floating point calculations will have imprecision, there is no way around it, the question is why would that really bother you as these are so small differences.... its just you cant use equality test on them as they are not equal, but they are invisible to the user. the above issue was because of the time a frame is being drawn and that time can be pretty big in some cases
     
  15. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    I know that I'm going off topic with my original post but I was wondering whether you could help me with a problem I have with using Mathf.Approximately and Mathf.Epsilon in regards to comparing two float values together?

    I have a square falling and hitting the ground with a raycast projecting from the square's bottom that hits the ground beneath it. If I have a if statement that outputs a message when the raycast's distance is equal zero it works perfectly. So for example there's no issues when I write the following:

    Code (CSharp):
    1.  
    2. if(hit && hit.distance == 0){
    3.  
    4.            Debug.Log("Raycast distance equals zero");
    5.  
    6.         }*
    7.  
    But if I write the following if statement then no message in the console appears at all:

    Code (CSharp):
    1.  
    2.  
    3. if(hit && hit.distance == 0.015f){
    4.  
    5.            Debug.Log("Raycast distance equals 0.015f");
    6.  
    7.  }
    8.  
    I don't understand why the first if statement works but the 2nd one does not? I would of assumed that both of the if statements would not work because of floating point imprecision?
     
  16. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120
    No, or partially, the main reason is the need of drawing the frame that takes lots of time, like 0.02sec. any movement between 0sec and 0.02 sec will not be accounted for (depending on frame rate, at 30 fps its 0.035sec). Its very much possible that in one frame your object is 0.018f from the hit point and at 0.009f in the next frame hence its never 0.015f.
    0.00f works only if the physics accounts for reaching ground level and adjusts the position to make the object "sitting" on the ground, otherwise that would not work either as you have seen it when you were hitting the side wall
     
  17. vargata

    vargata

    Joined:
    Nov 26, 2013
    Posts:
    120