Pygame开发游戏流程详解
Pygame 开发游戏详细流程
一、Pygame 核心架构
游戏主循环 ├── 事件处理 (Event Handling) ├── 游戏逻辑更新 (Game Logic) ├── 渲染绘制 (Rendering) └── 帧率控制 (FPS Control) 二、完整开发流程详解
1. 基础框架搭建
import pygame import sys classGame:def__init__(self):"""初始化游戏""" pygame.init()# 1. 创建游戏窗口 self.screen_width =800 self.screen_height =600 self.screen = pygame.display.set_mode((self.screen_width, self.screen_height)) pygame.display.set_caption("我的游戏")# 2. 初始化游戏时钟(控制帧率) self.clock = pygame.time.Clock() self.FPS =60# 3. 游戏状态 self.running =True self.game_over =False# 4. 颜色定义(RGB) self.BLACK =(0,0,0) self.WHITE =(255,255,255) self.RED =(255,0,0) self.GREEN =(0,255,0) self.BLUE =(0,0,255)# 5. 初始化游戏资源 self.load_resources()defload_resources(self):"""加载游戏资源"""# 字体 self.font_small = pygame.font.SysFont(None,36) self.font_large = pygame.font.SysFont(None,72)# 加载图片try: self.player_image = pygame.image.load("player.png").convert_alpha()except:# 如果图片不存在,创建一个矩形代替 self.player_image = pygame.Surface((50,50)) self.player_image.fill(self.BLUE)# 加载音效try: self.jump_sound = pygame.mixer.Sound("jump.wav")except: self.jump_sound =None# 背景音乐 pygame.mixer.music.load("bgm.mp3") pygame.mixer.music.play(-1)# -1表示循环播放2. 主游戏循环
defrun(self):"""主游戏循环"""while self.running:# 1. 处理事件 self.handle_events()# 2. 更新游戏状态(只有游戏没结束时才更新)ifnot self.game_over: self.update()# 3. 绘制画面 self.render()# 4. 控制帧率 self.clock.tick(self.FPS)# 游戏结束,退出 self.quit()defhandle_events(self):"""事件处理"""for event in pygame.event.get():if event.type== pygame.QUIT: self.running =False# 键盘按下事件elif event.type== pygame.KEYDOWN: self.on_key_down(event.key)# 键盘释放事件elif event.type== pygame.KEYUP: self.on_key_up(event.key)# 鼠标事件elif event.type== pygame.MOUSEBUTTONDOWN: self.on_mouse_click(event.pos, event.button)3. 精灵系统(Sprite System)
classPlayer(pygame.sprite.Sprite):"""玩家角色类"""def__init__(self, x, y):super().__init__()# 创建图像和矩形 self.image = pygame.Surface((50,50)) self.image.fill((0,0,255))# 加载动画帧 self.frames =[] self.load_animation_frames() self.current_frame =0 self.animation_speed =0.2 self.animation_timer =0 self.rect = self.image.get_rect() self.rect.center =(x, y)# 物理属性 self.velocity = pygame.Vector2(0,0) self.speed =5 self.jump_power =-15 self.gravity =0.8 self.on_ground =False# 游戏属性 self.health =100 self.score =0defload_animation_frames(self):"""加载动画帧"""for i inrange(4): frame = pygame.Surface((50,50)) frame.fill((0,0,200+ i *15)) self.frames.append(frame)defupdate(self, platforms):"""更新玩家状态"""# 处理用户输入 keys = pygame.key.get_pressed()# 水平移动 self.velocity.x =0if keys[pygame.K_LEFT]: self.velocity.x =-self.speed if keys[pygame.K_RIGHT]: self.velocity.x = self.speed # 跳跃if keys[pygame.K_SPACE]and self.on_ground: self.velocity.y = self.jump_power self.on_ground =False# 应用重力 self.velocity.y += self.gravity # 水平移动 self.rect.x += self.velocity.x # 水平碰撞检测 self.check_horizontal_collision(platforms)# 垂直移动 self.rect.y += self.velocity.y # 垂直碰撞检测 self.check_vertical_collision(platforms)# 更新动画 self.update_animation()# 边界检查 self.check_bounds()defcheck_horizontal_collision(self, platforms):for platform in platforms:if self.rect.colliderect(platform):if self.velocity.x >0:# 向右移动 self.rect.right = platform.left elif self.velocity.x <0:# 向左移动 self.rect.left = platform.right defcheck_vertical_collision(self, platforms): self.on_ground =Falsefor platform in platforms:if self.rect.colliderect(platform):if self.velocity.y >0:# 向下移动 self.rect.bottom = platform.top self.velocity.y =0 self.on_ground =Trueelif self.velocity.y <0:# 向上移动 self.rect.top = platform.bottom self.velocity.y =0defupdate_animation(self):"""更新动画帧""" self.animation_timer += self.animation_speed if self.animation_timer >=1: self.current_frame =(self.current_frame +1)%len(self.frames) self.image = self.frames[self.current_frame] self.animation_timer =0defcheck_bounds(self):"""检查边界"""if self.rect.top >600:# 掉落屏幕 self.health =04. 游戏场景管理
classGameScene:"""游戏场景基类"""def__init__(self, game): self.game = game defhandle_events(self):passdefupdate(self):passdefrender(self):passclassMainMenuScene(GameScene):"""主菜单场景"""def__init__(self, game):super().__init__(game) self.buttons =[] self.create_buttons()defcreate_buttons(self):"""创建菜单按钮""" button_width, button_height =200,50# 开始游戏按钮 start_rect = pygame.Rect( self.game.screen_width //2- button_width //2,200, button_width, button_height ) self.buttons.append({'rect': start_rect,'text':'开始游戏','action': self.start_game })# 退出游戏按钮 quit_rect = pygame.Rect( self.game.screen_width //2- button_width //2,280, button_width, button_height ) self.buttons.append({'rect': quit_rect,'text':'退出游戏','action': self.quit_game })defhandle_events(self):for event in pygame.event.get():if event.type== pygame.QUIT: self.game.running =Falseelif event.type== pygame.MOUSEBUTTONDOWN:if event.button ==1:# 左键 self.check_button_click(event.pos)defcheck_button_click(self, pos):"""检查按钮点击"""for button in self.buttons:if button['rect'].collidepoint(pos): button['action']()defstart_game(self):"""切换到游戏场景""" self.game.current_scene = GamePlayScene(self.game)defquit_game(self): self.game.running =Falsedefrender(self):# 绘制背景 self.game.screen.fill((30,30,70))# 绘制标题 title_font = pygame.font.SysFont(None,72) title_text = title_font.render("我的游戏",True,(255,255,255)) title_rect = title_text.get_rect(center=(self.game.screen_width//2,100)) self.game.screen.blit(title_text, title_rect)# 绘制按钮for button in self.buttons:# 绘制按钮背景 pygame.draw.rect(self.game.screen,(50,150,200), button['rect']) pygame.draw.rect(self.game.screen,(255,255,255), button['rect'],3)# 绘制按钮文字 button_font = pygame.font.SysFont(None,36) button_text = button_font.render(button['text'],True,(255,255,255)) text_rect = button_text.get_rect(center=button['rect'].center) self.game.screen.blit(button_text, text_rect)5. 完整游戏示例:平台跳跃游戏
import pygame import sys import random classPlatformGame:def__init__(self): pygame.init()# 屏幕设置 self.WIDTH =800 self.HEIGHT =600 self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT)) pygame.display.set_caption("平台跳跃")# 颜色 self.SKY_BLUE =(135,206,235) self.GROUND_COLOR =(101,67,33) self.PLATFORM_COLOR =(0,200,100)# 游戏状态 self.clock = pygame.time.Clock() self.FPS =60 self.running =True self.score =0 self.font = pygame.font.SysFont(None,36)# 游戏对象 self.player = pygame.Rect(100,300,30,30) self.player_vel_y =0 self.gravity =0.8 self.jump_strength =-15 self.on_ground =False# 平台 self.platforms =[ pygame.Rect(0,500,800,100),# 地面 pygame.Rect(200,400,200,20), pygame.Rect(450,350,150,20), pygame.Rect(300,250,200,20), pygame.Rect(100,200,150,20), pygame.Rect(550,150,200,20),]# 金币 self.coins =[] self.generate_coins()# 敌人 self.enemies =[] self.spawn_timer =0 self.spawn_interval =2000# 毫秒defgenerate_coins(self):"""生成金币"""for platform in self.platforms[1:]:# 除了地面 x = random.randint(platform.left +10, platform.right -20) y = platform.top -30 self.coins.append(pygame.Rect(x, y,15,15))defhandle_events(self):for event in pygame.event.get():if event.type== pygame.QUIT: self.running =Falseelif event.type== pygame.KEYDOWN:if event.key == pygame.K_SPACE and self.on_ground: self.player_vel_y = self.jump_strength self.on_ground =Falseelif event.key == pygame.K_r:# 重新开始 self.__init__()defupdate(self):# 键盘输入 keys = pygame.key.get_pressed()# 水平移动 player_speed =5if keys[pygame.K_LEFT]: self.player.x -= player_speed if keys[pygame.K_RIGHT]: self.player.x += player_speed # 应用重力 self.player_vel_y += self.gravity self.player.y += self.player_vel_y # 边界检查if self.player.left <0: self.player.left =0if self.player.right > self.WIDTH: self.player.right = self.WIDTH # 平台碰撞检测 self.on_ground =Falsefor platform in self.platforms:if self.player.colliderect(platform):if self.player_vel_y >0:# 下落 self.player.bottom = platform.top self.player_vel_y =0 self.on_ground =Trueelif self.player_vel_y <0:# 上升 self.player.top = platform.bottom self.player_vel_y =0# 金币收集for coin in self.coins[:]:if self.player.colliderect(coin): self.coins.remove(coin) self.score +=10# 生成敌人 current_time = pygame.time.get_ticks()if current_time - self.spawn_timer > self.spawn_interval: self.enemies.append(pygame.Rect( random.randint(0, self.WIDTH -30),-30,30,30)) self.spawn_timer = current_time # 更新敌人for enemy in self.enemies[:]: enemy.y +=3if enemy.top > self.HEIGHT: self.enemies.remove(enemy)# 玩家与敌人碰撞if self.player.colliderect(enemy): self.game_over()defgame_over(self):"""游戏结束""" game_over_font = pygame.font.SysFont(None,72) game_over_text = game_over_font.render("游戏结束!",True,(255,0,0)) score_text = self.font.render(f"最终得分: {self.score}",True,(255,255,255)) restart_text = self.font.render("按 R 重新开始",True,(255,255,255))# 绘制半透明背景 overlay = pygame.Surface((self.WIDTH, self.HEIGHT), pygame.SRCALPHA) overlay.fill((0,0,0,180)) self.screen.blit(overlay,(0,0))# 绘制文字 self.screen.blit(game_over_text,(self.WIDTH//2- game_over_text.get_width()//2, self.HEIGHT//2-100)) self.screen.blit(score_text,(self.WIDTH//2- score_text.get_width()//2, self.HEIGHT//2)) self.screen.blit(restart_text,(self.WIDTH//2- restart_text.get_width()//2, self.HEIGHT//2+50)) pygame.display.flip()# 等待玩家按键 waiting =Truewhile waiting:for event in pygame.event.get():if event.type== pygame.QUIT: self.running =False waiting =Falseelif event.type== pygame.KEYDOWN:if event.key == pygame.K_r: self.__init__() waiting =Falsedefrender(self):# 绘制背景 self.screen.fill(self.SKY_BLUE)# 绘制平台for platform in self.platforms: pygame.draw.rect(self.screen, self.PLATFORM_COLOR, platform)# 绘制地面 pygame.draw.rect(self.screen, self.GROUND_COLOR, self.platforms[0])# 绘制金币for coin in self.coins: pygame.draw.circle(self.screen,(255,215,0), coin.center, coin.width//2)# 绘制敌人for enemy in self.enemies: pygame.draw.rect(self.screen,(255,0,0), enemy)# 绘制玩家 pygame.draw.rect(self.screen,(0,0,255), self.player)# 绘制分数 score_text = self.font.render(f"分数: {self.score}",True,(255,255,255)) self.screen.blit(score_text,(10,10)) pygame.display.flip()defrun(self):while self.running: self.handle_events() self.update() self.render() self.clock.tick(self.FPS) pygame.quit() sys.exit()if __name__ =="__main__": game = PlatformGame() game.run()三、最佳实践和优化技巧
1. 性能优化
# 1. 使用双缓冲 screen = pygame.display.set_mode((width, height), pygame.DOUBLEBUF)# 2. 图像转换优化 image = pygame.image.load("image.png").convert()# 普通转换 image = pygame.image.load("image.png").convert_alpha()# 带透明度转换# 3. 脏矩形更新(只更新变化的部分) dirty_rects =[] dirty_rects.append(player.rect) pygame.display.update(dirty_rects)# 4. 对象池(减少对象创建销毁)classObjectPool:def__init__(self, create_func, max_size=100): self.pool =[] self.create_func = create_func self.max_size = max_size defget(self):if self.pool:return self.pool.pop()return self.create_func()defrecycle(self, obj):iflen(self.pool)< self.max_size: self.pool.append(obj)2. 状态机管理
classStateMachine:def__init__(self): self.states ={} self.current_state =Nonedefadd_state(self, name, state): self.states[name]= state defchange_state(self, name):if self.current_state: self.current_state.exit() self.current_state = self.states[name] self.current_state.enter()defupdate(self):if self.current_state: self.current_state.update()defrender(self):if self.current_state: self.current_state.render()classGameState:defenter(self):passdefexit(self):passdefupdate(self):passdefrender(self):pass3. 粒子系统
classParticle:def__init__(self, x, y): self.x = x self.y = y self.vx = random.uniform(-2,2) self.vy = random.uniform(-5,-2) self.lifetime =60 self.color = random.choice([(255,255,0),(255,165,0)])defupdate(self): self.x += self.vx self.y += self.vy self.vy +=0.1 self.lifetime -=1defdraw(self, screen): radius =max(1, self.lifetime //15) pygame.draw.circle(screen, self.color,(int(self.x),int(self.y)), radius)四、调试技巧
- 显示帧率
fps_text = font.render(f"FPS: {int(clock.get_fps())}",True, WHITE)- 显示调试信息
defdraw_debug_info(): debug_info =[f"玩家位置: ({player.rect.x}, {player.rect.y})",f"速度: ({player.velocity.x:.1f}, {player.velocity.y:.1f})",f"金币数量: {len(coins)}",f"敌人数量: {len(enemies)}"]for i, info inenumerate(debug_info): text = font.render(info,True, WHITE) screen.blit(text,(10,30+ i *25))- 碰撞框显示
pygame.draw.rect(screen,(255,0,0),object.rect,2)# 红色边框五、项目结构建议
my_game/ ├── main.py # 游戏主入口 ├── game.py # 游戏主类 ├── player.py # 玩家类 ├── enemy.py # 敌人类 ├── platform.py # 平台类 ├── powerup.py # 道具类 ├── scene/ │ ├── menu_scene.py # 菜单场景 │ ├── game_scene.py # 游戏场景 │ └── game_over_scene.py ├── assets/ │ ├── images/ │ ├── sounds/ │ └── fonts/ ├── config.py # 配置文件 └── utils.py # 工具函数 按照这个流程,你可以从简单到复杂逐步开发完整的Pygame游戏。记住:先实现核心玩法,再添加特效和优化!