Question

I'm writing a simple 'avoid the falling enemies' type game in pyglet. The objects are generated above the screen, travel downward, and are destroyed when they pass below the visible screen. However, I'm doing something terribly wrong and the longer the program runs, the number of objects rises and rises. (It was slowing down and I discovered the problem with objgraph.) When I remove this class, the problem disappears.

Falling Enemy class:

class Enemy(pyglet.sprite.Sprite):
    def __init__(self, **kwargs):
        super(Enemy, self).__init__(img=images.enemy_anim["front"], **kwargs)
        self.out_of_bounds = False

    def update(self, dt):
        self._move(dt)
        self._check_boundaries(dt)
        self._check_kill_condition()

    def _move(self, dt):
        self.y -= ENEMY_SPEED * dt

    def _check_boundaries(self, dt):
        if self.y + self.height < 0:
            self.out_of_bounds = True

    def _check_kill_condition(self):
        if self.out_of_bounds:
            enemy_list.remove(self)
            self.delete

Main method code:

enemy_list = []

def add_enemy(*args, **kwargs):
    randx = random.randint(0,
               WINDOW_WIDTH - images.enemy_anim["front"].get_max_width())
    randy = WINDOW_HEIGHT + images.enemy_anim["front"].get_max_height()
    enemy_list.append(Enemy(x=randx, y=randy, batch=update_batch))

def update(dt):
    for sprite in enemy_list:
        sprite.update(dt)

#send the above functions to the pyglet scheduler
pyglet.clock.schedule_interval(update, 1/TICKS_PER_SECOND)
pyglet.clock.schedule_interval(add_enemy, 1/ENEMY_ADD_RATE)

I have my enemy animation stored in a separate module (images) in a dictionary (images.enemy_anim).

I create an enemy with the reference inside a list.

When the enemy dies, I tell it to remove itself from the list. I've checked the length of the list during runtime and it's always the appropriate length. So the list isn't growing out of control. The object should have no references after it's removed from the list, right?

What am I doing wrong?

EDIT:

The problem was that I had self.delete instead of self.delete(). Stupid mistake...

Was it helpful?

Solution 2

As Bakuriu pointed out in the comment above, the problem was that I simply forgot a pair of parentheses on the pyglet sprite delete method. A huge problem cause by a simple and obvious mistake...

OTHER TIPS

Instead of deleting an object inside its own method, I'd go a different approach and delete the sprites in an additional schedule_interval like this:

def delete_enemy(*args, **kwargs):
    items_to_delete = []
    for enemy in enemy_list:
        if enemy.out_of_bounds:
            items_to_delete.append(enemy)
    for item in items_to_delete:
        enemy_list.remove(item)

pyglet.clock.schedule_interval(delete_enemy)

And of course remove the line self._check_kill_condition() in Enemy.update.

Edit: I don't know pyglet, but if this approach does not work either, then something inside pyglet keeps a reference to your sprite. The sprite could be referenced in a canvas or some similar object. There should be an API call in pyglet to delete a Sprite totally (i.e. from the canvas). This call should then be used right after my enemy_list.remove(item) call.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top