[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] [Announce] Python bindings for the bitmask collision detection library



Another option would be to have some new functions for direction.
Rather than adding more keyword arguments.  The benefit of that is
they can return something different.

spritecollide_direction(...) ->
[(spriteb, direction), ((spritec, direction)), ...]

groupcollide_direction(...) ->
{ spritea : ( spriteb, direction ), ... }


piman: I'd really appreciate your comments on this whole thing.




On 5/16/07, René Dudfield <renesd@xxxxxxxxx> wrote:
Hi,

for other peoples interest we have committed these changes to svn.  We
also made it use the old faster code for the default rect collision.
So it shouldn't change how fast current games go.

There's still some more changes coming though.
The main one being:
- implementing bitmask collision functions.

Which brought us on to a conversation about collision response.  As
the new mask module has the ability to return the direction of the
collisions.  So it'd be nice to make use of that functionality from
within the sprite module.

pygame.sprite already has a limited collision response mechanism.  It
allows the 'killing' of sprites upon collision.  With the dokill
arguments to groupcollide, and spritecollide functions, and the kill()
method of sprites.


However there are three types of collision+response we want: 1. - just collision detection. 2. - collision detection where the sprites are removed apon detection. 3. - collision detection where the direction is calculated and passed to the sprites to work out.

Pygame already does 1., and 2.  However 3 is useful.


3. - collision detection where the direction is calculated and passed to the sprites to work out.

Number 3, can is pretty generic (the goal of the sprite module).  So
people can implement their behaviour quite easily.  It will allow
people to ask all different questions in the behaviour of the
collision response functions that require a direction:
- did the mario character jump on the head of the creature?
- what direction should they bounce away from each other?


We worked out one way which we could do this to the sprite module so that the current api can remain, and that we can add it in such a way that directions are not calculated if they are not needed.

It is important _not_ to calculate the directions if not needed because:
- it is faster not calculating direction. (we don't want to slow down
existing games that don't use it).
- it is easier to implement just collision for custom collision
functions.  (so people can just implement new forms of collision
detection, without being forced to implement the collision direction).


There would be these changed functions:

The current collision functions:
def groupcollide(groupa, groupb, dokilla, dokillb, collided = None):
def spritecollideany(sprite, group, collided = None):
def spritecollide(sprite, group, dokill, collided = None):

The new collision functions:
def groupcollide(groupa, groupb, dokilla, dokillb, collided = None,
collided_direction = None):
def spritecollideany(sprite, group, collided = None, collided_direction = None):
def spritecollide(sprite, group, dokill, collided = None,
collided_direction = None):


The new argument is collided_direction. None means do not calculate the direction. Otherwise it should be a collision direction function.

The collision direction functions would be:
def collide_rect_direction( left, right ):
def collide_circle_direction( left, right ):
def collide_mask_direction( left, right ):

Each would of these collide_*_direction functions would return False
if there is no collision, or a vector direction if there was a
collision.


New Sprite method:

As well as a kill method, the Sprite class will gain a new collided() method.
    def kill(self):
    def collided(self, asprite, direction):

Where 'asprite' is the sprite collided with, and the 'direction' is
the direction of the collision.


So to implement sprite behaviour on a collision - you could place it in the collided method.


So that's the idea of how to implement generic collision response within the pygame sprite module.

What do you reckon?


On 5/9/07, John Krukoff <helot@xxxxxxxxxxx> wrote: > René Dudfield wrote: > > It's in pygame now. > > > > There's still a few things I need to do. > > > > - make constructor which takes a surface. > > - a 'make_surface' method in C. should take a threshold for alpha. > > - complete the documentation (now in src/mask.doc) > > - complete the unittests (test/test/mask_test.py) > > - make set_at and get_at raise IndexError when wrong index is given. > > - double check the reference counting. > > - integrate Mask into examples/testsprite.py > > > > > > JKrukoff has an idea about how to change the sprite classes so they > > can be extended to use different types of collision detection. He's > > going to write a proposal to the mailing list about it later. > > Right, so as discussed in IRC, I have a simple proposal for extending the > sprite module collision detection routines to be able to handle arbitrary > types of collisions instead of only rect collisions. I propose adding a > callback parameter to spritecollide, groupcollide, and spritecollideany > which will be a function which evaluates two sprites for a collision, > returning a boolean result. > > The default value for this parameter would be a function that uses > colliderect to evaluate the two sprites, giving clean backwards > compatibility with existing code. > > I've had to write my own collision routines in order to support mixing > bounding boxes and bounding circles, but this method would allow for such > tests to be plugged into the existing API. This functionality currently > seems urgent, as we now need an optional way to use bitmask based > collisions. As long as it has to be extended, why not do so in a generic > way? > > The attached file contains a sample implementation (sans documentation or > optimization work) which should illustrate the method. It also contains > basic collision functions for rect collisions, scaled rect collisions, and > circle collisions. > > This method also lends itself to doing tests in stages, where a less > accurate and faster collision test is used first, and then the results are > used for a second pass with a more accurate (and slower) collision test. > > Ex. > >>> import pygame.sprite as sprite > >>> a, b = pygame.sprite.Sprite( ), pygame.sprite.Sprite( ) > >>> a.rect = pygame.rect.Rect( 0, 0, 10, 10 ) > >>> b.rect = pygame.rect.Rect( 5, 5, 10, 10 ) > >>> sprite.spritecollide( a, [ b ], False ) > [<Sprite sprite(in 0 groups)>] > >>> sprite.spritecollide( a, [ b ], False, sprite.collide_rect ) > [<Sprite sprite(in 0 groups)>] > >>> sprite.spritecollide( a, [ b ], False, sprite.collide_circle ) > [<Sprite sprite(in 0 groups)>] > > Admittedly, this doesn't solve the issue of how to generate masks for > bitmask collisions (though that can be worked around in the collision > function much as radius calculations are in collide_circle), but then the > default implementation doesn't provide a rect either. This is, I think, a > change in spirit with the current sprite implementation of an extensible > container. > > There are some performance considerations, as this adds a couple of lookups > and a function call to each test, but honestly, if you're worried about > performance you aren't using the default collision functions anyway. > > --------- > John Krukoff > helot@xxxxxxxxxxx > >