pyzyd 发表于 2025-5-24 10:04:56

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,

FishC 发表于 2025-5-24 10:06:04

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 小助理,如未能正确解答您的问题,请继续追问。

小甲鱼的二师兄 发表于 2025-5-24 10:21:34

不错不错,这个版本很精致~

不二如是 发表于 2025-5-24 10:54:45

有趣~

player-none 发表于 2025-5-24 11:21:21

评分限制到了,但还是来支持下{:10_298:}

zlim 发表于 2025-5-24 12:40:49

挺不错{:10_257:}k

小甲鱼 发表于 2025-5-24 14:12:26

不错不错~

sanyecl 发表于 2025-5-24 15:25:07

牛啊牛啊!

某一个“天” 发表于 2025-5-24 16:04:23

哈哈哈,我也有这个素材

琅琊王朝 发表于 2025-5-24 19:26:21

好厉害

player-none 发表于 2025-5-24 19:35:01

建议发到GitHub

pyzyd 发表于 2025-5-24 20:08:05

player-none 发表于 2025-5-24 19:35
建议发到GitHub

git都没搞明白,账号也没有一个,技术也不好,只会在github上下载东西{:10_266:}

player-none 发表于 2025-5-24 20:10:40

pyzyd 发表于 2025-5-24 20:08
git都没搞明白,账号也没有一个,技术也不好,只会在github上下载东西

论坛上有小甲鱼发的教程的

pyzyd 发表于 2025-5-24 20:19:11

player-none 发表于 2025-5-24 20:10
论坛上有小甲鱼发的教程的

有时间去研究一下{:10_265:}

道中仙 发表于 2025-5-24 21:02:47

1

player-none 发表于 2025-5-25 09:58:13

pyzyd 发表于 2025-5-24 20:19
有时间去研究一下

现在好了嘛{:10_335:}

pyzyd 发表于 2025-5-25 10:08:00

player-none 发表于 2025-5-25 09:58
现在好了嘛

刚注册github{:10_257:}

player-none 发表于 2025-5-25 10:15:13

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

一定能行 发表于 2025-5-25 11:09:49

真牛{:10_256:}

Tyroe 发表于 2025-5-25 12:20:52

{:5_101:}
页: [1] 2
查看完整版本: FlappedBird 飞翔的小鸟源码及素材