Python游戏开发:Pygame全面指南与实战

第一章 Pygame简介与安装

1.1 Pygame概述

Pygame是一个开源的Python模块,专门用于多媒体应用(如电子游戏)的开发。它基于SDL(Simple DirectMedia Layer)库构建,提供了对图形、声音、输入设备等游戏开发所需功能的访问接口。Pygame最初由Pete Shinners于2000年创建,至今已成为Python游戏开发最流行的库之一。

Pygame的主要特点包括:

  • 简单易用的API设计
  • 跨平台支持(Windows、Mac OS X、Linux等)
  • 无需复杂的环境配置
  • 丰富的功能模块
  • 活跃的社区支持

1.2 Pygame与其他游戏引擎的比较

与其他游戏开发工具相比,Pygame有其独特的优势和不足:

特性 Pygame Unity Unreal Engine Godot
学习曲线 平缓 中等 陡峭 中等
编程语言 Python C# C++ GDScript
2D支持 优秀 良好 一般 优秀
3D支持 有限 优秀 卓越 良好
性能 中等 极高
适合项目规模 小型 大中型 大型 中小型

1.3 安装Pygame

安装Pygame非常简单,可以通过pip直接安装:

bash 复制代码
pip install pygame

验证安装是否成功:

python 复制代码
import pygame
print(pygame.__version__)  # 应输出安装的版本号

1.4 Pygame基础架构

Pygame的核心架构围绕以下几个主要组件构建:

  1. 显示模块:管理窗口和屏幕显示
  2. 事件系统:处理用户输入和系统事件
  3. 图像模块:加载和操作图像
  4. 声音模块:播放音效和音乐
  5. 时间控制:管理游戏帧率和计时
  6. 精灵系统:游戏对象管理

第二章 Pygame基础:第一个游戏窗口

2.1 初始化Pygame

在开始使用Pygame之前,需要先初始化所有模块:

python 复制代码
import pygame

# 初始化所有Pygame模块
pygame.init()

# 设置窗口尺寸
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))

# 设置窗口标题
pygame.display.set_caption("我的第一个Pygame窗口")

# 游戏主循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # 填充背景色(RGB)
    screen.fill((135, 206, 235))  # 天蓝色背景
    
    # 更新显示
    pygame.display.flip()

# 退出Pygame
pygame.quit()

2.2 游戏主循环解析

游戏主循环是Pygame程序的核心,通常包含以下步骤:

  1. 事件处理:检查用户输入和系统事件
  2. 游戏逻辑更新:更新游戏状态
  3. 渲染绘制:绘制当前帧的画面
  4. 帧率控制:控制游戏运行速度

2.3 基本绘图功能

Pygame提供了一系列基本绘图函数:

python 复制代码
# 绘制矩形
pygame.draw.rect(screen, (255, 0, 0), (100, 100, 200, 100))  # 红色矩形

# 绘制圆形
pygame.draw.circle(screen, (0, 255, 0), (400, 300), 50)  # 绿色圆形

# 绘制线条
pygame.draw.line(screen, (0, 0, 255), (50, 50), (750, 550), 5)  # 蓝色线条

# 绘制多边形
pygame.draw.polygon(screen, (255, 255, 0), [(200, 200), (300, 100), (400, 200)])  # 黄色多边形

2.4 完整示例:简单绘图板

python 复制代码
import pygame
import sys

pygame.init()

# 设置窗口
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("简单绘图板")

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# 绘图设置
drawing = False
last_pos = None
color = BLACK
radius = 5

# 游戏主循环
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        
        # 鼠标按下开始绘图
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:  # 左键
                drawing = True
                last_pos = event.pos
            elif event.button == 3:  # 右键
                screen.fill(WHITE)  # 清空画布
        
        # 鼠标移动时绘图
        elif event.type == pygame.MOUSEMOTION:
            if drawing and event.buttons[0]:  # 左键拖动
                if last_pos:
                    pygame.draw.line(screen, color, last_pos, event.pos, radius * 2)
                    last_pos = event.pos
        
        # 鼠标释放停止绘图
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                drawing = False
                last_pos = None
        
        # 键盘控制
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r:
                color = RED
            elif event.key == pygame.K_g:
                color = GREEN
            elif event.key == pygame.K_b:
                color = BLUE
            elif event.key == pygame.K_UP:
                radius = min(50, radius + 1)
            elif event.key == pygame.K_DOWN:
                radius = max(1, radius - 1)
    
    # 显示当前设置
    info_surface = pygame.Surface((200, 100))
    info_surface.fill(WHITE)
    font = pygame.font.SysFont(None, 24)
    color_text = font.render(f"颜色: {color}", True, BLACK)
    radius_text = font.render(f"粗细: {radius}", True, BLACK)
    info_surface.blit(color_text, (10, 10))
    info_surface.blit(radius_text, (10, 40))
    screen.blit(info_surface, (10, 10))
    
    pygame.display.flip()

