基于 Pygame 的水果忍者小游戏实现教程
一、项目简介
水果忍者是一款经典的休闲动作游戏,玩家需要通过鼠标或触摸屏幕切割飞出的水果,同时避免切到炸弹。本项目旨在使用 Python 的 Pygame 库从零开始构建一个简化版的水果忍者游戏。通过该项目,读者可以深入理解游戏开发中的核心概念,包括窗口管理、事件循环、碰撞检测、物理模拟以及游戏状态控制。
使用 Python 和 Pygame 库开发水果忍者小游戏的完整教程。内容涵盖环境搭建、窗口初始化、游戏对象管理、UI 绘制、主循环逻辑及碰撞检测机制。文章详细解释了物理模拟、事件处理和状态控制的实现方法,并对性能优化和扩展功能提出了建议,适合希望进行图形化编程实战的学习者参考。

水果忍者是一款经典的休闲动作游戏,玩家需要通过鼠标或触摸屏幕切割飞出的水果,同时避免切到炸弹。本项目旨在使用 Python 的 Pygame 库从零开始构建一个简化版的水果忍者游戏。通过该项目,读者可以深入理解游戏开发中的核心概念,包括窗口管理、事件循环、碰撞检测、物理模拟以及游戏状态控制。
本教程适合有一定 Python 基础,希望进行图形化编程实战的学习者。项目将涵盖从环境搭建到主逻辑实现的完整流程。
确保已安装 Python 3.x 版本,并通过 pip 安装 Pygame 库:
pip install pygame
为了保持代码整洁,建议建立如下目录结构:
main.py:游戏主程序入口images/:存放所有图片素材(如背景图、水果图片、炸弹图片、爆炸特效等)comic.ttf:游戏字体文件(可选,若无则使用默认字体)项目中需要以下关键图片资源:
background.jpg:游戏背景图apple.png, orange.png 等:不同种类的水果图片bomb.png:炸弹图片half_apple.png 等:被切开后的水果残片图片red_lives.png:生命值图标explosion.png:爆炸效果图片游戏的第一步是创建显示窗口并配置基本参数。Pygame 提供了丰富的接口来处理图形渲染。
import pygame
import sys
import os
import random
# 游戏窗口配置
WIDTH = 800
HEIGHT = 500
FPS = 60 # 帧率,每秒刷新次数
pygame.init()
pygame.display.set_caption('水果忍者')
gameDisplay = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# 颜色定义 (RGB)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 加载背景图片
try:
background = pygame.image.load('images/background.jpg')
except FileNotFoundError:
gameDisplay.fill(WHITE) # 若图片缺失则填充白色
# 字体设置
font_name = pygame.font.match_font('arial') # 尝试匹配系统字体
font = pygame.font.Font(font_name, 42)
关键点解析:
pygame.init():初始化所有导入的 Pygame 模块。set_mode:设置窗口大小和模式,返回 Surface 对象用于后续绘制。Clock:用于控制游戏循环的帧率,防止程序运行过快导致 CPU 占用过高。我们需要定义数据结构来存储游戏中各个元素的状态,例如水果的位置、速度、是否被击中等信息。
# 全局变量初始化
score = 0
player_lives = 3
data = {} # 存储所有水果对象的数据
game_over = False
first_round = True
fruits = ['apple', 'orange', 'banana'] # 可切割的水果列表
def generate_random_fruits(fruit_type):
"""
生成随机位置的水果对象
:param fruit_type: 水果类型名称
"""
fruit_path = f"images/{fruit_type}.png"
# 检查图片是否存在,不存在则跳过
if not os.path.exists(fruit_path):
return
data[fruit_type] = {
'img': pygame.image.load(fruit_path),
'x': random.randint(100, WIDTH - 100),
'y': HEIGHT + 50,
'speed_x': random.randint(-5, 5),
'speed_y': random.randint(-10, -5),
'throw': False,
't': 0, # 时间计数器,用于模拟重力
'hit': False, # 是否已被切割
'type': fruit_type
}
# 75% 概率抛出水果
if random.random() >= 0.25:
data[fruit_type]['throw'] = True
else:
data[fruit_type]['throw'] = False
# 初始化所有水果对象
for fruit in fruits:
generate_random_fruits(fruit)
逻辑说明:
data 字典采用键值对形式,key 为水果类型,value 为包含坐标、速度、图像引用的字典。speed_y 设为负值表示向上运动,配合 t 变量模拟抛物线轨迹。throw 标志位控制该水果是否参与当前帧的运动更新。为了提升用户体验,需要绘制分数、生命值和游戏结束提示。
def draw_text(display, text, size, x, y, color=WHITE):
"""
在指定位置绘制文字
"""
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
display.blit(text_surface, text_rect)
def draw_lives(display, x, y, lives, image_path):
"""
绘制玩家剩余生命值图标
"""
for i in range(lives):
try:
img = pygame.image.load(image_path)
img_rect = img.get_rect()
img_rect.x = int(x + 35 * i)
img_rect.y = y
display.blit(img, img_rect)
except FileNotFoundError:
pass
def hide_cross_lives(x, y):
"""
隐藏特定位置的生命值图标(用于减少生命值时的视觉效果)
"""
try:
gameDisplay.blit(pygame.image.load("images/red_lives.png"), (x, y))
except FileNotFoundError:
pass
def show_gameover_screen():
"""
显示游戏结束画面
"""
global score
gameDisplay.blit(background, (0, 0))
draw_text(gameDisplay, "GAME OVER", 90, WIDTH / 2, HEIGHT / 4, RED)
draw_text(gameDisplay, f"Score : {score}", 50, WIDTH / 2, HEIGHT / 2, WHITE)
draw_text(gameDisplay, "Press a key to restart!", 32, WIDTH / 2, HEIGHT * 3 / 4, WHITE)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
waiting = False
这是游戏的核心部分,负责处理输入事件、更新游戏状态和渲染画面。
while True:
# 1. 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# 获取鼠标点击位置
mouse_pos = pygame.mouse.get_pos()
# 遍历所有水果进行碰撞检测
for key, value in list(data.items()):
if value['throw'] and not value['hit']:
rect = value['img'].get_rect(topleft=(value['x'], value['y']))
# 简单的矩形碰撞检测
if rect.collidepoint(mouse_pos):
handle_hit(key, value, mouse_pos)
# 2. 游戏状态重置
if game_over:
if first_round:
show_gameover_screen()
first_round = False
game_over = False
player_lives = 3
score = 0
data.clear()
for fruit in fruits:
generate_random_fruits(fruit)
# 3. 清空屏幕
gameDisplay.blit(background, (0, 0))
# 4. 更新与绘制水果
for key, value in data.items():
if value['throw']:
# 物理模拟:重力加速度
value['speed_y'] += 0.5
value['x'] += value['speed_x']
value['y'] += value['speed_y']
value['t'] += 1
# 边界检查:超出屏幕底部则重新生成
if value['y'] > HEIGHT + 50:
value['throw'] = False
generate_random_fruits(key)
else:
gameDisplay.blit(value['img'], (value['x'], value['y']))
# 5. 绘制 UI
score_text = font.render(f'Score : {score}', True, WHITE)
gameDisplay.blit(score_text, (10, 10))
draw_lives(gameDisplay, WIDTH - 150, 10, player_lives, 'images/red_lives.png')
# 6. 游戏结束判断
if player_lives <= 0:
game_over = True
pygame.display.update()
clock.tick(FPS)
辅助函数补充:
为了完善上述主循环,需要补充 handle_hit 函数来处理切割逻辑:
def handle_hit(fruit_key, fruit_data, pos):
global score, player_lives
if fruit_key == 'bomb':
player_lives -= 1
# 播放爆炸音效(如有)
else:
score += 1
# 切换为半切图片
half_path = f"images/half_{fruit_key}.png"
if os.path.exists(half_path):
fruit_data['img'] = pygame.image.load(half_path)
fruit_data['hit'] = True
完成基础功能后,可以从以下几个方面进一步优化游戏体验:
pygame.mixer 模块实现。本文详细介绍了使用 Python 和 Pygame 开发水果忍者小游戏的完整过程。从窗口初始化、资源加载到核心的游戏循环与碰撞检测,涵盖了 2D 游戏开发的基础知识。通过阅读和修改本项目的代码,学习者可以掌握事件驱动编程的基本模式,并为后续开发更复杂的游戏打下坚实基础。
建议在本地环境中实际运行代码,并根据自身需求调整参数(如速度、分数权重等),以加深理解。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online