Question

I'm working on simple game in Python and Pyglet. I want to give possibility to shoot so I create a bullet class. If I create one instance of that class for example
self.new_bullet = bullet()
I'm able to have only one instance at the moment. My question is how to create many instances at same time and be be able to refer to them and their variables? Example code (with pieces of pseudocode):

if key pressed:
    self.new_bullet = bullet()

... somewhere in main loop ...
bullet_image.blit(new_bullet.x, new_bullet.y)
self.new_bullet.x += 5

class bullet:
    def __init__(self):
        self.pos_x = player.pos_x
        self.pos_y = player.pos_y

So how should I create as many bullets as player wishes and still be able to give them speed and update their positions on screen?

Was it helpful?

Solution

I think that you want a list of bullet objects. Then, you can add to your list using append, and during your main loop you can iterate through all of them using a for loop.

self.bullets = []
self.bullets.append(bullet())
self.bullets.append(bullet())

In your main loop:

for bullet in self.bullets:
    bullet_image.blit(bullet.x, bullet.y)
    bullet.x += 5

OTHER TIPS

You might also want your bullets to be Sprites grouped to a Batch for faster execution (in case of heavy fire). The pygletdocs show how its done:

batch = pyglet.graphics.Batch()

bullet_image = pyglet.image.load('bullet.png')
bullet_sprites = [] # I've changed the variable names to fitting our issue
for i in range(100):
  x, y = i * 10, 50
  bullet_sprites.append(pyglet.sprite.Sprite(bullet_image, x, y, batch=batch)

First, a fresh Batch is created. Next, 100 distinct Sprite objects are instantiated, each of which acts as a well-suited container for one bullet (or balls, but let's pretend we've got bullets here). Each call of the Sprite constructor passes an optional reference to our batch, thus attaching all newly created bullet Sprites to the bullet Batch.

The beauty of it is the draw() method of the Batch class. When calling it, care is taken of the blitting of every bullet in the batch. You don't have to call each bullet Sprite's draw() method yourself, because that can be done more efficiently in only one single call:

@window.event
def on_draw():
  batch.draw()

You will recognize that this example, much like the one @Xymostech gave in the first answer, populates a list with all bullet instances as well. You will still need a Collection structure like this to keep the references to your Sprites, since Batch has no function that would return a list of the objects attached to it.

So, you will stick with the solution in the previous answer, except for the Image blitting of course.
Another advantage of using Sprites is that you don't have to equip your bullet class with its own positional fields, because you can use the corresponding parameters of your Sprite objects. Beside allowing to update its (x, y) coordinates, Sprites can also rotate and fade out.

Actually, you should consider modifying your bullet class into being an extension of the Sprite class by inheriting from it.

class Bullet(pyglet.sprite.Sprite): # btw, class names usually start with an Uppercase letter
  def __init__(self):
    super(pyglet.sprite.Sprite, self).__init__()
    self.x = player.pos_x
    ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top