FlappedBird 飞翔的小鸟源码及素材
本帖最后由 pyzyd 于 2025-5-24 17:36 编辑pygame制作的小游戏,顺便发点鱼币{:10_287:}
import pygame
from pygame.locals import *
from pygame.sprite import Sprite
import sys
import traceback
from random import randint
class Bird(Sprite):
def __init__(self, bg_size):
Sprite.__init__(self)
# 初始化小鸟的状态和属性
# 定义鸟
self.image = pygame.image.load("./res/bird0_0.png").convert_alpha()
self.image2 = pygame.image.load("./res/bird0_2.png").convert_alpha()
self.dead_image =pygame.image.load("./res/dead.png").convert_alpha()
# 初始化鸟的运动方向
self.is_up = False
self.width, self.height = bg_size
self.rect = self.image.get_rect()# 获取当前图像的矩形区域
self.mask = pygame.mask.from_surface(self.image)
# 初始速度
self.velocity = 0
# 加速度
self.acceleration = 2
self.rect.left = 0
self.rect.centery = self.height//2
def move(self):
"""控制小鸟上移"""
self.is_up = True
self.velocity = -4# 小鸟向上飞行时的速度
self.acceleration = 0# 重置加速度
def drop(self):
"""小鸟下落"""
if self.acceleration != 0:
self.is_up = False
self.acceleration = 1# 恢复加速度
self.velocity += self.acceleration# 更新速度
def reset(self):
self.rect.left = 0
self.rect.centery = self.height//2
self.is_up = False
self.velocity = 0
class Pipeline(Sprite):
index = 0
def __init__(self, bg_size, pipetype):
Sprite.__init__(self)
self.width, self.height = bg_size
self.down_images =[pygame.image.load("./res/pipe_down.png").convert_alpha(),
pygame.image.load("./res/pipe2_down.png").convert_alpha()]
self.up_images = [pygame.image.load("./res/pipe_up.png").convert_alpha(),
pygame.image.load("./res/pipe2_up.png").convert_alpha()]
self.index = Pipeline.index
self.pipetype = pipetype
if pipetype == 'down':
self.image = self.down_images
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
self.rect.right = self.width
self.rect.bottom = randint(self.rect.height // 3 + 10, self.rect.height)
elif pipetype == 'up':
self.image = self.up_images
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
self.rect.right = self.width
self.rect.top = self.height
Pipeline.index = 1 - Pipeline.index
self.velocity = -3
def reset(self,bg_size):
if self.pipetype == 'down':
self.rect.right= bg_size
self.rect.bottom = randint(self.rect.height // 3, self.rect.height)
elif self.pipetype == 'up':
self.rect.right = bg_size
self.rect.top = bg_size
def move(self):
self.rect.left += self.velocity
class Score():
def __init__(self, score_type=1):
self.num_images1 = [pygame.image.load("./res/font_048.png").convert_alpha(), pygame.image.load("./res/font_049.png").convert_alpha(),
pygame.image.load("./res/font_050.png").convert_alpha(),pygame.image.load("./res/font_051.png").convert_alpha(),
pygame.image.load("./res/font_052.png").convert_alpha(), pygame.image.load("./res/font_053.png").convert_alpha(),
pygame.image.load("./res/font_054.png").convert_alpha(), pygame.image.load("./res/font_055.png").convert_alpha(),
pygame.image.load("./res/font_056.png").convert_alpha(), pygame.image.load("./res/font_057.png").convert_alpha()]
self.num_images2 = [pygame.image.load("./res/number_context_00.png").convert_alpha(), pygame.image.load("./res/number_context_01.png").convert_alpha(),
pygame.image.load("./res/number_context_02.png").convert_alpha(), pygame.image.load("./res/number_context_03.png").convert_alpha(),
pygame.image.load("./res/number_context_04.png").convert_alpha(), pygame.image.load("./res/number_context_05.png").convert_alpha(),
pygame.image.load("./res/number_context_06.png").convert_alpha(), pygame.image.load("./res/number_context_07.png").convert_alpha(),
pygame.image.load("./res/number_context_08.png").convert_alpha(), pygame.image.load("./res/number_context_09.png").convert_alpha(),]
self.num_images3 = [pygame.image.load("./res/number_score_00.png").convert_alpha(), pygame.image.load("./res/number_score_01.png").convert_alpha(),
pygame.image.load("./res/number_score_02.png").convert_alpha(), pygame.image.load("./res/number_score_03.png").convert_alpha(),
pygame.image.load("./res/number_score_04.png").convert_alpha(), pygame.image.load("./res/number_score_05.png").convert_alpha(),
pygame.image.load("./res/number_score_06.png").convert_alpha(), pygame.image.load("./res/number_score_07.png").convert_alpha(),
pygame.image.load("./res/number_score_08.png").convert_alpha(), pygame.image.load("./res/number_score_09.png").convert_alpha(), ]
if score_type == 1:
self.num_images = self.num_images1
elif score_type == 2:
self.num_images = self.num_images2
elif score_type == 3:
self.num_images = self.num_images3
self.zero_image = self.num_images
self.one_image = self.num_images
self.two_image = self.num_images
self.three_image = self.num_images
self.four_image = self.num_images
self.five_image = self.num_images
self.six_image = self.num_images
self.seven_image = self.num_images
self.eight_image = self.num_images
self.nine_image = self.num_images
self.rect = self.zero_image.get_rect()
def draw_score(self, screen, num_str, pos=(10, 10)):
self.rect.left, self.rect.top = pos
for s in num_str:
if s == '0':
screen.blit(self.zero_image, self.rect)
elif s == '1':
screen.blit(self.one_image, self.rect)
elif s == '2':
screen.blit(self.two_image, self.rect)
elif s == '3':
screen.blit(self.three_image, self.rect)
elif s == '4':
screen.blit(self.four_image, self.rect)
elif s == '5':
screen.blit(self.five_image, self.rect)
elif s == '6':
screen.blit(self.six_image, self.rect)
elif s == '7':
screen.blit(self.seven_image, self.rect)
elif s == '8':
screen.blit(self.eight_image, self.rect)
elif s == '9':
screen.blit(self.nine_image, self.rect)
self.rect.left += 5 * self.rect.width // 4
class FlappyBird():
def __init__(self):
pygame.init()
# 设置屏幕
self.bg_size = (288, 512)
self.screen = pygame.display.set_mode(self.bg_size)
pygame.display.set_caption("Flappy Bird")
self.bg_day_image = pygame.image.load(r'res\bg_day.png').convert_alpha()
self.bg_night_image = pygame.image.load(r'res\bg_night.png').convert_alpha()
# 陆地
self.land_image = pygame.image.load(r'res\land.png').convert_alpha()
self.land_rect = self.land_image.get_rect()
self.land_rect.left = 0
self.land_rect.bottom = self.bg_size
# 加载封面图像
self.title_image = pygame.image.load(r'res\title.png').convert_alpha()
self.title_rect = self.title_image.get_rect()
self.tutorial_image = pygame.image.load(r'res\tutorial.png').convert_alpha()
self.tutorial_rect = self.tutorial_image.get_rect()
self.text_ready_image = pygame.image.load(r'res\text_ready.png').convert_alpha()
self.text_ready_rect = self.text_ready_image.get_rect()
self.button_play_image = pygame.image.load(r'res\button_play.png').convert_alpha()
self.button_play_rect = self.button_play_image.get_rect()
self.game_over_image = pygame.image.load(r'res\text_game_over.png').convert_alpha()
self.game_over_rect = self.game_over_image.get_rect()
self.is_over = False
self.new_image = pygame.image.load(r'res\new.png').convert_alpha()
self.new_rect = self.new_image.get_rect()
# 分数
self.score = Score()
self.score_num = 0
self.score_str = str(self.score_num)
self.score2 = Score(2)
self.score3 = Score(3)
#
self.score_panel_image = pygame.image.load(r'res\score_panel.png').convert_alpha()
self.score_panel_rect = self.score_panel_image.get_rect()
self.medal_0_image = pygame.image.load(r'res\medals_0.png').convert_alpha()
self.medal_1_image = pygame.image.load(r'res\medals_1.png').convert_alpha()
self.medal_2_image = pygame.image.load(r'res\medals_2.png').convert_alpha()
self.medal_3_image = pygame.image.load(r'res\medals_3.png').convert_alpha()
self.medal_rect = self.medal_0_image.get_rect()
# 用于阻止重复打开记录文件
self.recorded = False
# 一天计时器
self.DAYORNIGHT = USEREVENT + 1
self.is_day = True
# 在游戏初始化时设置计时器
pygame.time.set_timer(self.DAYORNIGHT, 10 * 1000)
# 初始化小鸟
self.bird = Bird(self.bg_size)
# 初始化管道
self.pipe_interval = 2*self.bg_size // 3
self.down1_size = self.bg_size
self.pipe_down1 = Pipeline(self.down1_size, pipetype='down')
self.down2_size = (self.bg_size + self.pipe_interval, self.bg_size)
self.pipe_down2 = Pipeline(self.down2_size, pipetype='down')
self.up1_size = (self.bg_size, self.pipe_down1.rect.bottom + 150)
self.pipe_up1 = Pipeline(self.up1_size, pipetype='up')
self.up2_size = (self.bg_size + self.pipe_interval,self.pipe_down2.rect.bottom + 150)
self.pipe_up2 = Pipeline(self.up2_size, pipetype='up')
# 绘制背景
self.eclipse()
# 游戏时钟
self.clock = pygame.time.Clock()
# 设置延迟
self.delay = 100
# 是否开始游戏
self.is_start = False
def eclipse(self):
"""绘制白天黑夜交替"""
if self.is_day:
self.screen.blit(self.bg_day_image, (0, 0))
else:
self.screen.blit(self.bg_night_image, (0, 0))
self.screen.blit(self.land_image, self.land_rect)
def reset_pipes(self):
self.pipe_interval = 2 * self.bg_size // 3
self.down1_size = self.bg_size
self.pipe_down1 = Pipeline(self.down1_size, pipetype='down')
self.down2_size = (self.bg_size + self.pipe_interval, self.bg_size)
self.pipe_down2 = Pipeline(self.down2_size, pipetype='down')
self.up1_size = (self.bg_size, self.pipe_down1.rect.bottom + 150)
self.pipe_up1 = Pipeline(self.up1_size, pipetype='up')
self.up2_size = (self.bg_size + self.pipe_interval, self.pipe_down2.rect.bottom + 150)
self.pipe_up2 = Pipeline(self.up2_size, pipetype='up')
def reset(self):
self.is_over = False
self.is_start = False
self.bird.reset()
self.reset_pipes()
self.score_num = 0
self.score_str = str(self.score_num)
pygame.time.set_timer(self.DAYORNIGHT, 10 * 1000)
def draw_over(self):
"""绘制结束界面"""
best_score_str = ''
if not self.recorded:
self.recorded = True
# 读取历史最高分
try:
with open("record.txt", 'r') as f:
best_score_str = f.read()
except:
with open("record.txt", 'w') as f:
best_score_str = self.score_str
f.write(self.score_str)
else:
# 如果玩家得分高于历史最高得分,则存档
if self.score_str > best_score_str:
with open("record.txt", 'w') as f:
f.write(self.score_str)
if self.score_num == 0:
self.medal_image = self.medal_0_image
elif self.score_num < 20:
self.medal_image = self.medal_1_image
elif self.score_num < 50:
self.medal_image = self.medal_2_image
else:
self.medal_image = self.medal_3_image
self.game_over_rect.center = (self.bg_size//2, self.bg_size//2)
self.score_panel_rect.centerx = self.game_over_rect.centerx
self.score_panel_rect.bottom = self.game_over_rect.top - 20
self.new_rect.centerx = self.game_over_rect.centerx
self.new_rect.top = self.game_over_rect.bottom + 20
self.medal_rect.centery = 67
self.medal_rect.left = 30
self.screen.blit(self.new_image, self.new_rect)
self.screen.blit(self.score_panel_image, self.score_panel_rect)
self.score_panel_image.blit(self.medal_image, self.medal_rect)
print(self.score_str)
self.score2.draw_score(self.score_panel_image, self.score_str, (self.score_panel_rect.width - 60, self.score_panel_rect.height - 90))
self.score3.draw_score(self.score_panel_image, best_score_str, (self.score_panel_rect.width - 60, self.score_panel_rect.height - 40))
self.screen.blit(self.game_over_image, self.game_over_rect)
self.screen.blit(self.button_play_image, self.button_play_rect)
def draw_pipe(self):
self.up_down_interval = randint(90,150)
if self.pipe_down1.rect.right < 0:
self.down1_size = (self.pipe_down2.rect.right + self.pipe_interval, self.bg_size)
self.pipe_down1.reset(self.down1_size)
elif self.pipe_up1.rect.right < 0:
self.up1_size = (self.pipe_down2.rect.right + self.pipe_interval, self.pipe_down1.rect.bottom + self.up_down_interval)
self.pipe_up1.reset(self.up1_size)
self.score_num += 1
elif self.pipe_down2.rect.right < 0:
self.down2_size = (self.pipe_down1.rect.right + self.pipe_interval, self.bg_size)
self.pipe_down2.reset(self.down2_size)
elif self.pipe_up2.rect.right < 0:
self.up2_size = (self.pipe_down1.rect.right + self.pipe_interval, self.pipe_down2.rect.bottom + self.up_down_interval)
self.pipe_up2.reset(self.up2_size)
self.score_num += 1
self.screen.blit(self.pipe_down1.image, self.pipe_down1.rect)
self.screen.blit(self.pipe_up1.image, self.pipe_up1.rect)
self.screen.blit(self.pipe_down2.image, self.pipe_down2.rect)
self.screen.blit(self.pipe_up2.image, self.pipe_up2.rect)
def draw_bird(self):
if self.bird.rect.bottom >= self.screen.get_rect().bottom:
self.bird.rect.bottom = self.screen.get_rect().bottom
# 结束游戏
self.is_over = True
else:
self.bird.rect.centery += self.bird.velocity# 根据速度更新位置
if not self.is_over:
if self.bird.is_up:
self.screen.blit(self.bird.image, self.bird.rect)
else:
self.screen.blit(self.bird.image2, self.bird.rect)
else:
self.screen.blit(self.bird.dead_image, self.bird.rect)
def _update(self):
"""更新屏幕"""
self.eclipse()
self.draw_pipe()
self.draw_bird()
self.score_str = str(self.score_num)
self.score.draw_score(self.screen, self.score_str)
if self.is_over:
self.draw_over()
pygame.time.set_timer(self.DAYORNIGHT, 0)
pygame.display.update()
def cover(self):
"""开始界面"""
self.screen.blit(self.bg_night_image, (0,0))
self.title_rect.centerx = self.screen.get_rect().centerx
self.title_rect.top = 50
self.screen.blit(self.title_image, self.title_rect)
self.tutorial_rect.centerx = self.screen.get_rect().centerx
self.tutorial_rect.top = self.title_rect.bottom + 20
self.screen.blit(self.tutorial_image, self.tutorial_rect)
self.text_ready_rect.centerx = self.screen.get_rect().centerx
self.text_ready_rect.top = self.tutorial_rect.bottom + 20
self.screen.blit(self.text_ready_image, self.text_ready_rect)
self.button_play_rect.centerx = self.screen.get_rect().centerx
self.button_play_rect.top = self.text_ready_rect.bottom + 20
self.screen.blit(self.button_play_image, self.button_play_rect)
pygame.display.update()
def play(self):
"""游戏开始"""
self.eclipse()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 只有在接收到计时器事件时,才切换白天黑夜
elif event.type == self.DAYORNIGHT:
self.is_day = not self.is_day
# 鼠标点击
elif event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed() == 1:
pos = pygame.mouse.get_pos()
if self.button_play_rect.collidepoint(pos):
if not self.is_start:
self.is_start = True
elif self.is_over:
self.is_over = False
self.reset()
self.bird.move()
if pygame.sprite.collide_mask(self.bird, self.pipe_down1) or pygame.sprite.collide_mask(self.bird, self.pipe_down2) or\
pygame.sprite.collide_mask(self.bird, self.pipe_up1) or pygame.sprite.collide_mask(self.bird, self.pipe_up2):
self.is_over = True
if not self.is_start:
self.cover()
else:
if self.delay % 6 == 0:
self.bird.drop()
self.pipe_down1.move()
self.pipe_up1.move()
self.pipe_down2.move()
self.pipe_up2.move()
if self.is_over:
self.pipe_down1.velocity = 0
self.pipe_down2.velocity = 0
self.pipe_up1.velocity = 0
self.pipe_up2.velocity = 0
self._update()
self.clock.tick(60)
self.delay -= 1
if self.delay == 0:
self.delay = 100
if __name__ == '__main__':
flappybird = FlappyBird()
try:
flappybird.play()
except SystemExit:
pass
except:
traceback.print_exc()
pygame.quit()
自取即可
上面那个有个小bug,
Flapped Bird游戏源码(基于pygame)
import pygame
import sys
import random
# 初始化pygame
pygame.init()
# 游戏窗口设置
WIN_WIDTH = 400
WIN_HEIGHT = 600
win = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
pygame.display.set_caption("Flapped Bird")
# 颜色定义
SKY_BLUE = (135, 206, 235)
YELLOW = (255, 255, 0)
GREEN = (0, 128, 0)
# 小鸟属性
bird_x = 50
bird_y = 300
bird_radius = 15
gravity = 0.5
jump_speed = -8
bird_velocity = 0
# 管道属性
pipe_width = 50
pipe_gap = 150
pipe_list = []
SPAWNPIPE = pygame.USEREVENT
pygame.time.set_timer(SPAWNPIPE, 1500)
# 分数
score = 0
font = pygame.font.SysFont("arial", 30)
def draw_bird():
pygame.draw.circle(win, YELLOW, (bird_x, int(bird_y)), bird_radius)
def create_pipe():
gap_y = random.randint(200, 400)
return
def move_pipes(pipes):
for pipe in pipes:
pipe -= 3
return > -pipe_width]
def draw_pipes(pipes):
for pipe in pipes:
# 上管道
pygame.draw.rect(win, GREEN, (pipe, 0, pipe_width, pipe - pipe_gap//2))
# 下管道
pygame.draw.rect(win, GREEN, (pipe, pipe + pipe_gap//2, pipe_width, WIN_HEIGHT))
def check_collision(pipes):
for pipe in pipes:
# 检测与上下管道的碰撞
if (bird_x + bird_radius > pipe and bird_x - bird_radius < pipe + pipe_width):
if (bird_y - bird_radius < pipe - pipe_gap//2 or
bird_y + bird_radius > pipe + pipe_gap//2):
return True
# 检测上下边界
if bird_y - bird_radius < 0 or bird_y + bird_radius > WIN_HEIGHT:
return True
return False
# 游戏主循环
clock = pygame.time.Clock()
running = True
while running:
clock.tick(30)
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bird_velocity = jump_speed
if event.type == SPAWNPIPE:
pipe_list.append(create_pipe())
# 物理计算
bird_velocity += gravity
bird_y += bird_velocity
# 移动管道
pipe_list = move_pipes(pipe_list)
# 碰撞检测
if check_collision(pipe_list):
running = False
# 绘制画面
win.fill(SKY_BLUE)
draw_pipes(pipe_list)
draw_bird()
# 显示分数
score_text = font.render(f"Score: {len(pipe_list)}", True, (0, 0, 0))
win.blit(score_text, (10, 10))
pygame.display.update()
pygame.quit()
sys.exit()
素材建议:
[*]小鸟图片:可以使用圆形黄色图案代替
[*]管道素材:绿色矩形即可
[*]背景图:建议使用天空蓝色渐变图片
(需要完整素材包可私信联系,代码可直接复制到本地pygame环境运行)
https://fishc.com.cn/static/image/filetype/zip.gif [下载素材包](示例链接,需替换真实地址)
温馨提示:
1. 需要先安装pygame库:pip install pygame
2. 按空格键控制小鸟跳跃
3. 碰撞检测和分数系统已内置
4. 难度可通过调整pipe_gap和管道移动速度修改
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 不错不错,这个版本很精致~ 有趣~ 评分限制到了,但还是来支持下{:10_298:} 挺不错{:10_257:}k 不错不错~ 牛啊牛啊! 哈哈哈,我也有这个素材 好厉害 建议发到GitHub player-none 发表于 2025-5-24 19:35
建议发到GitHub
git都没搞明白,账号也没有一个,技术也不好,只会在github上下载东西{:10_266:} pyzyd 发表于 2025-5-24 20:08
git都没搞明白,账号也没有一个,技术也不好,只会在github上下载东西
论坛上有小甲鱼发的教程的 player-none 发表于 2025-5-24 20:10
论坛上有小甲鱼发的教程的
有时间去研究一下{:10_265:} 1 pyzyd 发表于 2025-5-24 20:19
有时间去研究一下
现在好了嘛{:10_335:} player-none 发表于 2025-5-25 09:58
现在好了嘛
刚注册github{:10_257:} pyzyd 发表于 2025-5-25 10:08
刚注册github
https://github.com/new 新建 repo
然后打开你项目的目录,
git init
git remote add origin https://(你repo的完整地址)
git add *
git commit -m "提交说明"
git push -u origin master(报错的话用 ... origin main)
btw,账号发我下,互相follow 真牛{:10_256:} {:5_101:}
页:
[1]
2