13

So I've gotten to the point in my program where I need to create a group for some sprites that the player can collide with without dying (like some other sprites I may have on screen).

I've scoured Google but it appears that the official pygame documentation is useless and/or hard to comprehend. I'm looking for just a wee bit of help from anyone who knows a bit about this.

First, I need to find out how to create a group. Does it go in the initial game setup?

Then adding a sprite to a group upon its creation. The pygame site has this to say on the subject:

Sprite.add(*groups)

So... how does one use this? Let's say I have an sprite named gem. I need to add gem to the gems group. Is it:

gem = Sprite.add(gems)

I doubt it, but without any examples to go off of on the site, I am at a loss.

Furthermore, I would love to be able to edit attributes for a certain group. Is this done by defining a group like I would a class? Or is it something I define within the definition for the existing sprite, but with an 'if sprite in group'?

ekad
  • 14,436
  • 26
  • 44
  • 46
user161592
  • 358
  • 1
  • 2
  • 12

4 Answers4

18

To answer your first question; to create a group you would do something like this:

gems = pygame.sprite.Group()

Then to add a sprite:

gems.add(gem)

Regarding the attributes for the group you'd like to edit it depends what they are. For example you could define something like this to indicate the direction of the group:

gems.direction = 'up'
timc
  • 2,124
  • 15
  • 13
7

I know this question has already been answered, but the best method is like what kelwinfc suggested. I'll elaborate so it's more understandable.

# First, create you group
gems = pygame.sprite.Group()

class Jewel (pygame.sprite.Sprite): # Inherit from the Sprite
    def __init__ (self, *args): # Call the constructor with whatever arguments...
        # This next part is key. You call the super constructor, and pass in the 
        # group you've created and it is automatically added to the group every 
        # time you create an instance of this class
        pygame.sprite.Sprite.__init__(self, gems) 

        # rest of class stuff after this.

>>> ruby = Jewel()  
>>> diamond = Jewel()  
>>> coal = Jewel()

# All three are now in the group gems. 
>>> gems.sprites()
[<Jewel sprite(in 1 groups)>, <Jewel sprite(in 1 groups)>, <Jewel sprite(in 1 groups)>]

You can also add more with gems.add(some_sprite) and likewise remove them with gems.remove(some_sprite).

jtsmith1287
  • 1,110
  • 2
  • 13
  • 24
  • 1
    I went through all that to post, and then realized the you already understood this method. :/ Oh well, haha. – jtsmith1287 Jan 14 '13 at 23:49
  • 1
    IMO using a global variable like that, especially in a class `__init__()` method, is a extremely poor programming practice. – martineau Sep 19 '18 at 09:29
  • @martineau I have to admit 6 years later I haven't fully grasped all the caveats with various practices. Would you mind explaining how this usage is bad? Not saying I disagree at all, just looking to fundamentally understand what you're pointing out. I don't even program in Python anymore and I'd hate to have old habits carry into my other projects. – jtsmith1287 Feb 09 '19 at 00:46
  • jtsmith: Global variables have long been considered bad for a [number of reasons](http://wiki.c2.com/?GlobalVariablesAreBad), none of which have anything to with Python specifically—but they're frequently used despite this because it makes the code shorter. Regardless, in this case I think it could have easily been avoided by simply passing `gems` as an argument to `Jewel`'s constructor method. So I don't think there's much excuse for doing so here on this website that gets used by so many novice programmers. – martineau Feb 09 '19 at 01:11
  • @martineau I understand the gist of what you're saying but, how exactly would one pass `gems` as an argument to `Jewel`'s constructor method? – Mitchell van Zuylen Apr 05 '20 at 10:19
  • 1
    @Mitchell: The simplest way would to explicitly pass the group to the `Jewel` subclass initializer. However, having instances of any class add themselves to a some sort of group sounds like a poor design (which might tempt you to start doing things with global variables). This is why the accepted answer — adding it to the group outside the initializer — is indeed probably the best. – martineau Apr 05 '20 at 16:00
1

Just call the super __init__ function with the list of groups. For example:

def __init__(self):
    pygame.sprite.Sprite.__init__(self, self.groups)

Then, in each class of your hierarchy, you should define an attribute self.groups and the super constructor will make the work of adding each instance to its groups. This is the cleanest solution in my opinion. Otherwise, just call the super constructor explicitly with the list of groups in every class.

martineau
  • 119,623
  • 25
  • 170
  • 301
kelwinfc
  • 3,101
  • 2
  • 14
  • 10
0

Easier yet you can pass the sprites directly on to the constructor:

gems = pygame.sprite.Group(gem1, gem2)