Python pygame - 删除屏幕外精灵
Python pygame - Deleting offscreen sprites
我用 python 2 和 pygame 创建了一个简单的 2D 游戏,你必须避开向下移动的方块。我为 'enemy' 创建了这个 class:
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
然后,我有一个创建敌人实例的线程:
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)
然后在绘图方法中我只写 self.all_sprites.draw()
游戏是一个无限奔跑者,每一帧敌人都会向下移动几个像素。问题是游戏开始有点迟钝,因为当方块离开屏幕时,精灵不会被删除。
有没有办法自动删除屏幕外的实例?
我尝试了以下方法,但它只是删除了屏幕上的所有敌人。
if self.rect.y >= WIDTH:
self.rect.kill()
我想我可以做类似 game.all_sprites.pop(1)
的事情(位置 0 是玩家)但是我找不到一种方法来存档类似的东西 ...
检查 self.rect.y、WIDTH 的值,也许是 kill 方法。看起来 self.rect.y 总是大于或等于 WIDTH,这就是它杀死它们的原因。
如果他们的 rect
不再在屏幕内,敌人可以通过调用 self.kill()
将自己从游戏中移除,例如:
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()
此外,您可以使用 pygame 的事件系统来生成您的敌人,而不是线程。这是一个简单、不完整但可运行的示例(注意注释):
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()
我用 python 2 和 pygame 创建了一个简单的 2D 游戏,你必须避开向下移动的方块。我为 'enemy' 创建了这个 class:
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
然后,我有一个创建敌人实例的线程:
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)
然后在绘图方法中我只写 self.all_sprites.draw()
游戏是一个无限奔跑者,每一帧敌人都会向下移动几个像素。问题是游戏开始有点迟钝,因为当方块离开屏幕时,精灵不会被删除。
有没有办法自动删除屏幕外的实例?
我尝试了以下方法,但它只是删除了屏幕上的所有敌人。
if self.rect.y >= WIDTH:
self.rect.kill()
我想我可以做类似 game.all_sprites.pop(1)
的事情(位置 0 是玩家)但是我找不到一种方法来存档类似的东西 ...
检查 self.rect.y、WIDTH 的值,也许是 kill 方法。看起来 self.rect.y 总是大于或等于 WIDTH,这就是它杀死它们的原因。
如果他们的 rect
不再在屏幕内,敌人可以通过调用 self.kill()
将自己从游戏中移除,例如:
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()
此外,您可以使用 pygame 的事件系统来生成您的敌人,而不是线程。这是一个简单、不完整但可运行的示例(注意注释):
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()