第三章 Pygame图像处理与动画

3.1 加载和显示图像

Pygame支持多种图像格式,包括PNG、JPG、BMP等:

python 复制代码
# 加载图像
player_img = pygame.image.load("player.png").convert_alpha()

# 显示图像
screen.blit(player_img, (100, 100))

convert()convert_alpha()方法可以优化图像显示性能,后者保留alpha通道(透明度)。

3.2 图像变换

Pygame提供了一些基本的图像变换功能:

python 复制代码
# 缩放图像
scaled_img = pygame.transform.scale(player_img, (50, 50))

# 旋转图像
rotated_img = pygame.transform.rotate(player_img, 45)  # 旋转45度

# 翻转图像
flipped_img = pygame.transform.flip(player_img, True, False)  # 水平翻转

3.3 动画实现原理

游戏动画通常通过快速连续显示一系列略有不同的图像(帧)来实现。在Pygame中,可以通过以下步骤创建动画:

  1. 加载所有动画帧
  2. 在游戏循环中按顺序显示这些帧
  3. 控制帧切换速度

3.4 完整示例:角色动画

python 复制代码
import pygame
import os

pygame.init()

# 设置窗口
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("角色动画演示")

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# 加载动画帧
animation_frames = []
for i in range(1, 7):
    frame = pygame.image.load(f"run_animation/frame_{i}.png").convert_alpha()
    frame = pygame.transform.scale(frame, (100, 100))
    animation_frames.append(frame)

# 动画设置
current_frame = 0
animation_speed = 0.2  # 每秒切换几帧
frame_count = 0

# 角色位置
player_x = 100
player_y = 400
player_speed = 3

# 游戏时钟
clock = pygame.time.Clock()

# 游戏主循环
running = True
while running:
    # 控制帧率
    dt = clock.tick(60) / 1000  # 转换为秒
    
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # 获取按键状态
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player_x -= player_speed
    if keys[pygame.K_RIGHT]:
        player_x += player_speed
    
    # 更新动画帧
    frame_count += animation_speed * dt * 60
    if frame_count >= 1:
        current_frame = (current_frame + 1) % len(animation_frames)
        frame_count = 0
    
    # 绘制
    screen.fill(WHITE)
    screen.blit(animation_frames[current_frame], (player_x, player_y))
    
    # 显示说明文字
    font = pygame.font.SysFont(None, 36)
    text = font.render("使用左右方向键移动角色", True, BLACK)
    screen.blit(text, (50, 50))
    
    pygame.display.flip()

pygame.quit()

第四章 Pygame精灵系统

4.1 Sprite类简介

Pygame的Sprite类是为游戏对象设计的基类,提供了以下功能:

  • 图像管理
  • 位置更新
  • 碰撞检测
  • 分组管理

4.2 创建自定义精灵

python 复制代码
class Player(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill((255, 0, 0))  # 红色方块
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.speed = 5
    
    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT]:
            self.rect.x += self.speed
        if keys[pygame.K_UP]:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN]:
            self.rect.y += self.speed

4.3 精灵组的使用

精灵组(Group)用于管理多个精灵,提供批量更新和绘制功能:

python 复制代码
# 创建精灵组
all_sprites = pygame.sprite.Group()
player = Player(100, 100)
all_sprites.add(player)

# 在游戏循环中
all_sprites.update()  # 更新所有精灵
all_sprites.draw(screen)  # 绘制所有精灵

4.4 碰撞检测

Pygame提供了多种碰撞检测方法:

python 复制代码
# 矩形碰撞检测
if pygame.sprite.collide_rect(sprite1, sprite2):
    print("发生碰撞!")

