第一章 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的核心架构围绕以下几个主要组件构建:
- 显示模块:管理窗口和屏幕显示
- 事件系统:处理用户输入和系统事件
- 图像模块:加载和操作图像
- 声音模块:播放音效和音乐
- 时间控制:管理游戏帧率和计时
- 精灵系统:游戏对象管理
第二章 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程序的核心,通常包含以下步骤:
- 事件处理:检查用户输入和系统事件
- 游戏逻辑更新:更新游戏状态
- 渲染绘制:绘制当前帧的画面
- 帧率控制:控制游戏运行速度
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中,可以通过以下步骤创建动画:
- 加载所有动画帧
- 在游戏循环中按顺序显示这些帧
- 控制帧切换速度
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 图像优化技巧
-
使用
convert()
和convert_alpha()
:python# 普通图像 image = pygame.image.load("image.png").convert() # 带透明度的图像 image = pygame.image.load("image.png").convert_alpha()
-
避免频繁加载图像:在游戏初始化时加载所有需要的图像
-
使用精灵表:将多个小图像合并到一个大图像中
7.2 游戏循环优化
-
控制帧率:
pythonclock = pygame.time.Clock() while True: clock.tick(60) # 限制为60FPS
-
脏矩形更新:只更新屏幕上发生变化的部分
pythonpygame.display.update(rect_list) # 只更新指定矩形区域
-
分批处理:将相似的绘制操作集中处理
7.3 内存管理
-
及时释放资源:
pythondef unload_resources(self): for image in self.image_cache.values(): del image self.image_cache.clear()
-
使用对象池:对频繁创建销毁的对象进行重用
7.4 性能分析工具
-
Python内置的
cProfile
:bashpython -m cProfile -s cumtime your_game.py
-
Pygame内置的
time
模块:pythonstart_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