飞行小鸟(Flappy bird)
一些想法
基本游戏界面就是这样
; 分析需要的功能
我的构思是将游戏分成三个部分
- 初始游戏菜单界面
- 游戏进行界面
- 游戏结束界面
游戏里的角色和道具则使用类
- 小鸟类
- 管道类
因为是使用pygame模块 我对这个模块也很不熟悉 很多功能都是论坛参考其他大神的 比如
pygame.transform 里面的各种变化功能
pygame.sprite 精灵模块里面的方法
构建整体框架
- 导入pygame和random pygame拥有丰富的制作游戏的功能 random是随机模块 游戏里各种随机事件就是通过这个模块功能实现
import pygame
import random
2.我们写一个小的项目之前 需要将每个功能分成不同的代码块
- 定义的变量都写到最上面
MAP_WIDTH = 288
MAP_HEIGHT = 512
FPS = 30
PIPE_GAPS = [110, 120, 130, 140, 150, 160]
全局变量
我一般喜欢使用大写来区分
- 游戏窗口的设置
pygame.init()
SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT))
pygame.display.set_caption('飞行小鸟')
CLOCK = pygame.time.Clock()
- 加载素材
加载游戏图片和音乐
SPRITE_FILE = './images'
IMAGES = {}
IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png')
IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png')
IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png')
SPRITE_SOUND = './audio/'
SOUNDS = {}
SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav')
SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav')
SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav')
SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav')
- 执行函数
就是执行程序的函数
def main():
menu_window()
result = game_window()
end_window(result)
- 程序入口
if __name__ == '__main__':
main()
- 我将游戏分成了三个界面
- 初始游戏菜单界面
- 游戏进行界面
- 游戏结束界面
def menu_window():
pass
def game_window():
pass
def end_window(result):
pass
- 因为要显示游戏得分 所以专门写一个方法在游戏主界面代码里面直接调用这个方法 让代码不会显得冗余
- 最后就是我们游戏角色和道具的类方法
- 小鸟类
- 管道类
class Bird(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
pass
def update(self, flap=False):
pass
def go_die(self):
pass
class Pipe(pygame.sprite.Sprite):
def __init__(self, x, y, upwards=True):
pygame.sprite.Sprite.__init__(self)
pass
def update(self):
pass
我们把整体框架搭建好之后 就可以着手完善代码
着手完整代码
"""
Project: pygame
Creator: stan Z
Create time: 2021-03-08 19:37
IDE: PyCharm
Introduction:
"""
import pygame
import random
MAP_WIDTH = 288
MAP_HEIGHT = 512
FPS = 30
PIPE_GAPS = [90, 100, 110, 120, 130, 140]
PIPE_HEIGHT_RANGE = [int(MAP_HEIGHT * 0.3), int(MAP_HEIGHT * 0.7)]
PIPE_DISTANCE = 120
pygame.init()
SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT))
pygame.display.set_caption('飞行小鸟byStanZ')
CLOCK = pygame.time.Clock()
SPRITE_FILE = './images'
BIRDS = [[f'{SPRITE_FILE}{bird}-{move}.png' for move in ['up', 'mid', 'down']] for bird in ['red', 'blue', 'yellow']]
BGPICS = [SPRITE_FILE + 'day.png', SPRITE_FILE + 'night.png']
PIPES = [SPRITE_FILE + 'green-pipe.png', SPRITE_FILE + 'red-pipe.png']
NUMBERS = [f'{SPRITE_FILE}{n}.png' for n in range(10)]
IMAGES = {}
IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS]
IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png')
IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png')
IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png')
FLOOR_H = MAP_HEIGHT - IMAGES['floor'].get_height()
SPRITE_SOUND = './sound'
SOUNDS = {}
SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav')
SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav')
SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav')
SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav')
SOUNDS['flap'] = pygame.mixer.Sound(SPRITE_SOUND + 'flap.wav')
SOUNDS['death'] = pygame.mixer.Sound(SPRITE_SOUND + 'death.wav')
SOUNDS['main'] = pygame.mixer.Sound(SPRITE_SOUND + 'main_theme.ogg')
SOUNDS['world_clear'] = pygame.mixer.Sound(SPRITE_SOUND + 'world_clear.wav')
def main():
while True:
IMAGES['bgpic'] = pygame.image.load(random.choice(BGPICS))
IMAGES['bird'] = [pygame.image.load(frame) for frame in random.choice(BIRDS)]
pipe = pygame.image.load(random.choice(PIPES))
IMAGES['pipe'] = [pipe, pygame.transform.flip(pipe, False, True)]
SOUNDS['start'].play()
menu_window()
result = game_window()
end_window(result)
def menu_window():
SOUNDS['world_clear'].play()
floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH
floor_x = 0
guide_x = (MAP_WIDTH - IMAGES['guide'].get_width()) / 2
guide_y = MAP_HEIGHT * 0.12
bird_x = MAP_WIDTH * 0.2
bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2
bird_y_vel = 1
max_y_shift = 50
y_shift = 0
idx = 0
frame_seq = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
return
if floor_x -floor_gap:
floor_x = floor_x + floor_gap
else:
floor_x -= 4
if abs(y_shift) == max_y_shift:
bird_y_vel *= -1
else:
bird_y += bird_y_vel
y_shift += bird_y_vel
idx += 1
idx %= len(frame_seq)
frame_index = frame_seq[idx]
SCREEN.blit(IMAGES['bgpic'], (0, 0))
SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H))
SCREEN.blit(IMAGES['guide'], (guide_x, guide_y))
SCREEN.blit(IMAGES['bird'][frame_index], (bird_x, bird_y))
pygame.display.update()
CLOCK.tick(FPS)
def game_window():
SOUNDS['world_clear'].stop()
SOUNDS['main'].play()
score = 0
floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH
floor_x = 0
bird_x = MAP_WIDTH * 0.2
bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2
bird = Bird(bird_x, bird_y)
n_pair = round(MAP_WIDTH / PIPE_DISTANCE)
pipe_group = pygame.sprite.Group()
pipe_x = MAP_WIDTH
pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1])
pipe1 = Pipe(pipe_x, pipe_y, upwards=True)
pipe_group.add(pipe1)
pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False)
pipe_group.add(pipe2)
SOUNDS['flap'].play()
while True:
flap = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
SOUNDS['flap'].play()
flap = True
bird.update(flap)
if floor_x -floor_gap:
floor_x = floor_x + floor_gap
else:
floor_x -= 4
if len(pipe_group) / 2 < n_pair:
last_pipe = pipe_group.sprites()[-1]
pipe_x = last_pipe.rect.right + PIPE_DISTANCE
pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1])
pipe1 = Pipe(pipe_x, pipe_y, upwards=True)
pipe_group.add(pipe1)
pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False)
pipe_group.add(pipe2)
pipe_group.update()
if bird.rect.y > FLOOR_H or bird.rect.y < 0 or pygame.sprite.spritecollideany(bird, pipe_group):
SOUNDS['score'].stop()
SOUNDS['main'].stop()
SOUNDS['hit'].play()
SOUNDS['die'].play()
SOUNDS['death'].play()
result = {'bird': bird, 'score': score, 'pipe_group': pipe_group}
return result
if pipe_group.sprites()[0].rect.left == 0:
SOUNDS['score'].play()
score += 1
SCREEN.blit(IMAGES['bgpic'], (0, 0))
pipe_group.draw(SCREEN)
SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H))
SCREEN.blit(bird.image, bird.rect)
show_score(score)
pygame.display.update()
CLOCK.tick(FPS)
def end_window(result):
gameover_x = MAP_WIDTH * 0.5 - IMAGES['gameover'].get_width() / 2
gameover_y = MAP_HEIGHT * 0.4
bird = result['bird']
pipe_group = result['pipe_group']
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and bird.rect.y > FLOOR_H:
SOUNDS['death'].stop()
return
bird.go_die()
SCREEN.blit(IMAGES['bgpic'], (0, 0))
pipe_group.draw(SCREEN)
SCREEN.blit(IMAGES['floor'], (0, FLOOR_H))
SCREEN.blit(IMAGES['gameover'], (gameover_x, gameover_y))
show_score(result['score'])
SCREEN.blit(bird.image, bird.rect)
pygame.display.update()
CLOCK.tick(FPS)
def show_score(score):
score_str = str(score)
w = IMAGES['numbers'][0].get_width()
x = MAP_WIDTH / 2 - 2 * w / 2
y = MAP_HEIGHT * 0.1
for number in score_str:
SCREEN.blit(IMAGES['numbers'][int(number)], (x, y))
x += w
class Bird(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.frames = IMAGES['bird']
self.frame_list = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5
self.frame_index = 0
self.image = self.frames[self.frame_list[self.frame_index]]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.gravity = 1
self.flap_acc = -10
self.y_vel = -10
self.max_y_vel = 15
self.rotate = 0
self.rotate_vel = -3
self.max_rotate = -30
self.flap_rotate = 45
def update(self, flap=False):
if flap:
self.y_vel = self.flap_acc
self.rotate = self.flap_rotate
else:
self.rotate = self.rotate + self.rotate_vel
self.y_vel = min(self.y_vel + self.gravity, self.max_y_vel)
self.rect.y += self.y_vel
self.rorate = max(self.rotate + self.rotate_vel, self.max_rotate)
self.frame_index += 1
self.frame_index %= len(self.frame_list)
self.image = self.frames[self.frame_list[self.frame_index]]
self.image = pygame.transform.rotate(self.image, self.rotate)
def go_die(self):
if self.rect.y < FLOOR_H:
self.y_vel = self.max_y_vel
self.rect.y += self.y_vel
self.rotate = -90
self.image = self.frames[self.frame_list[self.frame_index]]
self.image = pygame.transform.rotate(self.image, self.rotate)
class Pipe(pygame.sprite.Sprite):
def __init__(self, x, y, upwards=True):
pygame.sprite.Sprite.__init__(self)
self.x_vel = -4
if upwards:
self.image = IMAGES['pipe'][0]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.top = y
else:
self.image = IMAGES['pipe'][1]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.bottom = y
def update(self):
self.rect.x += self.x_vel
if self.rect.right < 0:
self.kill()
if __name__ == '__main__':
main()
我把每行复杂的代码都写了注释
Original: https://blog.csdn.net/Cantevenl/article/details/115278806
Author: stan Z
Title: Python——pygame 面向对象的飞行小鸟(Flappy bird)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/780549/
转载文章受原作者版权保护。转载请注明原作者出处!