跳到主要内容Pygame 游戏开发流程详解 | 极客日志Python算法
Pygame 游戏开发流程详解
使用 Pygame 库进行游戏开发的完整流程。内容涵盖核心架构(事件处理、逻辑更新、渲染)、基础框架搭建、主循环设计、精灵系统实现、场景管理以及性能优化技巧。通过平台跳跃游戏的完整示例,展示了碰撞检测、状态机管理和粒子系统等关键技术点,并提供了项目结构建议和调试方法,适合初学者构建自己的游戏项目。
ArchDesign5 浏览 Pygame 游戏开发详细流程
一、Pygame 核心架构
游戏主循环 ├── 事件处理 (Event Handling) ├── 游戏逻辑更新 (Game Logic) ├── 渲染绘制 (Rendering) └── 帧率控制 (FPS Control)
二、完整开发流程详解
1. 基础框架搭建
import pygame
import sys
class Game:
def __init__(self):
"""初始化游戏"""
pygame.init()
self.screen_width = 800
self.screen_height = 600
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
pygame.display.set_caption("我的游戏")
self.clock = pygame.time.Clock()
self.FPS = 60
self.running = True
self.game_over = False
self.BLACK = (0, 0, 0)
self.WHITE = (255, 255, 255)
self.RED = (255, 0, 0)
self.GREEN = (0, , )
.BLUE = (, , )
.load_resources()
():
.font_small = pygame.font.SysFont(, )
.font_large = pygame.font.SysFont(, )
:
.player_image = pygame.image.load().convert_alpha()
:
.player_image = pygame.Surface((, ))
.player_image.fill(.BLUE)
:
.jump_sound = pygame.mixer.Sound()
:
.jump_sound =
pygame.mixer.music.load()
pygame.mixer.music.play(-)
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
255
0
self
0
0
255
self
def
load_resources
self
"""加载游戏资源"""
self
None
36
self
None
72
try
self
"player.png"
except
self
50
50
self
self
try
self
"jump.wav"
except
self
None
"bgm.mp3"
1
2. 主游戏循环
def run(self):
"""主游戏循环"""
while self.running:
self.handle_events()
if not self.game_over:
self.update()
self.render()
self.clock.tick(self.FPS)
self.quit()
def handle_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)
class Player(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 = 0
def load_animation_frames(self):
"""加载动画帧"""
for i in range(4):
frame = pygame.Surface((50, 50))
frame.fill((0, 0, 200 + i * 15))
self.frames.append(frame)
def update(self, platforms):
"""更新玩家状态"""
keys = pygame.key.get_pressed()
self.velocity.x = 0
if 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()
def check_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
def check_vertical_collision(self, platforms):
self.on_ground = False
for 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 = True
elif self.velocity.y < 0:
self.rect.top = platform.bottom
self.velocity.y = 0
def update_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 = 0
def check_bounds(self):
"""检查边界"""
if self.rect.top > 600:
self.health = 0
4. 游戏场景管理
class GameScene:
"""游戏场景基类"""
def __init__(self, game):
self.game = game
def handle_events(self):
pass
def update(self):
pass
def render(self):
pass
class MainMenuScene(GameScene):
"""主菜单场景"""
def __init__(self, game):
super().__init__(game)
self.buttons = []
self.create_buttons()
def create_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})
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.game.running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
self.check_button_click(event.pos)
def check_button_click(self, pos):
"""检查按钮点击"""
for button in self.buttons:
if button['rect'].collidepoint(pos):
button['action']()
def start_game(self):
"""切换到游戏场景"""
self.game.current_scene = GamePlayScene(self.game)
def quit_game(self):
self.game.running = False
def render(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
class PlatformGame:
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
def generate_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))
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and self.on_ground:
self.player_vel_y = self.jump_strength
self.on_ground = False
elif event.key == pygame.K_R:
self.__init__()
def update(self):
keys = pygame.key.get_pressed()
player_speed = 5
if 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 = 0
if self.player.right > self.WIDTH:
self.player.right = self.WIDTH
self.on_ground = False
for 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 = True
elif 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 += 3
if enemy.top > self.HEIGHT:
self.enemies.remove(enemy)
for enemy in self.enemies:
if self.player.colliderect(enemy):
self.game_over()
def game_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 = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
waiting = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_R:
self.__init__()
waiting = False
def render(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()
def run(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. 性能优化
screen = pygame.display.set_mode((width, height), pygame.DOUBLEBUF)
image = pygame.image.load("image.png").convert()
image = pygame.image.load("image.png").convert_alpha()
dirty_rects = []
dirty_rects.append(player.rect)
pygame.display.update(dirty_rects)
class ObjectPool:
def __init__(self, create_func, max_size=100):
self.pool = []
self.create_func = create_func
self.max_size = max_size
def get(self):
if self.pool:
return self.pool.pop()
return self.create_func()
def recycle(self, obj):
if len(self.pool) < self.max_size:
self.pool.append(obj)
2. 状态机管理
class StateMachine:
def __init__(self):
self.states = {}
self.current_state = None
def add_state(self, name, state):
self.states[name] = state
def change_state(self, name):
if self.current_state:
self.current_state.exit()
self.current_state = self.states[name]
self.current_state.enter()
def update(self):
if self.current_state:
self.current_state.update()
def render(self):
if self.current_state:
self.current_state.render()
class GameState:
def enter(self):
pass
def exit(self):
pass
def update(self):
pass
def render(self):
pass
3. 粒子系统
class Particle:
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)])
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += 0.1
self.lifetime -= 1
def draw(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)
def draw_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 in enumerate(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 游戏。记住:先实现核心玩法,再添加特效和优化!