This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
en:pygame:step016 [2020/05/03 21:04] horst ↷ Links adapted because of a move operation |
en:pygame:step016 [2020/05/15 22:50] horst |
||
---|---|---|---|
Line 3: | Line 3: | ||
^ [[: | ^ [[: | ||
====== gameplay ====== | ====== gameplay ====== | ||
- | {{:en:part2: | + | {{part2: |
The source code example below is not much of a game, but it demonstrates the uses of layers for sprites and [[wp> | The source code example below is not much of a game, but it demonstrates the uses of layers for sprites and [[wp> | ||
Line 10: | Line 10: | ||
**Trivia: | **Trivia: | ||
- | [[http:// | + | [[http:// |
According to wikipedia, Parallax scrolling was first introduced to computer games by the arcade game [[wp> | According to wikipedia, Parallax scrolling was first introduced to computer games by the arcade game [[wp> | ||
Line 240: | Line 240: | ||
^ file ^ in folder | ^ file ^ in folder | ||
| [[https:// | | [[https:// | ||
- | | [[https:// | + | | [[https:// |
- | | [[https:// | + | | [[https:// |
| [[https:// | | [[https:// | ||
View/ | View/ | ||
- | //click reload in your browser if you see no code here:// | + | <code python> |
- | < | + | #!/usr/bin/env python |
- | <script src=" | + | # -*- coding: utf-8 -*- |
- | </script>< | + | """ |
+ | 016_layers.py | ||
+ | pygame sprites with different layers and parallax scrolling | ||
+ | url: http://thepythongamebook.com/en:part2:pygame:step016 | ||
+ | author: horst.jens@spielend-programmieren.at | ||
+ | licence: gpl, see http://www.gnu.org/ | ||
- | ^ [[: | ||
- | ====== | + | change the sprite layer by clicking with left or right mouse button |
- | ~~DISQUS~~ | + | the birdsprites will appear before or behind the blocks |
+ | |||
+ | point on a sprite and pres " | ||
+ | part of www.pythongamebook.com by Horst JENS | ||
+ | |||
+ | |||
+ | works with python3.4 and python2.7 | ||
+ | """ | ||
+ | #the next line is only needed for python2.x and not necessary for python3.x | ||
+ | from __future__ import print_function, | ||
+ | |||
+ | def game(): | ||
+ | |||
+ | import pygame | ||
+ | import os | ||
+ | import random | ||
+ | |||
+ | |||
+ | pygame.mixer.pre_init(44100, | ||
+ | pygame.init() | ||
+ | screen=pygame.display.set_mode((640, | ||
+ | # | ||
+ | print(" | ||
+ | |||
+ | BIRDSPEEDMAX | ||
+ | BIRDSPEEDMIN | ||
+ | FRICTION | ||
+ | FORCE_OF_GRAVITY | ||
+ | |||
+ | |||
+ | def write(msg=" | ||
+ | """ | ||
+ | myfont = pygame.font.SysFont(" | ||
+ | mytext = myfont.render(msg, | ||
+ | mytext = mytext.convert_alpha() | ||
+ | return mytext | ||
+ | |||
+ | class Text(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | def __init__(self, | ||
+ | self.groups = allgroup, textgroup | ||
+ | self._layer = 99 | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.newmsg(msg) | ||
+ | |||
+ | |||
+ | def update(self, | ||
+ | pass | ||
+ | |||
+ | def newmsg(self, | ||
+ | self.image = write(msg) | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.rect.center = (screen.get_width()/ | ||
+ | |||
+ | class Mountain(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | | ||
+ | ' | ||
+ | def __init__(self, | ||
+ | self.type = type | ||
+ | if self.type == 1: | ||
+ | self._layer = -1 | ||
+ | self.dx = -100 | ||
+ | self.color = (0,0,255) # blue mountains, close | ||
+ | elif self.type == 2: | ||
+ | self._layer = -2 | ||
+ | self.color = (200,0,255) # pink mountains, middle | ||
+ | self.dx = -75 | ||
+ | else: | ||
+ | self._layer = -3 | ||
+ | self.dx = -35 | ||
+ | self.color = (255,0,0) # red mountains, far away | ||
+ | self.groups = allgroup, mountaingroup | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.dy = 0 | ||
+ | x = 100 * self.type * 1.5 | ||
+ | y = screen.get_height() / 2 + 50 * (self.type -1) | ||
+ | self.image = pygame.Surface((x, | ||
+ | # | ||
+ | self.image.set_colorkey((0, | ||
+ | pygame.draw.polygon(self.image, | ||
+ | | ||
+ | (0, | ||
+ | (x/2, int(random.random()*y/ | ||
+ | (x, | ||
+ | (x,y), | ||
+ | (9,y)),0) # width=0 fills the polygon | ||
+ | self.image.convert_alpha() | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.pos = [0.0,0.0] | ||
+ | # start right side from visible screen | ||
+ | self.pos[0] = screen.get_width()+self.rect.width/ | ||
+ | self.pos[1] = screen.get_height()-self.rect.height/ | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | self.parent = False | ||
+ | |||
+ | def update(self, | ||
+ | self.pos[0] += self.dx * time | ||
+ | self.pos[1] += self.dy * time | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | # kill mountains too far to the left | ||
+ | if self.rect.centerx + self.rect.width/ | ||
+ | self.kill() | ||
+ | # create new mountains if necessary | ||
+ | if not self.parent: | ||
+ | if self.rect.centerx | ||
+ | self.parent = True | ||
+ | Mountain(self.type) # new Mountain coming from the right side | ||
+ | |||
+ | |||
+ | |||
+ | class Block(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | | ||
+ | def __init__(self, | ||
+ | self.blocknumber = blocknumber | ||
+ | self.color = (random.randint(10, | ||
+ | random.randint(10, | ||
+ | random.randint(10, | ||
+ | self._layer = self.blocknumber | ||
+ | self.groups = allgroup, blockgroup | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.area = screen.get_rect() | ||
+ | self.image = pygame.Surface((100, | ||
+ | self.image.fill(self.color) | ||
+ | self.image.blit(write(str(self.blocknumber)), | ||
+ | self.image = self.image.convert() | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.rect.centery = screen.get_height() / 2 | ||
+ | self.rect.centerx = 100 * self.blocknumber + 50 | ||
+ | # | ||
+ | self.pos = [0.0,0.0] | ||
+ | self.pos[0] = self.rect.centerx | ||
+ | self.pos[1] = self.rect.centery | ||
+ | self.dy = random.randint(50, | ||
+ | self.dx = 0 | ||
+ | |||
+ | def newspeed(self): | ||
+ | self.dy *= -1 | ||
+ | |||
+ | def update(self, | ||
+ | if not self.area.contains(self.rect): | ||
+ | # --- compare self.rect and area.rect | ||
+ | if self.pos[1] | ||
+ | self.pos[1] = self.area.top | ||
+ | self.newspeed() # calculate a new direction | ||
+ | elif self.pos[1] > self.area.bottom: | ||
+ | self.pos[1] = self.area.bottom | ||
+ | self.newspeed() # calculate a new direction | ||
+ | self.pos[0] += self.dx * time | ||
+ | self.pos[1] += self.dy * time | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | |||
+ | class BirdCatcher(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | def __init__(self): | ||
+ | self._layer = 9 | ||
+ | self.groups = allgroup, stuffgroup | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.image = pygame.Surface((100, | ||
+ | self.image.set_colorkey((0, | ||
+ | pygame.draw.circle(self.image, | ||
+ | self.image = self.image.convert_alpha() | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.radius = 50 # for collide check | ||
+ | |||
+ | def update(self, | ||
+ | # no need for seconds but the other sprites need it | ||
+ | self.rect.center = pygame.mouse.get_pos() | ||
+ | |||
+ | class Lifebar(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | with a given bossnumber, the Lifebar class can | ||
+ | | ||
+ | | ||
+ | def __init__(self, | ||
+ | self.groups | ||
+ | self.bossnumber | ||
+ | self._layer | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.image | ||
+ | self.image.set_colorkey((0, | ||
+ | pygame.draw.rect(self.image, | ||
+ | self.rect | ||
+ | self.oldpercent | ||
+ | |||
+ | def update(self, | ||
+ | self.percent = Bird.birds[self.bossnumber].hitpoints / Bird.birds[self.bossnumber].hitpointsfull * 1.0 | ||
+ | if self.percent != self.oldpercent: | ||
+ | pygame.draw.rect(self.image, | ||
+ | pygame.draw.rect(self.image, | ||
+ | | ||
+ | self.oldpercent = self.percent | ||
+ | self.rect.centerx = Bird.birds[self.bossnumber].rect.centerx | ||
+ | self.rect.centery = Bird.birds[self.bossnumber].rect.centery - Bird.birds[self.bossnumber].rect.height /2 - 10 | ||
+ | #check if boss is still alive | ||
+ | if Bird.birds[self.bossnumber].hitpoints < 1: | ||
+ | self.kill() # kill the hitbar | ||
+ | |||
+ | class Bird(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | image=[] | ||
+ | birds = {} # a dictionary of all Birds, each Bird has its own number | ||
+ | number = 0 | ||
+ | waittime = 1.0 # seconds | ||
+ | def __init__(self, | ||
+ | self.groups = birdgroup, allgroup # assign groups | ||
+ | self._layer = layer # assign level | ||
+ | #self.layer = layer | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | # | ||
+ | self.pos = [random.randint(50, | ||
+ | random.randint(25, | ||
+ | self.area = screen.get_rect() | ||
+ | self.image = Bird.image[0] | ||
+ | self.hitpointsfull = float(100) # maximal hitpoints | ||
+ | self.hitpoints = float(100) # actual hitpoints | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.radius = max(self.rect.width, | ||
+ | self.dx = 0 # wait at the beginning | ||
+ | self.dy = 0 | ||
+ | self.waittime = Bird.waittime # 1.0 # one second | ||
+ | # | ||
+ | self.lifetime = 0.0 | ||
+ | self.waiting = True | ||
+ | self.rect.center = (-100,-100) # out of visible screen | ||
+ | self.cleanstatus() | ||
+ | self.catched = False | ||
+ | self.crashing = False | ||
+ | #--- not necessary: | ||
+ | self.number = Bird.number # get my personal Birdnumber | ||
+ | Bird.number+= 1 # increase the number for next Bird | ||
+ | Bird.birds[self.number] = self # store myself into the Bird dictionary | ||
+ | #print "my number %i Bird number %i " % (self.number, | ||
+ | Lifebar(self.number) #create a Lifebar for this Bird. | ||
+ | # starting implosion of blue fragments | ||
+ | for _ in range(8): | ||
+ | Fragment(self.pos, | ||
+ | |||
+ | def newspeed(self): | ||
+ | # new birdspeed, but not 0 | ||
+ | speedrandom = random.choice([-1, | ||
+ | self.dx = random.randint(BIRDSPEEDMIN, | ||
+ | self.dy = random.randint(BIRDSPEEDMIN, | ||
+ | |||
+ | def cleanstatus(self): | ||
+ | self.catched = False # set all Bird sprites to not catched | ||
+ | self.crashing = False | ||
+ | |||
+ | def kill(self): | ||
+ | # a shower of red fragments, exploding outward | ||
+ | for _ in range(15): | ||
+ | Fragment(self.pos) | ||
+ | pygame.sprite.Sprite.kill(self) # kill the actual Bird | ||
+ | |||
+ | |||
+ | def update(self, | ||
+ | #---make Bird only visible after waiting time | ||
+ | self.lifetime += seconds | ||
+ | if self.lifetime > (self.waittime) and self.waiting: | ||
+ | self.newspeed() | ||
+ | self.waiting = False | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | if self.waiting: | ||
+ | self.rect.center = (-100, | ||
+ | else: | ||
+ | # speedcheck | ||
+ | # friction make birds slower | ||
+ | if abs(self.dx) > BIRDSPEEDMIN and abs(self.dy) > BIRDSPEEDMIN: | ||
+ | self.dx *= FRICTION | ||
+ | self.dy *= FRICTION | ||
+ | # spped limit | ||
+ | if abs(self.dx) > BIRDSPEEDMAX: | ||
+ | self.dx = BIRDSPEEDMAX * self.dx / self.dx | ||
+ | if abs(self.dy) > BIRDSPEEDMAX: | ||
+ | self.dy = BIRDSPEEDMAX * self.dy / self.dy | ||
+ | # movement | ||
+ | self.pos[0] += self.dx * seconds | ||
+ | self.pos[1] += self.dy * seconds | ||
+ | # -- check if Bird out of screen | ||
+ | if not self.area.contains(self.rect): | ||
+ | self.crashing = True # change colour later | ||
+ | # --- compare self.rect and area.rect | ||
+ | if self.pos[0] + self.rect.width/ | ||
+ | self.pos[0] = self.area.right - self.rect.width/ | ||
+ | if self.pos[0] - self.rect.width/ | ||
+ | self.pos[0] = self.area.left + self.rect.width/ | ||
+ | if self.pos[1] + self.rect.height/ | ||
+ | self.pos[1] = self.area.bottom - self.rect.height/ | ||
+ | if self.pos[1] - self.rect.height/ | ||
+ | self.pos[1] = self.area.top + self.rect.height/ | ||
+ | self.newspeed() # calculate a new direction | ||
+ | #--- calculate actual image: crasing, catched, both, nothing ? | ||
+ | self.image = Bird.image[self.crashing + self.catched*2] | ||
+ | #--- calculate new position on screen ----- | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | #--- loose hitpoins | ||
+ | if self.crashing: | ||
+ | self.hitpoints -=1 | ||
+ | #--- check if still alive | ||
+ | if self.hitpoints <= 0: | ||
+ | self.kill() | ||
+ | |||
+ | class Fragment(pygame.sprite.Sprite): | ||
+ | """ | ||
+ | gravity = False # fragments fall down ? | ||
+ | def __init__(self, | ||
+ | self._layer = 9 | ||
+ | self.groups = allgroup, stuffgroup | ||
+ | pygame.sprite.Sprite.__init__(self, | ||
+ | self.bluefrag = bluefrag | ||
+ | self.pos = [0.0,0.0] | ||
+ | self.target = pos | ||
+ | self.fragmentmaxspeed = BIRDSPEEDMAX * 2 # try out other factors ! | ||
+ | if self.bluefrag: | ||
+ | # blue frament implodes from screen edge toward Bird | ||
+ | self.color = (0, | ||
+ | self.side = random.randint(1, | ||
+ | if self.side == 1: # left side | ||
+ | self.pos[0] = 0 | ||
+ | self.pos[1] = random.randint(0, | ||
+ | elif self.side == 2: # top | ||
+ | self.pos[0] = random.randint(0, | ||
+ | self.pos[1] = 0 | ||
+ | elif self.side == 3: #right | ||
+ | self.pos[0] = screen.get_width() | ||
+ | self.pos[1] = random.randint(0, | ||
+ | else: #bottom | ||
+ | self.pos[0] = random.randint(0, | ||
+ | self.pos[1] = screen.get_height() | ||
+ | # calculating flytime for one second.. Bird.waittime should be 1.0 | ||
+ | self.dx = (self.target[0] - self.pos[0]) * 1.0 / Bird.waittime | ||
+ | self.dy = (self.target[1] - self.pos[1]) * 1.0 / Bird.waittime | ||
+ | self.lifetime = Bird.waittime + random.random() * .5 # a bit more livetime after the Bird appears | ||
+ | else: # red fragment explodes from the bird toward screen edge | ||
+ | self.color = (random.randint(25, | ||
+ | self.pos[0] = pos[0] | ||
+ | self.pos[1] = pos[1] | ||
+ | self.dx = random.randint(-self.fragmentmaxspeed, | ||
+ | self.dy = random.randint(-self.fragmentmaxspeed, | ||
+ | self.lifetime = 1 + random.random()*3 # max 3 seconds | ||
+ | self.image = pygame.Surface((10, | ||
+ | self.image.set_colorkey((0, | ||
+ | pygame.draw.circle(self.image, | ||
+ | self.image = self.image.convert_alpha() | ||
+ | self.rect = self.image.get_rect() | ||
+ | self.rect.center = self.pos #if you forget this line the sprite sit in the topleft corner | ||
+ | self.time = 0.0 | ||
+ | |||
+ | def update(self, | ||
+ | self.time += seconds | ||
+ | if self.time > self.lifetime: | ||
+ | self.kill() | ||
+ | self.pos[0] += self.dx * seconds | ||
+ | self.pos[1] += self.dy * seconds | ||
+ | if Fragment.gravity and not self.bluefrag: | ||
+ | self.dy += FORCE_OF_GRAVITY # gravity suck fragments down | ||
+ | self.rect.centerx = round(self.pos[0], | ||
+ | self.rect.centery = round(self.pos[1], | ||
+ | |||
+ | |||
+ | background = pygame.Surface((screen.get_width(), | ||
+ | background.fill((255, | ||
+ | background.blit(write(" | ||
+ | background.blit(write(" | ||
+ | background.blit(write(" | ||
+ | background.blit(write(" | ||
+ | # secret keys: g (gravity), p (print layers) | ||
+ | |||
+ | background = background.convert() | ||
+ | screen.blit(background, | ||
+ | |||
+ | #define sprite groups. Do this before creating sprites | ||
+ | blockgroup = pygame.sprite.LayeredUpdates() | ||
+ | birdgroup = pygame.sprite.Group() | ||
+ | textgroup = pygame.sprite.Group() | ||
+ | bargroup = pygame.sprite.Group() | ||
+ | stuffgroup = pygame.sprite.Group() | ||
+ | mountaingroup = pygame.sprite.Group() | ||
+ | # only the allgroup draws the sprite, so i use LayeredUpdates() instead Group() | ||
+ | allgroup = pygame.sprite.LayeredUpdates() # more sophisticated, | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | try: # load images into classes (class variable !). if not possible, draw ugly images | ||
+ | Bird.image.append(pygame.image.load(os.path.join(" | ||
+ | Bird.image.append(pygame.image.load(os.path.join(" | ||
+ | except: | ||
+ | print(" | ||
+ | print(" | ||
+ | image = pygame.Surface((32, | ||
+ | image.fill((255, | ||
+ | pygame.draw.circle(image, | ||
+ | image.set_colorkey((255, | ||
+ | Bird.image.append(image) # alternative ugly image | ||
+ | image2 = image.copy() | ||
+ | pygame.draw.circle(image2, | ||
+ | Bird.image.append(image2) | ||
+ | Bird.image.append(Bird.image[0].copy()) # copy of first image | ||
+ | pygame.draw.rect(Bird.image[2], | ||
+ | Bird.image.append(Bird.image[1].copy()) # copy second image | ||
+ | pygame.draw.rect(Bird.image[3], | ||
+ | Bird.image[0] = Bird.image[0].convert_alpha() | ||
+ | Bird.image[1] = Bird.image[1].convert_alpha() | ||
+ | Bird.image[2] = Bird.image[2].convert_alpha() | ||
+ | Bird.image[3] = Bird.image[3].convert_alpha() | ||
+ | |||
+ | |||
+ | try: # ------- load sound ------- | ||
+ | cry = pygame.mixer.Sound(os.path.join(' | ||
+ | except: | ||
+ | raise(SystemExit, | ||
+ | # | ||
+ | |||
+ | |||
+ | #create Sprites | ||
+ | hunter = BirdCatcher() # display the BirdCatcher and name it " | ||
+ | |||
+ | for x in range(screen.get_width()// | ||
+ | Block(x) # add more Blocks if you y screen resolution is bigger | ||
+ | |||
+ | othergroup = [] # important for good collision detection | ||
+ | badcoding = False | ||
+ | clock = pygame.time.Clock() | ||
+ | mainloop = True | ||
+ | FPS = 60 # desired max. framerate in frames per second. | ||
+ | |||
+ | birdlayer = 4 | ||
+ | birdtext = Text(" | ||
+ | cooldowntime = 0 #sec | ||
+ | |||
+ | # start with some Birds | ||
+ | for _ in range(15): | ||
+ | Bird(birdlayer) | ||
+ | |||
+ | # create the first parallax scrolling mountains | ||
+ | Mountain(1) # blue | ||
+ | Mountain(2) # pink | ||
+ | Mountain(3) # red | ||
+ | |||
+ | while mainloop: # ----------------- mainloop ---------------------- | ||
+ | milliseconds = clock.tick(FPS) | ||
+ | seconds = milliseconds / 1000.0 # seconds passed since last frame | ||
+ | for event in pygame.event.get(): | ||
+ | if event.type == pygame.QUIT: | ||
+ | mainloop = False # pygame window closed by user | ||
+ | elif event.type == pygame.KEYDOWN: | ||
+ | if event.key == pygame.K_ESCAPE: | ||
+ | mainloop = False # user pressed ESC | ||
+ | #elif event.key == pygame.K_g: | ||
+ | # | ||
+ | elif event.key == pygame.K_p: # get sprites at mouse position, print info | ||
+ | print(" | ||
+ | print(" | ||
+ | spritelist = allgroup.get_sprites_at(pygame.mouse.get_pos()) | ||
+ | for sprite in spritelist: | ||
+ | print(sprite, | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | |||
+ | elif event.key == pygame.K_g: | ||
+ | Fragment.gravity = not Fragment.gravity # toggle gravity class variable | ||
+ | |||
+ | |||
+ | # change birdlayer on mouseclick | ||
+ | if cooldowntime <= 0: # to | ||
+ | if pygame.mouse.get_pressed()[0]: | ||
+ | if birdlayer < 10: | ||
+ | birdlayer += 1 | ||
+ | cooldowntime = .5 # seconds | ||
+ | cry.play() | ||
+ | for bird in birdgroup: | ||
+ | allgroup.change_layer(bird, | ||
+ | for bar in bargroup: | ||
+ | allgroup.change_layer(bar, | ||
+ | if pygame.mouse.get_pressed()[2]: | ||
+ | if birdlayer > -4: | ||
+ | birdlayer -= 1 | ||
+ | cooldowntime = .5 | ||
+ | cry.play() | ||
+ | for bird in birdgroup: | ||
+ | allgroup.change_layer(bird, | ||
+ | for bar in bargroup: | ||
+ | allgroup.change_layer(bar, | ||
+ | else: | ||
+ | cooldowntime -= seconds # to avoid speedclicking | ||
+ | |||
+ | pygame.display.set_caption(" | ||
+ | |||
+ | |||
+ | birdtext.newmsg(" | ||
+ | |||
+ | # ------ collision detection | ||
+ | for bird in birdgroup: | ||
+ | bird.cleanstatus() | ||
+ | |||
+ | # | ||
+ | crashgroup = pygame.sprite.spritecollide(hunter, | ||
+ | # pygame.sprite.collide_circle works only if one sprite has self.radius | ||
+ | # you can do without that argument collided and only the self.rects will be checked | ||
+ | for crashbird in crashgroup: | ||
+ | crashbird.catched = True # will get a blue border from Bird.update() | ||
+ | |||
+ | for bird in birdgroup: | ||
+ | # check the Bird.number to make sure the bird is not crashing with himself | ||
+ | crashgroup = pygame.sprite.spritecollide(bird, | ||
+ | for crashbird in crashgroup: | ||
+ | if crashbird.number != bird.number: | ||
+ | bird.crashing = True | ||
+ | if not bird.waiting: | ||
+ | bird.dx -= crashbird.pos[0] - bird.pos[0] | ||
+ | bird.dy -= crashbird.pos[1] - bird.pos[1] | ||
+ | |||
+ | # create 10 new Birds if fewer than 11 birds alive | ||
+ | if len(birdgroup) < 10: | ||
+ | for _ in range(random.randint(1, | ||
+ | Bird(birdlayer) | ||
+ | |||
+ | # ----------- clear, draw , update, flip ----------------- | ||
+ | allgroup.clear(screen, | ||
+ | allgroup.update(seconds) | ||
+ | allgroup.draw(screen) | ||
+ | pygame.display.flip() | ||
+ | |||
+ | if __name__ == " | ||
+ | game() | ||
+ | else: | ||
+ | print(" | ||
+ | |||
+ | </ | ||
+ | ^ [[: | ||