- Home /
The question is answered, right answer was accepted
Differentiate an overlapping collision from just touching
So, I have a grid and you can build fixed size walls in that grid. I'm using simple onTriggerEnter/onTriggerExit to determine where I can/can't build walls. Now the problem was, onTriggerEnter is also fired off when the objects just touched, so I could not build adjacent walls. I fixed that by setting the collider size to 99% of the mesh in all dimensions. The meshes could touch, but not overlap (as the grid is larger than the 1% difference).
Now, I'm trying to set up a way to merge my wall meshes to get a performance boost down the line. The simplest way would be to just merge everything that is touching... but because of the above mentioned 99% sized collider box, technically, nothing in the grid ever touches.
I thought about calculating distance and comparing to object size, but you can build in all 3 dimensions and you can modify the size of your construction piece in all 3 dimensions, so everything's irregular and checking against every other thing in the scene (and I'm thinking of hundreds/thousands of pieces down the line) would be a pain.
So the problem in a sentence: how do I tell the difference from when two colliders are actually inside each other and from when they just share a few surface coordinates? That's the minor issue though. The major issue is merging meshes that are close by each other. If not with collision, how else would I go about doing that? I'm not asking for code here, just give me ideas what to do, and I'll try to work it out.
Answer by SinisterRainbow · Jun 29, 2013 at 09:23 PM
Edit: In that case -- The easiest way then, I can think to do this is, assuming both colliders are cubes only, and one entering the other is small in size, is to test the distance between the centers of the colliders. This is by far the easiest and faster.
If not cubes, then a more generic function is needed. I don't think Unity has an "OnInside" function exposed, surprisingly but it's not difficult, just six possible cases to test:
//Psuedo Code:
bool IsInside(Box other)
{
return maxEdge.X <= other.maxEdge.X &&
maxEdge.Y <= other.maxEdge.Y &&
maxEdge.Z <= other.maxEdge.Z &&
minEdge.X >= other.minEdge.X &&
minEdge.Y >= other.minEdge.Y &&
minEdge.Z >= other.minEdge.Z;
}
Should work for all axis aligned stuff (i.e. world coordinates)
OLD: I think you need something like:
bool m_bSomethingIsTouching = false;
//check if it enters
//note, this script only works iff just one object will ever move into another
void OnTriggerEnter() {
m_bSomethingIsTouching = true;
}
void Update() {
if (m_bSomethingIsTouching) {
if (gameObject.collider.bounds.Contains(enteringObjPosition)) {
// Something is inside!
}
}
void OnTriggerExit() {
m_bSomethingIsTouching = false;
}
as for merging meshes, i'll let someone more qualified answer that. should probably break this into two separate questions.
I can merge the meshes myself, I just need to know WHEN to do it.
As for your answer, bounds.Contains returns true when objects touch, IE share one side of a boundary. I've already tried it :) And yeah... I need multiple objects at once, not just one. I'm already using onTriggerEnter/Exit with multiple objects colliding, by tracking the number of enters and exits and only setting the colliding bool to false when its 0. But that's for overlapping. I need touching logic. As I said, I can work out the code myself, I just need an approach.
Actually, rectangles have twelve edges, not six. And your $$anonymous$$d seems to work in the exact same pattern $$anonymous$$e does. As this was the second thing I tried.
//Script takes each of the four points at the bottom of the
//rectangle and goes up along them in grid sized steps,
//checking for collisions with the other object
pointX = $$anonymous$$.x;
pointZ = $$anonymous$$.z;
for(float i = $$anonymous$$.y; i < max.y; i += gridSize)
{
if(other.Contains(new Vector3(pointX, i, pointZ)))
return true;
}
pointX = max.x;
for(float i = $$anonymous$$.y; i < max.y; i += gridSize)
{
if(other.Contains(new Vector3(pointX, i, pointZ)))
return true;
}
pointZ = max.z;
for(float i = $$anonymous$$.y; i < max.y; i += gridSize)
{
if(other.Contains(new Vector3(pointX, i, pointZ)))
return true;
}
pointX = $$anonymous$$.x;
for(float i = $$anonymous$$.y; i < max.y; i += gridSize)
{
if(other.Contains(new Vector3(pointX, i, pointZ)))
return true;
}
Now as you can see my problem is, that I'm using contains() to find collisions. And, as I said earlier, this returns true even if the point is on the boundary edge, not just inside it. I also tried adding and if SqrDistance == 0, which returns the $$anonymous$$imal distance from the point to the bounding box. And that worked for touching, BUT it would also think that this:
was touching, because as you can see, it shared a single wall. And the idea behind the script was: if its a collision and has shared walls, its a touch, otherwise its an overlap.
So, this is where my $$anonymous$$d caved in and came here for help. Can yours give me the next solution I never thought of? :) And thanks for trying to help.
the pic link is broke
You know, I don't think I've been reading what you were trying to do correctly, and going back I am definitely unclear. The alg above is for checking if a box is completely inside another box, is sound, but not what you want apparently.
Or do you mean, you're constructing a wall, and you try to set one adjacent to another, but failed before because the colliders touch and you are saying that your dimensions are exact and assu$$anonymous$$g that the only way it's touching is on the surface?
I think maybe it's time to scrap the oncollision detection. if you're doing what i know think you are doing, it requires much less computation and checking to store grid positions and data of placed objects:
So for example, you could use a dictionary that stores grid pieces that have been placed and see if one exists in that grid position or not, and check adjacent cells. $$anonymous$$uch easier just to check a bool if one exists in that cube/square or not..Even with thousands of objects, dictionary is O(1) lookup, and no further processing. It's also more flexible, so if ure building a wall and want a door in the middle say, the door will check to make sure two walls are on either side - which is not possible with collision (not easily possible at all anyway).
Also, allowing users to resize objects then trying to merge them will need more explaining, that could be extremely complex, unless say you are resizing in one dimension only at fixed grid intervals.
on another note, why merge? Batching will take care of most of your problems both drawcalls and vert counts. but resizing could break that I believe (not sure about scaling equally in all directions, may be ok, you'll need to double check the batching docs). The only reason i have thought about merging meshes in my game is to make textures look smoother, but this actually destroys batching and if it doesn't merge a LOT together, it probably isn't worth it.
But putting walls next to each other may be different. For example, when putting two wall pieces, you could always spawn a 'tower' or some piece to cover up the seams between them..It would look great.
No idea why the pic broke, uploaded it elsewhere.
Anyway, the idea of actually storing the grid ($$anonymous$$ine is only virtual) had occurred, but I dreaded it for some reason. And yeah, as you say, there will eventually be other objects like doors and whatnot that would need those kinds of checks. Sigh...
Convert your last comment to an answer and I'll tick it correct :)
Follow this Question
Related Questions
How to combine sprites to create a seamless and efficient level 0 Answers
How can I optimize a very large terrain mesh? 0 Answers
Resize particle effects 2 Answers
How to make a mesh programatically. 1 Answer