# 圆形碰撞检测
if pygame.sprite.collide_circle(sprite1, sprite2):
    print("圆形碰撞!")

# 精灵与组碰撞检测
hits = pygame.sprite.spritecollide(player, enemy_group, True)
for enemy in hits:
    player.health -= 10

4.5 完整示例:太空射击游戏

python 复制代码
import pygame
import random
import os

pygame.init()

# 屏幕设置
WIDTH = 480
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("太空射击游戏")

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# 加载图像
def load_image(name, scale=1):
    img = pygame.Surface((50, 40))
    img.fill(BLUE if name == "player" else RED)
    return img

# 玩家精灵
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = load_image("player")
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 10
        self.speed_x = 0
        self.health = 100
    
    def update(self):
        self.speed_x = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speed_x = -8
        if keystate[pygame.K_RIGHT]:
            self.speed_x = 8
        self.rect.x += self.speed_x
        
        # 边界检查
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
        if self.rect.left < 0:
            self.rect.left = 0
    
    def shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.top)
        all_sprites.add(bullet)
        bullets.add(bullet)

# 敌人类
class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = load_image("enemy")
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.speedy = random.randrange(1, 5)
        self.speedx = random.randrange(-2, 2)
    
    def update(self):
        self.rect.y += self.speedy
        self.rect.x += self.speedx
        
        # 边界检查和重生
        if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right > WIDTH + 25:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.speedy = random.randrange(1, 5)

# 子弹类
class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((10, 20))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.bottom = y
        self.speedy = -10
    
    def update(self):
        self.rect.y += self.speedy
        # 如果子弹飞出屏幕顶部,则删除
        if self.rect.bottom < 0:
            self.kill()

# 创建精灵组
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()

# 创建玩家
player = Player()
all_sprites.add(player)

# 创建敌人
for i in range(8):
    enemy = Enemy()
    all_sprites.add(enemy)
    enemies.add(enemy)

# 分数
score = 0
font = pygame.font.SysFont(None, 36)

# 游戏循环
clock = pygame.time.Clock()
running = True
while running:
    # 保持循环以正确的速度运行
    clock.tick(60)
    
    # 处理输入事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.shoot()
    
    # 更新
    all_sprites.update()
    
    # 检查子弹是否击中敌人
    hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
    for hit in hits:
        score += 10
        enemy = Enemy()
        all_sprites.add(enemy)
        enemies.add(enemy)
    
    # 检查敌人是否撞到玩家
    hits = pygame.sprite.spritecollide(player, enemies, False)
    if hits:
        player.health -= 1
        if player.health <= 0:
            running = False
    
    # 渲染
    screen.fill(BLACK)
    all_sprites.draw(screen)
    
    # 显示分数
    score_text = font.render(f"分数: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))
    
    # 显示生命值
    health_text = font.render(f"生命: {player.health}", True, WHITE)
    screen.blit(health_text, (10, 50))
    
    # 刷新屏幕
    pygame.display.flip()

pygame.quit()

第五章 Pygame声音与音乐

5.1 加载和播放音效

python 复制代码
# 加载音效
shoot_sound = pygame.mixer.Sound("shoot.wav")

# 播放音效
shoot_sound.play()

5.2 背景音乐控制

python 复制代码
# 加载背景音乐
pygame.mixer.music.load("background.mp3")

# 播放背景音乐(循环播放)
pygame.mixer.music.play(-1)

# 暂停音乐
pygame.mixer.music.pause()

# 继续播放
pygame.mixer.music.unpause()

# 停止音乐
pygame.mixer.music.stop()

5.3 音量控制

python 复制代码
# 设置主音量(0.0到1.0)
pygame.mixer.music.set_volume(0.5)

# 设置单个音效音量
shoot_sound.set_volume(0.3)

5.4 完整示例:音乐播放器

python 复制代码
import pygame
import os

pygame.init()

# 屏幕设置
WIDTH = 400
HEIGHT = 300
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("简易音乐播放器")

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)

# 字体
font = pygame.font.SysFont(None, 24)

# 音乐列表
music_files = ["song1.mp3", "song2.mp3", "song3.mp3"]
current_song = 0

# 加载第一首歌
pygame.mixer.music.load(music_files[current_song])

