Check if position is inside a collider
Hey all,
This is for a teleport feature.
I am about to write a function that returns if a position is inside of a collider.That way I can negate the teleport, so the player doesn't go inside of objects.
Does unity have some magic way of doing this? I have an idea of how I can do it, but I wanted to ask here first in case there was an built in way / simple way one of you guys knew of.
Thanks
On collision, make the player's transform (Position) where you want it to be... If you want a random position, you can make it randomly select it from a couple of positions (Use empty gameobjects perhaps to get it, then you just move the player to that spot...).
Answer by s4vi0r · Jan 02, 2011 at 10:41 PM
Guys I found a good simple way of doing this. Thanks for the responses. Here is a hunk of code
I used a sweeptest on my rigidbody, I used distance and direction of my teleport location and used it as the ray to send out. I tested the what my RaycastHit got assigned to like this.
if(hitToTest.collider.bounds.Contains(telePosition))
{
print("point is inside collider");
}
Check out unity SweepTest() and Collider.bounds for specific syntax and what not
Hey, great to report your solution, but you should really mark your question as answered (using your answer). Cheers
I tried already. Says I have to wait 47 hours for some reason )=
I believe `bounds` is always just a cube, so it might not be exactly what it seems (the precise collider mesh boundary). Try this ins$$anonymous$$d: http://answers.unity3d.com/questions/163864/test-if-point-is-in-collider.html
you may as well use Collider.ClosestPoint for more precision than the bounding box. I am not sure whether it will return a point inside the collider, or always on the surface. But if it's inside, then it's easy
Answer by Socapex · Jan 02, 2011 at 10:00 PM
You can use triggers to check if objects are colliding. In the collider inspector of your object, turn on 'Is Trigger'. Then you can create a script on your object that sends out values using the OnTriggerEnter(){}, OnTriggerStay(){} and OnTriggerExit(){} functions.
Edit: You could make your teleport OnTriggerEnter(){} function modify the location of the character easily. You can access your players location from that function and change it.
Make sure one of the colliding objects is a rigidBody, since it wont trigger with an other static collider. Checl the Collision action matrix here for more information on triggers and what will trigger them.
Also, the 3d platform tutorial covers teleports IRC. Their solution might be more complete than mine, can't remember how they did it though.
Answer by chriscode · May 30, 2019 at 11:15 PM
Almost same: we used in the end:
public static bool IsInside(Collider c, Vector3 point)
{
Vector3 closest = c.ClosestPoint(point);
// Because closest=point if point is inside - not clear from docs I feel
return closest == point;
}
I was afraid of Unity's accuracy so that's why I used $$anonymous$$athf.Epsilon.
That never fails? I could change it.
Answer by Tehelee · Jul 10, 2018 at 09:38 AM
@s4vi0r has a good solution if you're using box colliders, but a lot of us are asking about colliders in general, which would include spheres, capsules, and mesh colliders. The solution bellow should account for these in a generic manner.
I should note that MeshColliders marked for triggers must also be marked convex, for similar reasons the MeshColliders you check with this code must also be convex or you may recieve eroneous results.
However this code could be modified for an IsBelow() method for use with static MeshColliders you might have for terrain.
bool IsWithin(Collider c, Vector3 point, bool useRigidbody)
{
Vector3 closest = c.ClosestPoint(point);
Vector3 origin = c.transform.position + (c.transform.rotation * c.bounds.center);
Vector3 originToContact = closest-origin;
Vector3 pointToContact = closest-point;
// If you're checking if a point is within a moving rigidbody and want to use it instead (ideally a single collider rigidbody; multiple could move the center of mass between the colliders, placing it "outside" and returning false positives).
Rigidbody r = c.attachedRigidbody;
if (useRigidbody && (r != null))
{
// The benefit of this is the use of the center of mass for a more accurate physics origin; we multiply by rotation to convert it from it's local-space to a world offset.
originToContact = closest - (r.position + (r.rotation * r.centerOfMass));
}
// Here we make the magic, originToContact points from the center to the closest point. So if the angle between it and the pointToContact is less than 90, pointToContact is also looking from the inside-out.
// The angle will probably be 180 or 0, but it's bad to compare exact floats and the rigidbody centerOfMass calculation could add some potential wiggle to the angle, so we use "< 90" to account for any of that.
return (Vector3.Angle(originToContact, pointToContact) < 90);
}
See this solution if you're looking to do checks on concave MeshColliders, but it's certainly overkill otherwise so pick the solution that works for you. http://answers.unity.com/answers/394300/view.html
Few issues with this: origin needs to be middle of the collider. e.g. c.bounds.center.
Vector3.Angle(originToContact, pointToContact) returns 90 IF inside.
public static bool IsPointWithinCollider(Collider collider, Vector3 point)
{
return (collider.ClosestPoint(point) - point).sqrMagnitude < Mathf.Epsilon * Mathf.Epsilon;
}
This is simpler and works.
:)Thanks a lot. This function works like a charm and it saved me a lot of time.
Boggles my $$anonymous$$d that this isn't built into unity. The accepted answer is actually incorrect and doesn't work if the box is rotated. Your solution works off the actual collider without having to convert the bounding box to its original unrotated state.
I'm puzzled why Unity doesn't have a Collider.IsPointWith .. IsLineWithin, etc. The bounding boxes are useless for calculations because you have convert them to to their original unrotated state and then convert any points you check against them based on the rotation. It's pretty ridiculous.
A lil late but can just do this, There's no need to check epsilon since "==" already has that check. https://docs.unity3d.com/ScriptReference/Vector3-operator_eq.html
public static bool IsPointWithinCollider(Collider collider, Vector3 point)
{
return collider.ClosestPoint(point) == point;
}
Actually it didn't fully work. I had to change tack. My use case was an enclosed edge and I wanted to know if I was inside it. I got the closest point and then cast a ray through the position being tested. If it hit the line again then it must be inside, or the line must be bent. In my case though the line could be bent I could mitigate that by restricting the cast length to a sensible value.
Answer by shieldgenerator7 · Jun 03, 2020 at 03:46 AM
What you need is OverlapPoint()
:
Collider2D collider;
Vector2 point;
if(collider.OverlapPoint(point)){
//do stuff
}
Only Collider2D has thos method. @chriscode or my solution is right for 3D colliders and points.