import pygame import sys from pygame.locals import * import random ###小鸟类## class Bird(): def __init__(self, pos_x, pos_y, speed): #初始化 self.images = [bird_0_image, bird_1_image, bird_2_image] self.order = 0 #应该放第几张图片 self.number = 3 #做一个动画一共需要3张图 self.image = self.images[self.order] self.rect = self.image.get_rect() #取出一个代表图片的矩形 self.rect.x = pos_x #矩形左上角的坐标 self.rect.y = pos_y #小鸟图片并非充满整个rect,做碰撞检测需要小鸟的精确位置,记做self.base self.base = pygame.Rect(self.rect.x + 6, self.rect.y + 13, 34, 24) self.speed_y = speed self.crash = 0 #坠落情况 self.score = 0 #分数 self.direct = 1 def draw(self, screen): #画在屏幕上 screen.blit(self.image, (self.rect.x, self.rect.y)) def flap(self): #扇翅膀动画 if self.order >= self.number - 1: self.order = -1 self.order += 1 self.image = self.images[self.order] def move_y(self): #动作规律以及积分情况 coin_sound = pygame.mixer.Sound("coin_sound.wav") self.rect.y += self.speed_y self.speed_y += gravity self.base = pygame.Rect(self.rect.x + 6, self.rect.y + 13, 34, 24) if self.rect.x == pipe_1.rect_up.x or self.rect.x == pipe_2.rect_up.x + 1: coin_sound.play() self.score = max(pipe_1.order, pipe_2.order) - 1 def up_and_down(self, pos_y): if self.rect.y <= pos_y: self.direct = 1 self.rect.y += self.direct elif self.rect.y >= pos_y + 5 : self.direct = -1 self.rect.y += self.direct else: self.rect.y += self.direct def soar(self, speed): #点击小鸟飞起 self.speed_y = speed def drop(self): #小鸟坠落 self.rect.y += self.speed_y self.speed_y += gravity def die(self): #小鸟死亡 self.rect.y = 365 self.image = self.images[0] ###柱子1### class Pipe_1(): def __init__(self): #初始化 self.images = [pipe_up_image,pipe_down_image] self.rand= random.randrange(50, 270, 20) self.rect_up = self.images[0].get_rect() #上部分柱子 self.rect_down = self.images[1].get_rect() #下部分柱子 self.order = 1 #柱子编号 self.rect_up.x = 1.5 * screen_width #位置 self.rect_down.x = 1.5 * screen_width self.rect_up.y = 400 - self.rand self.rect_down.y = - self.rand - random.randrange(0, 100) def imagein(self, a, b): self.images = [a, b] def draw(self, screen): #画在屏幕上 screen.blit(self.images[0], (self.rect_up.x, self.rect_up.y)) screen.blit(self.images[1], (self.rect_down.x, self.rect_down.y)) def move_x(self): #柱子动作规律 if self.rect_up.x > -pipe_width: self.rect_up.x -= pipe_speed self.rect_down.x -= pipe_speed else: self.reset() def reset(self): #移出屏幕后重新进入屏幕 self.rand = random.randrange(50, 270, 20) self.rect_up.x = screen_width self.rect_down.x = screen_width self.rect_up.y = 400 - self.rand self.rect_down.y = -self.rand -random.randrange(0,100) ##柱子是320个像素点,地面以上部分400个像素点,两柱之间距离有点近,- 20拉大20个像素的距离,可根据喜好随意设置 self.order += 2 def collide(self, bird_rect): #判断与小鸟的碰撞 if self.rect_up.colliderect(bird_rect): collide_pipe = 1 elif self.rect_down.colliderect(bird_rect): collide_pipe= 1 else: collide_pipe = 0 return collide_pipe def halt(self): pass class Pipe_2(): def __init__(self): self.images = [pipe_up_image,pipe_down_image] self.rand= random.randrange(50, 270, 20) self.rect_up = self.images[0].get_rect() self.rect_down = self.images[1].get_rect() self.order = 0 self.reset() def imagein(self,a,b): self.images=[a,b] def draw(self, screen): screen.blit(self.images[0], (self.rect_up.x, self.rect_up.y)) screen.blit(self.images[1], (self.rect_down.x, self.rect_down.y)) def move_x(self): if pipe_1.rect_up.x < self.rect_up.x: self.rect_up.x = pipe_1.rect_up.x + (screen_width + pipe_width)/2 self.rect_down.x = pipe_1.rect_down.x + (screen_width + pipe_width)/2 elif pipe_1.rect_up.x > self.rect_up.x and self.rect_up.x > -pipe_width: self.rect_up.x -= pipe_speed self.rect_down.x -= pipe_speed else: self.reset() def reset(self): self.rand = random.randrange(50, 270, 20) self.rect_up.x = pipe_1.rect_up.x + (screen_width + pipe_width)/2 self.rect_down.x = pipe_1.rect_up.x + (screen_width + pipe_width)/2 self.rect_up.y = 400 - self.rand self.rect_down.y = -self.rand - 20 self.order += 2 def collide(self, bird_rect): if self.rect_up.colliderect(bird_rect): collide_pipe = 1 elif self.rect_down.colliderect(bird_rect): collide_pipe= 1 else: collide_pipe = 0 return collide_pipe def halt(self): pass ###地面### class Land(): def __init__(self): #初始化 self.image = land_image self.rect = self.image.get_rect() self.rect.x = 0 self.rect.y = 400 def draw(self, screen): #画在屏幕上 screen.blit(self.image, (self.rect.x, self.rect.y)) def move_x(self): #地面动作规律 if self.rect.x > -44: self.rect.x -= pipe_speed else: self.rect.x = 0 def collide(self, bird_rect): #判断与小鸟碰撞 if self.rect.colliderect(bird_rect): collide_land = 1 else: collide_land = 0 return collide_land def halt(self): pass ###分数### class Score(): def __init__(self): self.images = [num_0_image, num_1_image, num_2_image, num_3_image, num_4_image, num_5_image, num_6_image, num_7_image, num_8_image, num_9_image] self.hun_pos_3 = 108 self.dec_pos_3 = 132 self.dec_pos_2 = 120 self.uni_pos_3 = 156 self.uni_pos_2 = 144 self.uni_pos_1 = 132 def draw(self, screen, score): #画在屏幕上,为了保持分数在屏幕正中央,判断分数有几位,根据位数画图 if score < 10: screen.blit(self.images[score], (self.uni_pos_1, 0)) if score >= 10 and score <100: screen.blit(self.images[score % 10], (self.uni_pos_2, 0)) screen.blit(self.images[int(score/10)], (self.dec_pos_2, 0)) if score > 100: screen.blit(self.images[score % 10], (self.uni_pos_3, 0)) screen.blit(self.images[int((score % 100)/10)], (self.dec_pos_3, 0)) screen.blit(self.images[int(score/100)], (self.hun_pos_3, 0)) gamename = "小鸟历险记" screen_width = 288 screen_height = 512 #pipe_width = 52 # 固定柱子间距 pipe_width = random.randrange(22, 102, 10) # 随机柱子间距 pipe_height = 320 pipe_speed = 3 gravity = 1.2 soar_speed = -5 play_x = 120 #play界面下小鸟的位置 play_y = 190 ready_x = 60 ready_y = 210 #ready界面下小鸟的位置 game_over_x = 60 game_over_y = 365 #game over界面下小鸟的位置 ###加载所有图片### update = 30 bird_0_image = pygame.image.load("bird_0.png") bird_1_image = pygame.image.load("bird_1.png") bird_2_image = pygame.image.load("bird_2.png") background_image = pygame.image.load("bg_day.png") land_image = pygame.image.load("land.png") pipe_up_image = pygame.image.load("pipe_up.png") pipe_down_image = pygame.image.load("pipe_down.png") num_0_image = pygame.image.load("num_0.png") #显示在屏幕中央的分数图片 num_1_image = pygame.image.load("num_1.png") num_2_image = pygame.image.load("num_2.png") num_3_image = pygame.image.load("num_3.png") num_4_image = pygame.image.load("num_4.png") num_5_image = pygame.image.load("num_5.png") num_6_image = pygame.image.load("num_6.png") num_7_image = pygame.image.load("num_7.png") num_8_image = pygame.image.load("num_8.png") num_9_image = pygame.image.load("num_9.png") score_0_image = pygame.image.load("score_0.png") #显示在分数版上的分数图片 score_1_image = pygame.image.load("score_1.png") score_2_image = pygame.image.load("score_2.png") score_3_image = pygame.image.load("score_3.png") score_4_image = pygame.image.load("score_4.png") score_5_image = pygame.image.load("score_5.png") score_6_image = pygame.image.load("score_6.png") score_7_image = pygame.image.load("score_7.png") score_8_image = pygame.image.load("score_8.png") score_9_image = pygame.image.load("score_9.png") medals_0_image = pygame.image.load('medals_0.png') medals_1_image = pygame.image.load('medals_1.png') medals_2_image = pygame.image.load('medals_2.png') medals_3_image = pygame.image.load('medals_3.png') pass title_image = pygame.image.load("title.png") button_play_image = pygame.image.load("button_play.png") game_over_image = pygame.image.load("text_game_over.png") score_panel_image = pygame.image.load("score_panel.png") ###全局变量初始化,由于小鸟在不同的游戏界面不一样,需要在函数内部设置局部变量 pipe_1 = Pipe_1() pipe_2 = Pipe_2() land = Land() clock = pygame.time.Clock() #非常重要,控制游戏速度,每一帧的时间间隔 ###最开始的play界面### def play_page(): pygame.init() screen = pygame.display.set_mode([screen_width, screen_height]) #设置屏幕 pygame.display.set_caption(gamename) #设置顶栏名称 bird = Bird(play_x, play_y, 0) while True: for event in pygame.event.get(): if event.type == QUIT: exit() mouse_x, mouse_y = pygame.mouse.get_pos() #判断是否在点击了play button,点击之后退出该状态,进入ready状态 if pygame.mouse.get_pressed()[0] and mouse_x >= 92 and mouse_x <= 196 and mouse_y >= 287 and mouse_y <= 345: break screen.blit(background_image, (0, 0)) screen.blit(title_image, (55, 98)) screen.blit(button_play_image, (86, 284)) bird.up_and_down(play_y) bird.flap() bird.draw(screen) land.move_x() land.draw(screen) pygame.display.update() global update clock.tick(update) ###准备界面### def ready_page(): pygame.init() screen = pygame.display.set_mode([screen_width, screen_height]) pygame.display.set_caption(gamename) bird = Bird(ready_x, ready_y, 0) while True: for event in pygame.event.get(): if event.type == QUIT: exit() #判断是否点击了鼠标,点击之后返回当前小鸟的位置和速度信息,使两界面之间的切换没有瑕疵 if pygame.mouse.get_pressed()[0]: bird.soar(soar_speed) return [bird.rect.x, bird.rect.y, bird.speed_y] break screen.blit(background_image, (0, 0)) bird.up_and_down(ready_y) bird.flap() bird.draw(screen) land.move_x() land.draw(screen) pygame.display.update() global update clock.tick(update) #帧速最高不超过updatems/帧 ###游戏界面,接收上一界面的信息,以保持画面不断帧### def start_page(start_x, start_y, start_speed): pygame.init() collide_sound = pygame.mixer.Sound("collide_sound.wav") #加载碰撞声 pygame.mixer.music.load("bg_music.mp3") #加载并播放背景音乐,并且设置声音 pygame.mixer.music.set_volume(0.8) pygame.mixer.music.play(-1) screen = pygame.display.set_mode([screen_width, screen_height]) pygame.display.set_caption(gamename) bird = Bird(start_x, start_y, start_speed) pipe_1.__init__() #初始化 pipe_2.__init__() score = Score() first_collide = 1 flag = 1 # 标志位 while True: if bird.score >= 10 and bird.score<=20: #b = 52 + bird.score*10 b = pipe_width + bird.score new1 = pygame.transform.scale(pipe_up_image, (b, 320)) new2 = pygame.transform.scale(pipe_down_image, (b, 320)) pipe_1.imagein(new1, new2) pipe_2.imagein(new1, new2) global soar_speed #if bird.score > 15 and (bird.score + 1) % 4 == 0 : if bird.score > 20 and bird.score % 2 == 0 and flag ==1: a = 52 + random.randrange(20,100) new1 = pygame.transform.scale(pipe_up_image, (a, 320)) new2 = pygame.transform.scale(pipe_down_image, (a, 320)) if a >= 210: new1 = pygame.transform.scale(pipe_up_image, (52, 320)) new2 = pygame.transform.scale(pipe_down_image, (52, 320)) pipe_1.imagein(new1, new2) pipe_2.imagein(new1, new2) if bird.score % 2 == 0: flag = -1 else: flag = 1 for event in pygame.event.get(): if event.type == QUIT: exit() screen.blit(background_image, (0, 0)) if pipe_1.collide(bird.base) == 0 and pipe_2.collide(bird.base) ==0 and land.collide(bird.rect) == 0: #正常飞行 if pygame.mouse.get_pressed()[0]: bird.soar(soar_speed) pipe_1.move_x() pipe_1.draw(screen) pipe_2.move_x() pipe_2.draw(screen) bird.move_y() bird.flap() bird.draw(screen) land.move_x() land.draw(screen) score.draw(screen, bird.score) elif (pipe_1.collide(bird.base) == 1 or pipe_2.collide(bird.base) ==1) and land.collide(bird.rect) == 0: #碰到柱子坠落 if first_collide == 1: collide_sound.play() pipe_1.halt() pipe_1.draw(screen) pipe_2.halt() pipe_2.draw(screen) bird.drop() bird.flap() bird.draw(screen) land.halt() land.draw(screen) score.draw(screen, bird.score) first_collide = 0 else: #坠落到地面时的状态 pipe_1.halt() pipe_1.draw(screen) pipe_2.halt() pipe_2.draw(screen) bird.die() bird.draw(screen) land.halt() land.draw(screen) score.draw(screen, bird.score) pygame.display.update() #更新图像,否则显示不对 return bird.score #返回分数信息,给game over界面 break #一旦碰到地面就进入game over界面 pygame.display.update() clock.tick(30) ###game over界面,接收上一界面的分数信息进行显示,接收以往的最高成绩,接收是否产生了新纪录### def game_over_page(score, best): pygame.init() screen = pygame.display.set_mode([screen_width, screen_height]) pygame.display.set_caption(gamename) pygame.mixer.music.load("dead_sound.wav") pygame.mixer.music.set_volume(0.5) pygame.mixer.music.play() bird = Bird(game_over_x, game_over_y, 0) restart = 0 images = [score_0_image, score_1_image, score_2_image, score_3_image, score_4_image, score_5_image, score_6_image, score_7_image, score_8_image, score_9_image] while True: for event in pygame.event.get(): if event.type == QUIT: exit() mouse_x, mouse_y = pygame.mouse.get_pos() #判断是否点击开始按钮以重新开始 if pygame.mouse.get_pressed()[0] and mouse_x >= 92 and mouse_x <= 196 and mouse_y >= 337 and mouse_y <= 395: restart = 1 return restart break screen.blit(background_image, (0, 0)) pipe_1.halt() pipe_1.draw(screen) pipe_2.halt() pipe_2.draw(screen) bird.die() bird.draw(screen) land.halt() land.draw(screen) screen.blit(game_over_image, (42, 98)) screen.blit(score_panel_image, (25, 183)) screen.blit(button_play_image, (86, 334)) #将分数按照位数进行分类,保证分数显示时的美观 if score < 10: pass elif score >= 10 and score < 50: screen.blit(medals_3_image, (57, 226)) elif score >= 50 and score < 100: screen.blit(medals_2_image, (57, 226)) elif score >= 100 and score < 500: screen.blit(medals_1_image, (57, 226)) else: screen.blit(medals_0_image, (57, 226)) if score < 10: screen.blit(images[score], (215, 219)) if score >= 10 and score <100: screen.blit(images[score%10], (215, 219)) screen.blit(images[int(score/10)], (202, 219)) if score > 100: screen.blit(images[score%10], (215, 219)) screen.blit(images[int((score%100)/10)], (202, 219)) screen.blit(images[int(score/100)], (189, 219)) #最高成绩显示,同上 if best < 10: screen.blit(images[best], (215, 261)) if best >= 10 and best <100: screen.blit(images[best%10], (215, 261)) screen.blit(images[int(best/10)], (202, 261)) if best > 100: screen.blit(images[best%10], (215, 261)) screen.blit(images[int((best%100)/10)], (202, 261)) screen.blit(images[int(best/100)], (189, 261)) pygame.display.update() global update clock.tick(update) #游戏的总框架 def run(): play_page() #play界面 restart = 1 #先将restart置1,否则无法开始游戏 best = 0 while restart: #判断是否重新开始游戏 [start_x, start_y, start_speed] = ready_page() #ready界面 score = start_page(start_x, start_y, start_speed) #start_page界面 if score > best: best = score restart = game_over_page(score, best) #game over界面 #开始游戏 if __name__ == "__main__": run()