# 按钮类
class Button:
    def __init__(self, x, y, width, height, text, color, hover_color):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.is_hovered = False
    
    def draw(self, surface):
        color = self.hover_color if self.is_hovered else self.color
        pygame.draw.rect(surface, color, self.rect)
        pygame.draw.rect(surface, BLACK, self.rect, 2)
        
        text_surf = font.render(self.text, True, BLACK)
        text_rect = text_surf.get_rect(center=self.rect.center)
        surface.blit(text_surf, text_rect)
    
    def check_hover(self, pos):
        self.is_hovered = self.rect.collidepoint(pos)
        return self.is_hovered
    
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and self.is_hovered:
            return True
        return False

# 创建按钮
play_button = Button(50, 200, 80, 40, "播放", GRAY, WHITE)
pause_button = Button(160, 200, 80, 40, "暂停", GRAY, WHITE)
stop_button = Button(270, 200, 80, 40, "停止", GRAY, WHITE)
next_button = Button(270, 150, 80, 40, "下一首", GRAY, WHITE)
prev_button = Button(50, 150, 80, 40, "上一首", GRAY, WHITE)

# 游戏主循环
running = True
clock = pygame.time.Clock()

while running:
    # 事件处理
    mouse_pos = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
        # 检查按钮悬停
        play_button.check_hover(mouse_pos)
        pause_button.check_hover(mouse_pos)
        stop_button.check_hover(mouse_pos)
        next_button.check_hover(mouse_pos)
        prev_button.check_hover(mouse_pos)
        
        # 处理按钮点击
        if play_button.handle_event(event):
            pygame.mixer.music.play()
        
        if pause_button.handle_event(event):
            if pygame.mixer.music.get_busy():
                pygame.mixer.music.pause()
            else:
                pygame.mixer.music.unpause()
        
        if stop_button.handle_event(event):
            pygame.mixer.music.stop()
        
        if next_button.handle_event(event):
            current_song = (current_song + 1) % len(music_files)
            pygame.mixer.music.load(music_files[current_song])
            pygame.mixer.music.play()
        
        if prev_button.handle_event(event):
            current_song = (current_song - 1) % len(music_files)
            pygame.mixer.music.load(music_files[current_song])
            pygame.mixer.music.play()
    
    # 绘制
    screen.fill(WHITE)
    
    # 显示当前歌曲
    song_text = font.render(f"当前播放: {music_files[current_song]}", True, BLACK)
    screen.blit(song_text, (20, 50))
    
    # 显示播放状态
    status = "播放中" if pygame.mixer.music.get_busy() else "已停止"
    status_text = font.render(f"状态: {status}", True, BLACK)
    screen.blit(status_text, (20, 80))
    
    # 绘制按钮
    play_button.draw(screen)
    pause_button.draw(screen)
    stop_button.draw(screen)
    next_button.draw(screen)
    prev_button.draw(screen)
    
    # 更新显示
    pygame.display.flip()
    clock.tick(30)

pygame.quit()

第六章 Pygame高级主题

6.1 使用OpenGL加速

Pygame可以通过pygame.OPENGL标志与OpenGL结合使用:

python 复制代码
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

def init():
    glEnable(GL_DEPTH_TEST)
    glClearColor(0.5, 0.5, 0.5, 1.0)
    gluPerspective(45, (800/600), 0.1, 50.0)
    glTranslatef(0.0, 0.0, -5)

