collisions optimization

BlitzMax Forums/BlitzMax Beginners Area/collisions optimization

hub(Posted 2006) [#1]
Hi !
in my game a use collideimage to determine if my ship collide with an enemy.

If ImagesCollide(j.hImage,j.PosX,j.PosY,j.Frame,hImage,PosX,PosY,Frame) Then
				TExplosion.Creer(PosX, PosY)
endif


see the screenshoot, in this case the enemy checked is far the player...

1) so is ImagesCollide perform a rect or oval check before test perfect pixel collision ?

2) or should i code my own check before call imagescollide to increase my game performance ? For example :

a) check if i've the ennemy is inside the 'player oval' (radius collision test, there are some formulaes posted somewhere)...

b) ... if it's the case call imagescollide for perfect collision check

Need your suggestions and your experience !
Thanks !





TartanTangerine (was Indiepath)(Posted 2006) [#2]
In the interests of speed

1) Check to see if bounding rectangles overlap.
2) Check to see if bounding circles overlap (you can miss this).
3) Perform Collision check proper.
4) Report collision.

Step 1 is very fast as this can be calculated using very simple boolean logic. Step 2 take a little longer as you need to use multiplication and square root calculations.


QuietBloke(Posted 2006) [#3]
step 2 shouldnt really need square root calculations. Instead of storing the radius of the bounding circle for each sprite you can store the radius squared.
That way when you want to see if the bounding circles have collided you simply calculate the distance between the two sprites and square it and compare the result with the sum of the stored 'raduis squared' of the sprites.

Did that make sense ?


hub(Posted 2006) [#4]
for 1) this ?

Function RectsOverlap%(x0, y0, w0, h0, x2, y2, w2, h2)
If x0 > (x2 + w2) Or (x0 + w0) < x2 Then Return False
If y0 > (y2 + h2) Or (y0 + h0) < y2 Then Return False
Return True
End Function

for 2 this ?
(stored for each sprite)

local radius# = sqr( ImageWidth(img)*ImageWidth+ImageHeight(Img)*Imageheight)


and for 3 ImagesCollide;-)


hub(Posted 2006) [#5]
1) so is ImagesCollide perform a rect or oval check before test perfect pixel collision ?

answer seems to be 'no' ?


Grey Alien(Posted 2006) [#6]
well I found this was the case in Blitz PLus, I *assumed* it would check and was amazed to find out it didn't, or at least it was faster with my own checks!


Dreamora(Posted 2006) [#7]
I would not use ImagesCollide unless you have no static objects and you really need to check everything against everything.

BMs new way with the collision layers is more powerfull and its ability to return any given object you give it, as the collision result gives you more power than ever.


hub(Posted 2006) [#8]
Dreamora i use also the system with the collision layer (to test collision between :
map tiles, map static object and players.

else i now use imagescollides after my own tests. For example, i test an ennemy collision box with the player and after call imagescollide. For the projectiles (for example the player shoot), before the call to imagescollides, i compute the distance between the shoot and the ennemy.

The thing i don't know how to with bmax collision system layer is to return the 'projectile id' when for example it collide with a maptile, and remove it from my projectiles list.


Dreamora(Posted 2006) [#9]
Urgs ...

Do not use distance checks unless you do distance square tests!
using SQRT will cost you an "extreme" amount of time, that is not really be needed in a 2D game (you can't make worlds large enough as screens can't have that high resolutions ;-) )


hub(Posted 2006) [#10]
no use sqr function for distance. i just use this test :

(dx-ox)(dx-ox)+(dy-oy)(dy-oy) < d*d

but agree with you, i should use a box check...


Dreamora(Posted 2006) [#11]
local radius# = sqr( ImageWidth(img)*ImageWidth+ImageHeight(Img)*Imageheight)


That's what you posted above.
Use Squared Radius instead, ie without the sqr ... Or did you change that and mean that? In that case ignore this posting :D


hub(Posted 2006) [#12]
oups... sorry, i not use radius ;-) i'm modified my code to use check box and not use (dx-ox)(dx-ox)+(dy-oy)(dy-oy) < d*d.

(for small projectile center_x, center_y)

Function Checkbox(x0, y0, w0, h0, center_x, center_y)
If x0 > center_x Or (x0 + w0) < center_x Then Return False
If y0 > center_y Or (y0 + h0) < center_y Then Return False
Return True
End Function


Haramanai(Posted 2006) [#13]
Looks like you are trying to use AABB ( Axis-aligned Bounding Boxes)
Check this out.

Test the two AABB and if returns 1(true) check pixelPerfect.
The problem with that is that you will have to reposition in every frame the AABB Fields.
For example if the handle of you picture is at the middle of the image and the position of the image is at x , y.
MinX = x - ImageWidth/2 , MinY = y - ImageHeight/2 , MaxX = x + imageWidth/2 , MaxY = y + imageHeight/2.
The best is to store somewhere the ImageWidth/2 and ImageHeight/2.
The problem with this is that you will have to check for collisions for all your objects in the game. For example if you have in the level 300 enemies you will have to run 300 times the TestAABBAABB and to update all AABB.
One good solution (I haven't checked this yet) is to split your map in AABBs. Put a byte in your enemies’ types that will tell them if they are going to be Active.
Then you will have active only the enemies of the AABB that you are in and the neighbours of it. Also it's good to have a (pointer) of the AABB that your enemies are belongs to before you make them active. After that if an enemy goes beyond the neighbours AABB change the pointer to the current AABB and deactivate him.
I believe that this will speed up your game. Just make a test with a small map to see how it’s going to look like.


hub(Posted 2006) [#14]
Many thanks for your explanations. fi you want you can test my first try to increase my game speed.

download it from this page : http://www.bayre.com/zigwigwis/telech.php

during the game press 'f' to show the fps and 'm' to show the 'main code loop execution time'. You can see the boxes, cones by pressing 'c' (but it slowdown the game).