I am working on LibGdx framework for developing a 2D isometric tower defense game.All my sprites are drawn in 2D isometric view.
I have used an array list to store 8 points at boundary in the rectangle.LibGdx has an inbuilt function (returns Boolean) ellipse.contains(x,y),by iterating through array list I can check whether any points are inside ellipse
But the problem is as shown in below picture,it wont detect the enemies in some particular cases
So my question is:
1)Is this a correct approach for solving these kinds of problems
2)If not can you suggest better approach for solving this problemThank you.
Answer
I’m going to tell you how to do it with a computationally cheap way in terms of CPU usage.
First, let’s say that the calculation of seking if a point is “inside the ellipse or not” is not computationally cheap, while comparing just rectangles with mere “greater than” or “less than” comparisons are ultra cheap.
Definition 1) Ellipse and its quadrants
If the perspective is isometric I’m going to assume that the axes of the ellipse E
are always horizontal and vertical.
The axes define 4 quadrants Q
around the center of the ellipse E
as seen in the following picture. Let’s name them like this:
QTL
= Quadrant Top LeftQTR
= Quadrant Top RightQBL
= Quadrant Bottom LeftQBR
= Quadrant Bottom Right
Note that the quadrant is all the area defined by the axes, like for example, the blue area for QBR, which comprises the area inside the ellipse and the area outside it, despite of where the labels are set in the image.
Definition 2) Ellipse and its bounding box
Now let’s define a bounding box B
around the ellipse E
, like in this image:
Now let’s focus in the areas of the quadrants that belong to the inside of the bounding box. Let me give the Exx
names for the areas inside the ellipse and the Dxx
names for the “diff” of the bounding box less the ellipse (so the bounding box area that is not inside the ellipse).
Those are the names for the areas inside the ellipse:
ETL
= Ellipse Top LeftETR
= Ellipse Top RightEBL
= Ellipse Bottom LeftEBR
= Ellipse Bottom Right
And these for the “diff areas” (the ones inside B
but outside E
):
DTL
= Diff Top LeftDTR
= Diff Top RightDBL
= Diff Bottom LeftDBR
= Diff Bottom Right
Definition 3) Enemy rectangles
Additionally, watching your images, I’m going to imagine that the enemies are always bound with a rectangle R
whose sides are exactly horizontal and vertical.
Also, I am going to use only the 4 vertexes V
of the rectagle and forget about the intermediate points you used.
Algorithm
Step 1. Check the bounding box
If the enemy rectangle R
is outside the bounding box B
then for sure it is outside the ellipse E
.
Checking this first saves a lot of calculation as you forget expensive calculations to discard a lot of rectangles (and most of the time enemies shall be far).
You can check if R
is outside B
by checking each 4 sides:
R
is outside B
if and only if:
- The bottom side of
R
is higher than the top side ofB
OR - The top side of
R
is lower than the bottom side ofB
OR - The left side of
R
is more to the right than the right side ofB
OR - The right side of
R
is more to the left than the left side ofB
.
In other words: If any of those conditions are met, then the enemy R
is outside the bounding box B
. This is the same than saying than if all those conditions are false, then R
shares some area with B
.
If the enemy R
is outside the bounding box B
set collision to false and end the algorithm here.
Note that checking the bounding box is a cheap operation.
Step 2. Quadrant check
If you are here, it means that your enemy R
shares at least one small area with the bounding box B
, and we require further analysis to see if the enemy collides or not with the ellipse E
.
Look at this image:
I have painted rectangles of 3 types here. The green and yellow rectangles share a common characteristic: All the 4 vertexes of the rectangle R
fall in the very same quadrant. And this does not ensure if the enemy R
collides with the ellipse E
or not.
Instead, all the red rectangles also share not only one characteristic, but two:
- Feature 1: All the red rectangles have vertexes that do not fall in
the same quadrant. - Feature 2: All the red rectangles collide with the
ellipse.
Why this happens? Because the red rectangles all cross, at least, one axis. And the axis points that are crossed are necessary inside the ellipse, as if R
crossed an axis outside the ellipse we would have catched that R
while checking the bounding box, as the bounding box is precisely the limit where the axes change from “inside the ellipse” to the “outside of it”.
So if one rectangle not catched in step 1, then, in step 2, has vertexes in different quadrants, then necessarily it happens that some points of some axis that are also contained in the ellipse E
are shared with the rectangle R
. This means that the rectangle R
for sure collides with E
at least on those axis points and for sure all non-axis points surrounding the points mentioned before, to the extent of the limit of R
or E
whichever comes first.
So… if a rectangle has vertexes in any different quadrant than the other vertexes of itself, just mark collision = true
and exit the algorithm.
Note that checking if all vertexes fall in the same quadrant is merely checking coordinates with “greater than” or “less than” comparisons, so it’s a cheap operation.
Step 3. Ellipse check.
So, finally, we enter step 3 only with green and yellow rectangles. Ie: it’s a pre-requisite we may assume. Enemies R
here shall match that:
- They collide with the bounding box.
- All the vertexes of
R
fall in a single quadrant.
We can then conclude that:
- ‘At least one vertex’ shall lie in the part of the area of the quadrant that is within the bounding box.
- Which is the same to say that ‘at least one vertex’ shall lie either in the
Exx
area or theDxx
area. - And which is that vertex? This happens at least to the ‘nearest vertex to the center of the ellipse’.
So we can reformualte the conclussion as:
- The vertex
V
of the rectangleR
which is nearest to the center of the ellipseE
must fall necessarily in the ellipse areaExx
or the diff areaDxx
.
But it also happens that, by Reductio ad absurdum we can say that:
- If the nearest vertex defined above falls in in the diff area
Dxx
(ie: does not fall inside the ellipse) then no other pointP
in the enemyR
can be touching the ellipse. The demonstration is that if with this hypotheses we could find another pointP
that was touching the ellipseE
then the tested vertexV
could not be the nearest to the center of the ellipse which contradicts the hypotheses.
We don’t care if “the other vertexes” are inside or outside the box. And you don’t have to do complex maths to select the nearest vertex… just it is straight forward:
- For the Top Left quadrant, choose the Bottom Right vertex of
R
. - For the Top Right quadrant, choose the Bottom Left vertex of
R
. - For the Bottom Left quadrant, choose the Top Right vertex of
R
. - For the Bottom Right quadrant, choose the Top Left vertex of
R
.
Those vertexes are highlighted in the green and yellow rectangles of the picture.
Just then test one single selected vertex with the expensive maths. Test that vertex against the ellipse.
Set the collision
flag if the selected vertex is in the ellipse area Exx
, otherwise the vertex shall lie in Dxx
and leave collision
clear.
Computationally the cost of this 3rd step is just one single complex calculation at most. Never more than 1 vertex per rectangle.
End of the algorithm.
I hope I have helped! Cheers.
Attribution
Source : Link , Question Author : Shersha Fn , Answer Author : Xavi Montero