def cube():
    glBegin(GL_QUADS)
    # 前面
    glColor3fv((1, 0, 0))
    glVertex3fv((1, -1, -1))
    glVertex3fv((1, 1, -1))
    glVertex3fv((-1, 1, -1))
    glVertex3fv((-1, -1, -1))
    # 更多面...
    glEnd()

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    
    init()
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return
        
        glRotatef(1, 3, 1, 1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        cube()
        pygame.display.flip()
        pygame.time.wait(10)

if __name__ == "__main__":
    main()

6.2 使用Pygame制作GUI

虽然Pygame不是专门的GUI库,但可以用来创建简单的界面元素:

python 复制代码
class Button:
    def __init__(self, x, y, width, height, text, color, hover_color):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.is_hovered = False
    
    def draw(self, surface):
        color = self.hover_color if self.is_hovered else self.color
        pygame.draw.rect(surface, color, self.rect)
        pygame.draw.rect(surface, (0, 0, 0), self.rect, 2)
        
        font = pygame.font.SysFont(None, 24)
        text_surf = font.render(self.text, True, (0, 0, 0))
        text_rect = text_surf.get_rect(center=self.rect.center)
        surface.blit(text_surf, text_rect)
    
    def check_hover(self, pos):
        self.is_hovered = self.rect.collidepoint(pos)
        return self.is_hovered
    
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and self.is_hovered:
            return True
        return False

6.3 网络游戏开发

Pygame可以与socket模块结合开发简单的网络游戏:

python 复制代码
import socket
import threading
import pygame

class NetworkGame:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((800, 600))
        self.clock = pygame.time.Clock()
        self.running = True
        
        # 网络设置
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_address = ('localhost', 12345)
        
        # 连接服务器
        self.connect_to_server()
    
    def connect_to_server(self):
        try:
            self.socket.connect(self.server_address)
            # 启动接收线程
            receive_thread = threading.Thread(target=self.receive_data)
            receive_thread.daemon = True
            receive_thread.start()
        except Exception as e:
            print(f"连接服务器失败: {e}")
    
    def receive_data(self):
        while self.running:
            try:
                data = self.socket.recv(1024).decode()
                if data:
                    self.handle_network_data(data)
            except Exception as e:
                print(f"接收数据错误: {e}")
                break
    
    def handle_network_data(self, data):
        # 处理接收到的网络数据
        print(f"收到数据: {data}")
    
    def send_data(self, data):
        try:
            self.socket.sendall(data.encode())
        except Exception as e:
            print(f"发送数据失败: {e}")
    
    def run(self):
        while self.running:
            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:
                        self.send_data("player_jump")
            
            # 游戏逻辑和渲染
            self.screen.fill((0, 0, 0))
            pygame.display.flip()
            self.clock.tick(60)
        
        pygame.quit()

if __name__ == "__main__":
    game = NetworkGame()
    game.run()

第七章 Pygame性能优化

7.1 图像优化技巧

  1. 使用convert()convert_alpha()

    python 复制代码
    # 普通图像
    image = pygame.image.load("image.png").convert()
    
    # 带透明度的图像
    image = pygame.image.load("image.png").convert_alpha()
  2. 避免频繁加载图像:在游戏初始化时加载所有需要的图像

  3. 使用精灵表:将多个小图像合并到一个大图像中

7.2 游戏循环优化

  1. 控制帧率

    python 复制代码
    clock = pygame.time.Clock()
    while True:
        clock.tick(60)  # 限制为60FPS
  2. 脏矩形更新:只更新屏幕上发生变化的部分

    python 复制代码
    pygame.display.update(rect_list)  # 只更新指定矩形区域
  3. 分批处理:将相似的绘制操作集中处理

7.3 内存管理

  1. 及时释放资源

    python 复制代码
    def unload_resources(self):
        for image in self.image_cache.values():
            del image
        self.image_cache.clear()
  2. 使用对象池:对频繁创建销毁的对象进行重用

7.4 性能分析工具

  1. Python内置的cProfile

    bash 复制代码
    python -m cProfile -s cumtime your_game.py
  2. Pygame内置的time模块

    python 复制代码
    start_time = pygame.time.get_ticks()
    # 执行代码
    end_time = pygame.time.get_ticks()
    print(f"耗时: {end_time - start_time}毫秒")

第八章 Pygame项目实战:平台游戏

8.1 游戏设计

我们将创建一个简单的平台游戏,包含以下功能:

  • 玩家角色可以左右移动和跳跃
  • 多个平台供玩家站立
  • 收集物品获得分数
  • 敌人会移动并伤害玩家
  • 简单的关卡设计

8.2 游戏架构

python 复制代码
import pygame
import random
import sys

# 初始化
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("平台游戏")
clock = pygame.time.Clock()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
GRAY = (100, 100, 100)

# 玩家类
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((30, 50))
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH // 2, HEIGHT // 2)
        self.velocity_y = 0
        self.velocity_x = 0
        self.jumping = False
        self.health = 100
        self.score = 0
    
    def update(self):
        # 重力
        self.velocity_y += 0.5
        if self.velocity_y > 10:
            self.velocity_y = 10
        
        # 水平移动
        self.rect.x += self.velocity_x
        
        # 检查水平边界
        if self.rect.left < 0:
            self.rect.left = 0
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
        
        # 垂直移动
        self.rect.y += self.velocity_y
        
        # 检查是否落地
        if self.rect.bottom >= HEIGHT - 50:
            self.rect.bottom = HEIGHT - 50
            self.velocity_y = 0
            self.jumping = False
    
    def jump(self):
        if not self.jumping:
            self.velocity_y = -12
            self.jumping = True

# 平台类
class Platform(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height):
        super().__init__()
        self.image = pygame.Surface((width, height))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

# 敌人类
class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((30, 30))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.direction = 1
        self.speed = 2
    
    def update(self):
        self.rect.x += self.speed * self.direction
        # 简单的AI:碰到边缘就回头
        if self.rect.right > WIDTH or self.rect.left < 0:
            self.direction *= -1

# 收集物品类
class Item(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((20, 20))
        self.image.fill((255, 255, 0))  # 黄色
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)

# 创建精灵组
all_sprites = pygame.sprite.Group()
platforms = pygame.sprite.Group()
enemies = pygame.sprite.Group()
items = pygame.sprite.Group()

# 创建玩家
player = Player()
all_sprites.add(player)

# 创建地面
ground = Platform(0, HEIGHT - 50, WIDTH, 50)
all_sprites.add(ground)
platforms.add(ground)

# 创建平台
platform_positions = [
    (100, 400, 200, 20),
    (400, 300, 150, 20),
    (200, 200, 100, 20),
    (500, 150, 200, 20)
]

for pos in platform_positions:
    p = Platform(*pos)
    all_sprites.add(p)
    platforms.add(p)

# 创建敌人
enemy_positions = [(200, 350), (450, 250), (300, 150)]
for pos in enemy_positions:
    e = Enemy(*pos)
    all_sprites.add(e)
    enemies.add(e)

# 创建收集物品
for i in range(10):
    x = random.randint(50, WIDTH - 50)
    y = random.randint(50, HEIGHT - 100)
    item = Item(x, y)
    all_sprites.add(item)
    items.add(item)

# 游戏状态
game_over = False
font = pygame.font.SysFont(None, 36)

# 游戏主循环
while not game_over:
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.jump()
    
    # 获取按键状态
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.velocity_x = -5
    elif keys[pygame.K_RIGHT]:
        player.velocity_x = 5
    else:
        player.velocity_x = 0
    
    # 更新
    all_sprites.update()
    
    # 检查玩家是否站在平台上
    if player.velocity_y > 0:  # 正在下落
        platform_hits = pygame.sprite.spritecollide(player, platforms, False)
        if platform_hits:
            player.rect.bottom = platform_hits[0].rect.top
            player.velocity_y = 0
            player.jumping = False
    
    # 检查与敌人的碰撞
    enemy_hits = pygame.sprite.spritecoll
相关推荐
悠哉悠哉愿意1 小时前
【电赛学习笔记】MaixCAM 的OCR图片文字识别
笔记·python·嵌入式硬件·学习·视觉检测·ocr
nbsaas-boot1 小时前
SQL Server 窗口函数全指南(函数用法与场景)
开发语言·数据库·python·sql·sql server
Catching Star1 小时前
【代码问题】【包安装】MMCV
python
摸鱼仙人~1 小时前
Spring Boot中的this::语法糖详解
windows·spring boot·python
Warren981 小时前
Java Stream流的使用
java·开发语言·windows·spring boot·后端·python·硬件工程
点云SLAM3 小时前
PyTorch中flatten()函数详解以及与view()和 reshape()的对比和实战代码示例
人工智能·pytorch·python·计算机视觉·3d深度学习·张量flatten操作·张量数据结构
爱分享的飘哥3 小时前
第三篇:VAE架构详解与PyTorch实现:从零构建AI的“视觉压缩引擎”
人工智能·pytorch·python·aigc·教程·生成模型·代码实战
进击的铁甲小宝4 小时前
Django-environ 入门教程
后端·python·django·django-environ
落魄实习生4 小时前
UV安装并设置国内源
python·uv
阿克兔4 小时前
建筑兔零基础python自学记录114|正则表达式(1)-18
python