发布于2026-05-26 阅读(0)
扫一扫,手机访问
今天要聊的这个项目,是一个挺有意思的玩意儿——Super Pirate Maker。它本质上是一个用 Python 和 Pygame 打造的横版闯关游戏,但它的特别之处在于,它把“玩”和“造”结合在了一起。玩家不仅能扮演海盗在关卡里冒险,还能摇身一变,用内置的编辑器亲手设计自己的冒险地图。这种“自给自足”的游戏体验,在技术实现上其实有不少门道。
先来看看它的整体骨架。项目采用了非常清晰的模块化设计,每个文件各司其职,这种结构对于学习和维护来说都相当友好:
Python冒险岛游戏/ ├── code/ │ ├── main.py # 游戏主入口 & 状态切换 │ ├── level.py # 关卡逻辑实现 │ ├── editor.py # 关卡编辑器 │ ├── sprites.py # 游戏角色与精灵 │ ├── settings.py # 全局配置常量 │ ├── support.py # 工具函数库 │ ├── menu.py # 编辑器菜单系统 │ └── timer.py # 计时器工具 ├── audio/ # 游戏音效 ├── graphics/ # 游戏资源图片 │ ├── player/ # 玩家角色动画帧 │ ├── enemies/ # 敌人精灵图 │ ├── terrain/ # 地形砖块 │ ├── items/ # 道具(金币、钻石等) │ └── palm/ # 棕榈树装饰 └── font/ # 游戏字体
游戏的所有全局配置都集中在一个地方管理,这种做法能有效避免“魔法数字”满天飞。从窗口大小到动画速度,再到编辑器里能用的所有物件,都一目了然:
# 基础配置
TILE_SIZE = 64
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
ANIMATION_SPEED = 8
# 编辑器图块数据 - 定义了19种游戏对象
EDITOR_DATA = {
0: {'style': 'player', 'type': 'object', ...}, # 玩家出生点
2: {'style': 'terrain', 'type': 'tile', ...}, # 地形砖块
3: {'style': 'water', 'type': 'tile', ...}, # 水面
4-6: {'style': 'coin', ...}, # 金币/银币/钻石
7-10: {'style': 'enemy', ...}, # 敌人(尖刺/牙齿/贝壳)
11-18: {'style': 'palm', ...}, # 棕榈树
}
# 层级系统 - 实现前后景深效果
LEVEL_LAYERS = {
'clouds': 1,
'ocean': 2,
'bg': 3,
'water': 4,
'main': 5
}
这个游戏最核心的设计,莫过于编辑器模式和闯关模式之间的无缝切换。这可不是简单的场景跳转,背后有一套完整的机制在支撑。
主控类负责管理模式的切换状态。默认进入编辑模式,当玩家按下切换键(比如回车)时,会触发一个平滑的过渡:
class Main:
def __init__(self):
self.editor_active = True # 默认进入编辑模式
self.editor = Editor(self.land_tiles, self.switch)
def toggle(self):
"""切换游戏模式"""
self.editor_active = not self.editor_active
if self.editor_active:
self.editor.editor_music.play()
def switch(self, grid=None):
"""创建新关卡并切换"""
self.transition.active = True
if grid:
self.level = Level(grid, self.switch, asset_dict, self.level_sounds)
为了让切换不显得生硬,项目采用了一个圆形缩放的过渡动画。这个动画会逐渐扩大一个黑色圆形遮罩覆盖整个屏幕,然后在切换完成后再收索消失,视觉上非常流畅:
class Transition:
def display(self, dt):
if self.active:
self.border_width += 1000 * dt * self.direction
if self.border_width >= self.threshold:
self.direction = -1
self.toggle() # 切换模式
if self.border_width < 0:
self.active = False
self.direction = 1
# 绘制圆形遮罩
pygame.draw.circle(self.display_surface, 'black',
self.center, self.radius, int(self.border_width))
编辑器是整个项目的亮点,它提供了一个完整的所见即所得的创作环境。你可以像玩沙盒游戏一样,用鼠标点点拖拖,就搭建出一个可玩的关卡。
编辑器的核心是一个字典,用来存储画布上每个网格位置放置了什么对象。同时,它还管理着视角的平移(拖拽地图):
class Editor:
def __init__(self, land_tiles, switch):
self.canvas_data = {} # 画布数据
self.origin = vector() # 视角偏移
self.pan_active = False # 拖拽状态
def get_current_cell(self, obj=None):
"""根据鼠标位置计算当前网格坐标"""
distance_to_origin = vector(mouse_pos()) - self.origin
col = int(distance_to_origin.x / TILE_SIZE)
row = int(distance_to_origin.y / TILE_SIZE)
return col, row
为了让地形看起来更自然,编辑器实现了一个“智能邻居检测”功能。当你放置一块地形砖时,它会自动检查周围八个方向是否有其他地形,然后选择正确的瓦片图片来拼接,让地形的边缘看起来是连贯的,而不是一块块孤立的方块。
def check_neighbors(self, cell_pos):
"""检测8个方向的邻居,自动匹配地形瓦片"""
NEIGHBOR_DIRECTIONS = {
'A': (0,-1), 'B': (1,-1), 'C': (1,0), 'D': (1,1),
'E': (0,1), 'F': (-1,1), 'G': (-1,0), 'H': (-1,-1)
}
for cell in local_cluster:
if cell in self.canvas_data:
for name, side in NEIGHBOR_DIRECTIONS.items():
neighbor_cell = (cell[0] + side[0], cell[1] + side[1])
if neighbor_cell in self.canvas_data:
if self.canvas_data[neighbor_cell].has_terrain:
self.canvas_data[cell].terrain_neighbors.append(name)
编辑器需要加载大量的图片资源。这里用了两个工具函数,一个将文件夹内所有图片导入为列表,另一个则导入为字典(以文件名为键),方便后续按名称调用:
def imports(self):
# 瓦片资源
self.land_tiles = import_folder_dict('../graphics/terrain/land')
# 动画资源
self.animations = {}
for key, value in EDITOR_DATA.items():
if value['graphics']:
graphics = import_folder(value['graphics'])
self.animations[key] = {
'frame index': 0,
'frames': graphics,
'length': len(graphics)
}
进入闯关模式后,游戏世界开始运转。为了高效地进行碰撞检测和渲染,所有游戏对象(精灵)被分到了不同的组里:
class Level:
def __init__(self, grid, switch, asset_dict, audio):
# 精灵分组
self.all_sprites = CameraGroup(0, 2) # 所有精灵
self.coin_sprites = pygame.sprite.Group() # 硬币组
self.shell_sprites = pygame.sprite.Group() # 贝壳敌人组
self.damage_sprites = pygame.sprite.Group() # 可造成伤害的敌人
self.collision_sprites = pygame.sprite.Group() # 碰撞体积组
关卡是如何从编辑器保存的数据“变”出来的呢?答案就在这个构建函数里。它遍历编辑器生成的网格数据字典,根据每个位置上的数字代号,实例化对应的游戏对象:
def build_level(self, grid, asset_dict, jump_sound):
for layer_name, layer in grid.items():
for pos, data in layer.items():
match data:
case 0: # 玩家
self.player = Player(pos, asset_dict['player'], ...)
case 2: # 地形
Generic(pos, asset_dict['land'][data], [...])
case 4: Coin('gold', ...) # 金币
case 7: Spikes(...) # 尖刺陷阱
case 8: Tooth(...) # 牙齿敌人
case 9: Shell(orientation='left', ...)
case 10: Shell(orientation='right', ...)
横版游戏的手感,很大程度上取决于物理和碰撞处理的细腻程度。这里的实现思路很经典:先水平移动并检测碰撞,再处理垂直移动和重力,最后分别解决两个方向上的碰撞:
def move(self, dt):
# 水平移动
self.pos.x += self.direction.x * self.speed * dt
self.hitbox.centerx = round(self.pos.x)
self.collision('horizontal')
# 垂直移动 + 重力
self.direction.y += self.gra vity * dt
self.pos.y += self.direction.y * self.speed * dt
def collision(self, direction):
for sprite in self.collision_sprites:
if sprite.rect.colliderect(self.hitbox):
if direction == 'horizontal':
# 水平碰撞处理
self.hitbox.right = sprite.rect.left if self.direction.x > 0 else self.hitbox.right
else:
# 垂直碰撞处理
self.hitbox.bottom = sprite.rect.top if self.direction.y > 0 else self.hitbox.bottom
玩家的动作和动画不是随便播放的,而是由一个简单的状态机控制。根据垂直速度判断是在跳跃、下落,还是根据水平速度判断是在奔跑或 idle(待机):
class Player(Generic):
def get_status(self):
"""根据运动状态更新动画状态"""
if self.direction.y < 0:
self.status = 'jump' # 上升
elif self.direction.y > 1:
self.status = 'fall' # 下落
else:
self.status = 'run' if self.direction.x != 0 else 'idle'
控制逻辑很直观,就是监听键盘按键,改变角色的移动方向和状态,并在跳跃时播放音效:
def input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.direction.x = 1
self.orientation = 'right'
elif keys[pygame.K_a]:
self.direction.x = -1
self.orientation = 'left'
if keys[pygame.K_w] and self.on_floor: # 跳跃
self.direction.y = -2
self.jump_sound.play()
这个敌人有自己的巡逻 AI。它会一直朝一个方向走,直到撞墙或者走到平台边缘,然后自动掉头:
class Tooth(Generic):
def move(self, dt):
right_gap = self.rect.bottomright + vector(1,1)
right_block = self.rect.midright + vector(1,0)
if self.direction.x > 0: # 向右移动
floor_sprites = [sprite for sprite in self.collision_sprites
if sprite.rect.collidepoint(right_gap)]
wall_sprites = [sprite for sprite in self.collision_sprites
if sprite.rect.collidepoint(right_block)]
if wall_sprites or not floor_sprites:
self.direction.x *= -1
self.orientation = 'left'
贝壳敌人更“高级”一些,它会周期性地打开贝壳,发射珍珠攻击玩家。攻击的时机被巧妙地绑定在动画的特定帧上:
class Shell(Generic):
def animate(self, dt):
if int(self.frame_index) == 2 and self.status == 'attack' and not self.has_shot:
pearl_direction = vector(-1,0) if self.orientation == 'left' else vector(1,0)
Pearl(self.rect.center + offset, pearl_direction,
self.pearl_surf, [self.groups()[0], self.damage_sprites])
self.has_shot = True
为了让玩家始终处于画面中心,游戏实现了一个相机跟随系统。它计算玩家位置与屏幕中心的偏移量,然后在绘制所有精灵时应用这个偏移,营造出镜头跟随的效果。同时,它还按照预设的层级顺序绘制,确保前景、背景关系正确:
class CameraGroup(pygame.sprite.Group):
def custom_draw(self, player):
# 相机跟随玩家
self.offset.x = player.rect.centerx - WINDOW_WIDTH / 2
self.offset.y = player.rect.centery - WINDOW_HEIGHT / 2
# 按层级绘制
for sprite in self:
for layer in LEVEL_LAYERS.values():
if sprite.z == layer:
offset_rect = sprite.rect.copy()
offset_rect.center -= self.offset
self.display_surface.blit(sprite.image, offset_rect)
资源加载是游戏启动的重要一环。下面这两个工具函数非常实用,一个负责加载文件夹内所有图片到列表,另一个则加载到字典(以文件名作为键),后者在需要按名称索引资源时特别方便:
def import_folder(path):
"""导入文件夹中的所有图片"""
surface_list = []
for folder_name, sub_folders, img_files in walk(path):
for image_name in img_files:
full_path = path + '/' + image_name
image_surf = pygame.image.load(full_path).convert_alpha()
surface_list.append(image_surf)
return surface_list
def import_folder_dict(path):
"""导入为字典,键为文件名"""
surface_dict = {}
for folder_name, sub_folders, img_files in walk(path):
for image_name in img_files:
full_path = path + '/' + image_name
surface_dict[image_name.split('.')[0]] = pygame.image.load(full_path).convert_alpha()
return surface_dict
| 操作 | 功能 |
|---|---|
| 鼠标左键 | 放置选中对象 |
| 鼠标右键 | 切换菜单选项 |
| 鼠标中键 | 切换前景/背景 |
| 滚轮 | 缩放/拖拽地图 |
| Enter | 进入闯关模式 |
| ESC | 保存并退出 |
| 按键 | 功能 |
|---|---|
| A/D | 左右移动 |
| W/空格 | 跳跃 |
| ESC | 返回编辑器 |
想自己跑起来看看?步骤非常简单:
# 1. 安装 Python 3.10+ # 2. 安装依赖 pip install pygame # 3. 运行游戏 cd code python main.py



总的来说,Super Pirate Maker 这个项目完整地展示了一个小型游戏从架构设计到功能实现的全过程。它的代码结构清晰,功能模块划分明确,并且实现了一些在游戏开发中非常实用的技巧,比如状态机、智能瓦片拼接和相机系统。无论你是刚入门想了解游戏开发流程的新手,还是希望深入研究 Pygame 某个模块的开发者,这个项目都提供了一个相当不错的范本,值得花时间细细琢磨。
上一篇:ie11怎么开启企业模式
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8