简体   繁体   中英

Python pygame - Deleting offscreen sprites

I created a simple 2D game with python 2 and pygame where you have to avoid squares that are moving down. I created this class for the 'enemy':

class Enemy(pygame.sprite.Sprite):

  def __init__(self, game):
      self.groups = game.all_sprites
      pygame.sprite.Sprite.__init__(self, self.groups)
      self.game = game
      self.image = pygame.Surface((TILESIZE + 10, TILESIZE + 10))
      self.image.fill(ENEMY_COLOR)
      self.rect = self.image.get_rect()
      self.x = random.uniform(0, WIDTH - TILESIZE)
      self.rect.x = self.x
      self.y = 0

  def update(self):
      if self.rect.colliderect(self.game.player.rect):
          self.game.deaths += 1
          self.game.score = 0
          self.game.run()
      self.rect.y += (self.game.score + 500) / 50

Then, I have a thread that creates an instance of the enemy:

class Create_Enemy(Thread):

  def __init__(self):
      Thread.__init__(self)

  def run(self):
      while True:
          while not game.game_paused:
              time.sleep((game.score + 1) / game.speed)
              Enemy(game)

Then in the draw method i just write self.all_sprites.draw() The game is an infinite runner, and every frame the enemies move a few pixels down. The problem is that after a bit the game gets laggy since, when the blocks go offscreen, the sprites don't get deleted. Is there a way to automatically delete the offscreen instances?

I tried the following but it just deletes all the enemies onscreen.

if self.rect.y >= WIDTH:
    self.rect.kill()

I was thinking I could do something like game.all_sprites.pop(1) (the position 0 is the player) but I couldn't find a way to archive something similar ...

Check the values of self.rect.y, WIDTH, maybe the method kill. It looks like self.rect.y is always greater or equal WIDTH, that's why it kills them all.

The enemies can remove themselfs from the game by calling self.kill() if their rect is no longer inside the screen, eg:

def update(self):
    if self.rect.colliderect(self.game.player.rect):
        self.game.restart() // reset score + count deaths

    // we can simply use move_ip here to move the rect
    self.rect.move_ip(0, (self.game.score + 500) / 100)

    // check if we are outside the screen
    if not self.game.screen.get_rect().contains(self.rect):
        self.kill()

Also, instead of the thread, you can use pygame's event system to spawn your enemies. Here's a simple, incomplete but runnable example (note the comments):

import random

import pygame

TILESIZE = 32
WIDTH, HEIGHT = 800, 600

// a lot of colors a already defined in pygame
ENEMY_COLOR = pygame.color.THECOLORS['red']
PLAYER_COLOR = pygame.color.THECOLORS['yellow']

// this is the event we'll use for spawning new enemies
SPAWN = pygame.USEREVENT + 1

class Enemy(pygame.sprite.Sprite):

    def __init__(self, game):

        // we can use multiple groups at once. 
        // for now, we actually don't need to
        // but we could do the collision handling with pygame.sprite.groupcollide()
        // to check collisions between the enemies and the playerg group
        pygame.sprite.Sprite.__init__(self, game.enemies, game.all)
        self.game = game
        self.image = pygame.Surface((TILESIZE + 10, TILESIZE + 10))
        self.image.fill(ENEMY_COLOR)

        // we can use named arguments to directly set some values of the rect
        self.rect = self.image.get_rect(x=random.uniform(0, WIDTH - TILESIZE))
        // we dont need self.x and self.y, since we have self.rect already
        // which is used by pygame to get the position of a sprite


    def update(self):
        if self.rect.colliderect(self.game.player.rect):
            self.game.restart() // reset score + count deaths

        // we can simply use move_ip here to move the rect
        self.rect.move_ip(0, (self.game.score + 500) / 100)

        // check if we are outside the screen
        if not self.game.screen.get_rect().contains(self.rect):
            self.kill()

class Player(pygame.sprite.Sprite):

    def __init__(self, game):
        pygame.sprite.Sprite.__init__(self, game.all, game.playerg)
        self.game = game
        self.image = pygame.Surface((TILESIZE, TILESIZE))
        self.image.fill(PLAYER_COLOR)
        self.rect = self.image.get_rect(x=WIDTH/2 - TILESIZE/2, y=HEIGHT-TILESIZE*2)

    def update(self):
        // no nothing for now
        pass


class Game(object):

    def __init__(self):
        // for now, we actually don't need mujtiple groups
        // but we could do the collision handling with pygame.sprite.groupcollide()
        // to check collisions between the enemies and the playerg group
        self.enemies = pygame.sprite.Group()
        self.all = pygame.sprite.Group()
        self.playerg = pygame.sprite.GroupSingle()
        self.running = True
        self.score = 0
        self.deaths = -1
        self.clock = pygame.time.Clock()

    def restart(self):
        // here we set the timer to create the SPAWN event
        // every 1000 - self.score * 2 milliseconds
        pygame.time.set_timer(SPAWN, 1000 - self.score * 2)
        self.score = 0
        self.deaths += 1

    def run(self):
        self.restart()
        self.player = Player(self)
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))

        while self.running:
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    self.running = False
                // when the SPAWN event is fired, we create a new enemy
                if e.type == SPAWN:
                    Enemy(self)

            // draw and update everything
            self.screen.fill(pygame.color.THECOLORS['grey'])
            self.all.draw(self.screen)
            self.all.update()
            pygame.display.flip()

            self.clock.tick(40)

if __name__ == '__main__':
    Game().run()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM