如何使Pygame飞行模拟器游戏支持模组(含EXE打包场景)
Pygame飞行模拟器模组化实现方案
一、核心模组加载逻辑
放弃硬编码的路径列表,直接在游戏根目录(打包后为EXE所在目录)创建mods文件夹,所有模组以独立.py文件形式存放。每个模组需定义标准化的钩子函数,供主程序调用:
init_mod():模组初始化逻辑(如打印加载提示、初始化资源)update_mod():每帧更新逻辑(如粒子效果、状态变化)handle_event_mod(event):事件处理逻辑(如按键触发功能)
主程序通过importlib.util动态加载模组,无需提前导入,具体步骤:
- 定位
mods文件夹路径 - 遍历文件夹内所有
.py文件 - 动态加载模块并注册钩子函数
- 在主循环中统一调用所有模组的钩子
二、打包EXE后的适配方案
PyInstaller打包后会将代码放入临时目录,直接读取相对路径会失败,需通过以下方式获取真实运行目录:
import os import sys def get_mods_path(): if getattr(sys, 'frozen', False): # 打包为EXE时,获取EXE所在目录 exe_dir = os.path.dirname(sys.executable) else: # 脚本运行时,获取当前脚本目录 exe_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(exe_dir, 'mods')
启动时自动检查mods文件夹是否存在,不存在则创建,确保用户无需手动操作。
三、完整示例代码
主程序核心代码
import pygame import os import sys import importlib.util pygame.init() screen = pygame.display.set_mode((800, 600)) clock = pygame.time.Clock() # 存储模组钩子函数的列表 mod_inits = [] mod_updates = [] mod_event_handlers = [] def load_mods(): mods_path = get_mods_path() if not os.path.exists(mods_path): os.makedirs(mods_path) print("已创建mods文件夹,请将模组文件放入此处") return for filename in os.listdir(mods_path): if filename.endswith('.py') and filename != '__init__.py': mod_name = filename[:-3] mod_path = os.path.join(mods_path, filename) # 动态加载模组 spec = importlib.util.spec_from_file_location(mod_name, mod_path) if not spec: print(f"加载模组失败:{filename}") continue mod = importlib.util.module_from_spec(spec) try: spec.loader.exec_module(mod) except Exception as e: print(f"加载{filename}出错:{str(e)}") continue # 注册钩子函数 if hasattr(mod, 'init_mod'): mod_inits.append(mod.init_mod) if hasattr(mod, 'update_mod'): mod_updates.append(mod.update_mod) if hasattr(mod, 'handle_event_mod'): mod_event_handlers.append(mod.handle_event_mod) # 初始化所有模组 for init_func in mod_inits: init_func() def get_mods_path(): if getattr(sys, 'frozen', False): exe_dir = os.path.dirname(sys.executable) else: exe_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(exe_dir, 'mods') # 加载模组 load_mods() running = True while running: screen.fill((0, 0, 0)) # 处理事件,传递给所有模组 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False for handler in mod_event_handlers: handler(event) # 执行所有模组的更新逻辑 for update_func in mod_updates: update_func() pygame.display.flip() clock.tick(60) pygame.quit()
示例模组:空中自毁(mods/self_destruct.py)
import pygame def init_mod(): print("自毁模组已加载!按X键触发自毁") def handle_event_mod(event): if event.type == pygame.KEYDOWN and event.key == pygame.K_x: print("BOOM!飞机已自毁") # 此处可添加自毁动画、音效等逻辑
示例模组:烟雾尾迹(mods/smoke_trail.py)
import pygame smoke_particles = [] def init_mod(): print("烟雾尾迹模组已加载") def update_mod(): global smoke_particles # 模拟飞机位置(实际需从主游戏获取真实坐标) plane_pos = (400, 300) # 添加新烟雾粒子 smoke_particles.append((*plane_pos, pygame.time.get_ticks())) # 移除超过1秒的旧粒子 smoke_particles = [p for p in smoke_particles if pygame.time.get_ticks() - p[2] < 1000] # 绘制烟雾 screen = pygame.display.get_surface() for pos_x, pos_y, spawn_time in smoke_particles: alpha = 255 - ((pygame.time.get_ticks() - spawn_time) / 1000) * 255 pygame.draw.circle(screen, (100, 100, 100, int(alpha)), (pos_x, pos_y), 5)
四、打包注意事项
使用PyInstaller打包时:
- 无需将
mods文件夹打包进EXE,保持其为外部目录,方便用户添加/修改模组 - 打包命令示例:
pyinstaller --onefile --windowed your_game.py - 若模组依赖额外资源(如图片、音效),可让模组将资源放在
mods目录下的子文件夹中,自行处理路径逻辑
内容的提问来源于stack exchange,提问作者HyperOverflow
相关产品推荐
相关产品推荐

