4
\$\begingroup\$

I've got two game objects a circular (circGO) and rectangular (retiGO) objects, with the rectangular larger than the circular. I want to be know when retiGO contains circGO. I tried the following but it didn't work:

retiGOBounds = retiGO.GetComponent<Renderer>().bounds;
circGOBounds = circGO.GetComponent<Renderer>().bounds;

void Update () {

    if (retiGOBounds != null & circGOBounds != null)    {
        if (circGOBounds.Intersects (retiGOBounds)) {
            Debug.Log ("We Good");
        }
    }
}

Also I saw Physics2D.OverlapArea documentation, but didn't really understand how to use it to tell when one game object contains another.

\$\endgroup\$
2
  • \$\begingroup\$ There are a few things we'll need to clarify before we can help here: 1) What do you mean by "contains"? Do you mean that visually, the circular object is wholly inside the rectangle, or that it overlaps the rectangle, or that the rectangle has the circle as a child object / descendant in its transform hierarchy? 2) What precisely "didn't work" about the code you've shown? Did it crash or generate an error, or did it give the wrong result in some situations (which?). These symptoms help us narrow down what you need. 3) Do your objects move? If so, when are you updating your bounds variables? \$\endgroup\$
    – DMGregory
    Commented Jul 6, 2017 at 22:05
  • \$\begingroup\$ @DMGregory 1) the circular object should be wholly inside the rectangle 2). The intersection if condition was never satisfied though the circular object was visually contained in the rectangle. 3) Yes the objects move, I didn't know I had to update the bounds. I thought that once there are references, the changes would be recognized within a call in the update. I hope this puts things into perspective. \$\endgroup\$ Commented Jul 7, 2017 at 4:24

2 Answers 2

3
\$\begingroup\$

Firstly, if you want to know when one set of bounds are wholly inside another one, don't test for intersection - that will return true even if the two bounds just barely touch.

The existing Contains method only works for points, but we can add our own as an extension method for convenience:

public static class BoundsExtension {

    // Note I skipped Z since you seem to be working in 2D.
    // The Bounds struct is shared between both 2D & 3D uses, 
    // so we can write explicit Contains2D / Contains3D cases if needed.
    public static bool Contains (this Bounds container, Bounds other) {
        return container.min.x <= other.min.x
            && container.min.y <= other.min.y
            && container.max.x >= other.max.x
            && container.max.y >= other.max.y;
    }
}

Next, it's important to remember that struct instances like Bounds are what's called a "value type" in C# - like booleans, numbers, and enumrations. That means that when we read them into a variable, we're taking a snapshot or shallow copy of their current value.

This is in contrast to "reference types" like class instances, where reading them into a variable means storing a reference to the existing live instance, rather than copying its current contents.

(This also means a struct can't be null, only hold a default value - so that null check on the bounds is not meaningful here. You could use Nullable structs that hold an extra flag to express "no value set" but here we have better solutions)

So, if we want to keep track of where our objects are now, we first need to store references to the reference types we care about. Since we need a Renderer specifically to get bounds data from, we can make that explicit in our script's public variables - Unity will enforce this in the Inspector, so I can't accidentally assign a GameObject that has no Renderer attached into these fields.

(You can also get bounds from a Collider2D depending on your needs)

public Renderer container;
public Renderer contents;

Then we can ask for the current value of the bounds struct each frame when we want to do the test:

void Update() {
    // Doing a null check on the references tells us if we forgot to set them, 
    // or if either of the Renderer components have been destroyed
    if(container == null || contents == null)
        return;

    // Compare our Renderers' current bounds using our shiny new Contains method.
    if(container.bounds.Contains(contents.bounds)) {
        Debug.Log("We Good");
    }
}
\$\endgroup\$
1
\$\begingroup\$

I guess you need to write your own function to check this type of intersection, because Bounds.Intersects() function checks if bounds "intersect" with other, not wholly contain the other bounds;

bool IsContaining(Bounds outerBounds, Bounds innerBounds){
        return (outerBounds.Contains(innerBounds.min)
        && outerBounds.Contains(innerBounds.max));
    }

Note: This function is pretty straightforward for your special case (checking for a circle is inside a rectangle, it will also work for two rectangles too).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .