🎮 Walimaker - 专为教学设计的Python游戏引擎
Walimaker 是一个专为教学场景设计的Python游戏引擎模块。它采用简洁直观的API设计,让学生能够快速上手游戏开发,同时掌握编程核心概念。模块基于Pygame和Pymunk构建,提供完整的2D游戏开发功能。
✨ 特性亮点
🎯 教学友好
- 简洁API:基于Python语法糖,类似Processing/turtle的直观接口
- 错误友好:详尽的错误提示和调试信息,帮助初学者快速定位问题
- 渐进学习:从简单绘图到复杂游戏逻辑的平滑过渡
🛠 功能完备
- 🎨 图形渲染:精灵动画、位图渲染、TileMap支持
- ⚙️ 物理系统:刚体动力学、碰撞检测、约束系统(基于Pymunk)
- 🎵 音频管理:背景音乐、音效播放、音量控制
- 📝 UI组件:文本框、对话框、按钮等交互元素
- ⌨️ 输入系统:鼠标、键盘、触控事件处理
- 📊 资源管理:智能LRU缓存,自动内存管理
🚀 开发效率
- 热重载:支持代码热更新,快速迭代开发
- 调试工具:内置调试绘制、性能监控、状态查看
- 模块化设计:可扩展的组件系统,易于定制和扩展
🚀 快速开始
安装
通过pip安装
pip install Walimaker
第一个游戏:移动的角色
from Walimaker import *
# 初始化游戏窗口
setup(800, 600)
title("我的第一个Walimaker游戏")
# 创建角色
character = Character(["idle_1.png", "idle_2.png", "idle_3.png"])
character.scale(2, 2)
# 主游戏循环
while True:
# 事件处理:key_pressed 接收 pygame 的按键常量
# (K_UP / K_a / K_SPACE 等常量随 `from Walimaker import *` 一起提供)
if key_pressed(K_UP):
character.forward(5)
if key_pressed(K_LEFT):
character.left(5)
if key_pressed(K_RIGHT):
character.right(5)
if key_pressed(K_SPACE):
character.say("跳跃!")
# 动画播放
character.play_anim()
# 渲染更新
update()
🧭 中文报错提示(教学特性)
程序出错时,英文原始报错会完整保留(异常类型、消息、完整 traceback),中文解释追加在它的后面, 方便初学者对照着官方报错一起看:
Traceback (most recent call last):
File "main.py", line 12, in <module>
if key_pressed(K_SPACE):
NameError: name 'K_SPACE' is not defined
────────────────────────────────────────────────────────────────
【Walimaker 中文提示】按键/事件常量「K_SPACE」没有导入
原因:pygame 的按键、鼠标、事件常量(K_SPACE、KEYDOWN、QUIT、MOUSEBUTTONDOWN 等)需要先导入才能使用。
解决:① 确认 walimaker 版本 ≥ 2.1.0(pip install -U walimaker),这些常量会随 from Walimaker import *
一起提供;② 或者显式写 from pygame.locals import *。
参考:CHANGELOG 2.1.0「恢复 pygame 事件/按键常量的导出」
────────────────────────────────────────────────────────────────
覆盖的常见错误包括:缺少依赖、变量/函数未定义(按键常量有专项提示)、忘记调用 setup()、
图片/音乐路径找不到、没有声卡、pymunk 坐标类型错误、pymunk 版本兼容问题、key_pressed("w") 传了字符串、
图片类型不支持、setup() 参数不对、Tab 与空格混用、语法/缩进错误、除零、全局变量作用域、递归过深等;
如果报错发生在 Walimaker 自身代码里,会提示"可能是框架问题 + 如何反馈"。
关闭方式(默认开启):
WALIMAKER_ERROR_HELP=0 python main.py # 环境变量
set_error_help(False) # 或在代码里关闭
在 try/except 里主动取中文解释:
try:
character = Character("hero.png")
except Exception as e:
print(explain_exception(e)) # 返回中文解释文本
📁 项目结构
Walimaker/
├── 📄 pyproject.toml # 打包 / 依赖配置
├── 📄 README.md # 项目说明
├── 📄 LICENSE # MIT 许可证
├── 📄 OPTIMIZATION_PLAN.md # 性能 / 结构分析与优化计划
├── 📁 benchmarks/ # 性能基线脚本(不参与打包)
│ └── 🐍 perf_baseline.py
├── 📁 tests/ # 冒烟 / 回归测试(不参与打包)
│ └── 🐍 smoke_test.py
└── 📁 src/
└── 📁 Walimaker/ # 包源码(import Walimaker)
├── 📄 API.py # 主要API接口(Character、窗口管理等)
├── 📄 sprite.py # 精灵和动画系统
├── ⚙️ physics.py # 物理引擎封装(基于Pymunk)
├── 📷 camera.py # 相机系统(缩放、跟随)
├── 🗺️ tiledmap.py # TileMap地图系统
├── 📝 textbox.py # UI文本组件
├── 🎵 music.py # 音频管理系统
├── 📦 resource_manager.py # 资源管理(智能缓存)
├── 🔧 config.py # 全局配置和初始化
├── 🎮 test.py # 示例代码(walimaker-demo 入口)
└── 📁 static/ # 资源文件(只有体积很小的图片)
└── 🖼️ *.png # 图片资源
关于字体:从 2.3.0 起包内不再携带字体文件(原先的楷体/宋体合计 28.6 MB, 使 wheel 接近 16 MB,且属于微软版权字体不允许再分发)。中文显示改为运行时自动解析, 详见下文「🅰️ 中文字体」一节。
开发时可用 pip install -e .(或把 src/ 加入 PYTHONPATH)后 import Walimaker。
📚 核心模块详解
🎨 sprite.py - 精灵与动画系统
- EasySpriteStrategy - 静态精灵策略
- ListSpriteStrategy - 帧动画策略
- AnimatorStrategy - 状态动画策略
- SpriteSheet - 精灵表支持
- 支持:旋转、缩放、翻转、颜色修改
📦 resource_manager.py - 资源管理
智能LRU缓存系统:
from Walimaker.resource_manager import ResourceManager
resource_manager = ResourceManager.get_instance()
# 自动缓存管理
image = resource_manager.load_image("image.png") # 首次加载
cached_image = resource_manager.load_image("image.png") # 从缓存读取
# 缓存统计
info = resource_manager.get_cache_info()
print(f"图片缓存: {info['images']['current_size']}/{info['images']['maxsize']}")
🎮 API.py - 主要接口
提供简洁的面向对象API:
from Walimaker import *
# 创建各种类型的角色
character = Character("image.png") # 静态角色
anim_character = Character(["frame1.png", "frame2.png"]) # 动画角色
state_character = Character({ # 状态机角色
"idle": ["idle_1.png", "idle_2.png"],
"walk": ["walk_1.png", "walk_2.png", "walk_3.png"]
})
🧭 API文档
📋 概述
Walimaker采用笛卡尔坐标系(像素单位),提供完整的游戏开发功能。坐标原点位于窗口左上角,角度系统:0°指向右侧,逆时针方向角度增加。
🖼️ 窗口设置模块
| 函数名 | 功能描述 | 参数说明 | 返回值 | 备注 |
|---|---|---|---|---|
setup(width, height) |
创建指定尺寸的窗口 | width: 宽度height: 高度 |
- | 窗口在屏幕中心生成 |
update() |
刷新画面显示 | - | - | 将修改内容更新到窗口 |
title(text) |
设置窗口标题 | text: 标题文本 |
- | - |
bgpic(image_path) |
设置背景图片 | image_path: 图片路径 |
- | 图片小于窗口时显示黑色背景 |
bgmusic(music_path) |
播放背景音乐 | music_path: 音乐路径 |
- | 循环播放模式 |
set_volume(level) |
设置音量 | level: 0-1浮点数 |
- | 全局音量控制 |
tracer(enable) |
自动刷新控制 | enable: 布尔值 |
- | 防止主线程卡顿 |
save_screen(path) |
截图保存 | path: 保存路径 |
- | 保存当前窗口画面 |
set_mouse_visible(visible) |
鼠标显示控制 | visible: 布尔值 |
- | 显示/隐藏鼠标光标 |
Character 角色类
构造方法
| 方式 | 描述 | 参数 | 返回值 |
|---|---|---|---|
| 单图模式 | 创建静态角色 | image_path: 图片路径 |
Character对象 |
| 动画序列 | 创建帧动画角色 | image_list: 图片路径列表 |
Character对象 |
| 状态动画 | 创建多状态角色 | anim_dict: {状态名: 图片列表} |
Character对象 |
核心属性
| 属性 | 类型 | 描述 | 权限 |
|---|---|---|---|
x, y |
float |
角色坐标位置 | 读写 |
pos |
tuple |
坐标元组 (x, y) | 读写 |
rot |
float |
旋转角度 (0°=右侧,逆时针) | 读写 |
dir |
vec |
方向向量 | 读写 |
red, green, blue, alpha |
int |
颜色通道值 (0-255) | 读写 |
color |
tuple |
颜色元组 (r, g, b, a) | 读写 |
visible |
bool |
可见性状态 | 只读 |
width, height |
int |
图片尺寸 | 只读 |
frame |
int |
当前动画帧索引 | 读写 |
state |
str |
当前动画状态名 | 读写 |
dt |
float |
动画帧间隔时间 | 读写 |
layer |
int |
渲染层级 (0=底层) | 读写 |
动作方法
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
forward(distance) |
向前移动 | distance: 像素距离 |
- |
backward(distance) |
向后移动 | distance: 像素距离 |
- |
left(angle) |
左转 | angle: 旋转角度 |
- |
right(angle) |
右转 | angle: 旋转角度 |
- |
goto(x, y) |
瞬移到坐标 | x, y: 目标坐标 |
- |
slide_to(pos, velocity) |
滑动移动 | pos: 目标位置velocity: 速度 |
- |
scale(width, height) |
缩放尺寸 | width, height: 缩放倍数 |
- |
flipx(enable) |
水平翻转 | enable: 布尔值 |
- |
flipy(enable) |
垂直翻转 | enable: 布尔值 |
- |
show() / hide() |
显示/隐藏角色 | - | - |
交互方法
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
play_snd(sound_path, volume) |
播放音效 | sound_path: 音效路径volume: 音量(0-1) |
- |
collide(target) |
碰撞检测 | target: 角色或坐标 |
bool |
separate(target) |
分离检测 | target: 角色或坐标 |
bool |
distance(target) |
距离计算 | target: 角色或坐标 |
float |
say(text) |
显示对话气泡 | text: 对话内容 |
- |
动画控制
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
play_anim() |
开始播放动画 | - | - |
stop_anim() |
停止播放动画 | - | - |
set_dt(state, interval) |
设置帧间隔 | state: 状态名interval: 间隔时间 |
- |
set_next_state(from_state, to_state) |
设置状态切换 | from_state: 当前状态to_state: 下一状态 |
- |
set_start_func(state, func) |
设置开始回调 | state: 状态名func: 回调函数 |
- |
set_end_func(state, func) |
设置结束回调 | state: 状态名func: 回调函数 |
- |
鼠标交互
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
get_mouse_clicked() |
鼠标点击检测 | - | bool |
get_mouse_just_clicked() |
鼠标点击瞬间检测 | - | bool |
get_mouse_just_released() |
鼠标释放瞬间检测 | - | bool |
get_mouse_upon() |
鼠标悬停检测 | - | bool |
kill() |
销毁角色对象 | - | - |
TextBox 文本框类
构造函数
TextBox(font_size, font=None, bg_color=默认值, font_color=默认值)
font=None 表示自动选择字体(包内 static/ → 系统中文字体 → pygame 默认字体);
也可以直接给字体路径,例如 TextBox(25, font=r"C:\Windows\Fonts\simhei.ttf")。
属性
| 属性 | 类型 | 描述 | 权限 |
|---|---|---|---|
pos |
tuple |
文本框位置坐标 | 读写 |
color |
tuple |
文本颜色 (r, g, b) | 读写 |
方法
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
print(content) |
显示文本内容 | content: 文本字符串 |
- |
goto(x, y) |
移动文本框 | x, y: 目标坐标 |
- |
事件处理函数
鼠标事件
| 函数 | 功能 | 参数 | 返回值 |
|---|---|---|---|
get_mouse_pos() |
获取鼠标坐标 | - | tuple (x, y) |
get_mouse_rel() |
获取鼠标移动向量 | - | tuple (dx, dy) |
get_mouse_clicked() |
检测鼠标按下状态 | - | bool |
get_mouse_just_clicked() |
检测鼠标按下瞬间 | - | bool |
get_mouse_just_released() |
检测鼠标释放瞬间 | - | bool |
键盘事件
| 函数 | 功能 | 参数 | 返回值 |
|---|---|---|---|
key_pressed(key) |
检测按键按下状态 | key: 按键常量(可选) |
bool |
key_just_pressed(key) |
检测按键按下瞬间 | key: 按键常量(可选) |
bool |
key_just_released(key) |
检测按键释放瞬间 | key: 按键常量(可选) |
bool |
key_input() |
获取按键输入字符 | - | str |
🚦 高级用法
状态机与动画控制
from Walimaker import *
character = Character({
"idle": ["idle_1.png", "idle_2.png"],
"walk": ["walk_1.png", "walk_2.png", "walk_3.png"],
"jump": ["jump_1.png", "jump_2.png"]
})
# 设置动画参数
character.set_dt("walk", 0.1) # 走路动画每帧0.1秒
character.set_next_state("walk", "idle") # 走路结束后回到空闲状态
# 状态切换回调
def on_jump_start():
print("开始跳跃!")
def on_jump_end():
print("跳跃结束!")
character.state = "idle"
character.set_start_func("jump", on_jump_start)
character.set_end_func("jump", on_jump_end)
# 切换状态
character.state = "walk" # 开始走路
character.state = "jump" # 开始跳跃(触发回调)
资源管理
from Walimaker.config import global_var
# 预加载资源
assets = {
"images": ["player.png", "enemy.png", "background.png"],
"fonts": [(None, 24), (None, 36)], # None = 自动选择中文字体
"sounds": ["jump.wav", "collect.wav"]
}
global_var.RESOURCE_MANAGER.preload(assets)
# 查看缓存状态
cache_info = global_var.RESOURCE_MANAGER.get_cache_info()
print(f"已缓存图片: {cache_info['images']['current_size']}张")
print(f"已缓存字体: {cache_info['fonts']['current_size']}种")
# 清理缓存
global_var.RESOURCE_MANAGER.clear_cache("image") # 仅清理图片缓存
🅰️ 中文字体
从 2.3.0 起包内不再携带字体文件(原先的 simkai.ttf + simsun.ttc 合计 28.6 MB,
使 wheel 接近 16 MB,且属于微软授权字体不允许再分发)。TextBox / DialogBox
的字体改为运行时按顺序解析:
| 顺序 | 来源 | 说明 |
|---|---|---|
| 1 | 显式传入路径 | TextBox(25, font=r"C:\Windows\Fonts\simhei.ttf") |
| 2 | 环境变量 WALIMAKER_FONT |
机房统一字体:set WALIMAKER_FONT=D:\fonts\SourceHanSansSC.otf |
| 3 | 包内 Walimaker/static/ |
把任意 ttf/ttc/otf 丢进去即可,无需改代码 |
| 4 | 操作系统中文字体 | Windows 微软雅黑/黑体/宋体;macOS 苹方/冬青黑体;Linux Noto CJK/文泉驿 |
| 5 | pygame 默认字体 | 任何平台都存在,但不含中文字形(中文显示成方框) |
-
找不到字体不会报错:只发出一次中文 + 英文的
RuntimeWarning,程序继续运行; 仅当“显式指定的字体文件确实存在但已损坏”时才抛出错误。 -
排查中文显示成方框:
from Walimaker.fonts import font_info print(font_info()) # {'path': '/System/Library/Fonts/Hiragino Sans GB.ttc', 'source': 'system', # 'source_label': '操作系统中文字体', 'has_cjk': True}
若
has_cjk为False,说明系统里没有中文字体(常见于精简 Linux / Docker 镜像), 安装fonts-noto-cjk(Debian/Ubuntu:apt install fonts-noto-cjk)或设置WALIMAKER_FONT指向一个中文字体文件即可。只跑逻辑、不显示画面 (SDL_VIDEODRIVER=dummy)的场景不受影响。
📊 性能优化建议
最佳实践
- 资源复用:尽量复用Character对象,避免频繁创建销毁
- 动画优化:使用精灵表和状态机,减少Draw Call
- 物理优化:将静态物体设为STATIC类型,减少物理计算
- 内存管理:使用resource_manager的预加载功能
- 批处理:相似的对象尽量使用相同的材质和大小
常见性能问题
-
问题: 游戏卡顿,FPS下降
-
检查: 使用
debug()模式查看物理调试绘制 -
解决: 减少同时活动的物理对象数量
-
问题: 内存占用过高
-
检查: 查看resource_manager缓存状态
-
解决: 调整缓存大小或手动清理缓存
🧪 测试示例
查看 Walimaker/test.py 获取更多完整的游戏示例:
- 平台跳跃游戏
- 弹球物理模拟
- TileMap使用示例
- UI交互演示
🤝 贡献指南
欢迎贡献代码!请遵循以下步骤:
- Fork项目
- 创建功能分支 (
git checkout -b feature/AmazingFeature) - 提交修改 (
git commit -m 'Add some AmazingFeature') - 推送分支 (
git push origin feature/AmazingFeature) - 开启Pull Request
代码规范
- 遵循 PEP 8 编码规范
- 使用 类型注解 (Python 3.7+)
- 注释:重要功能和复杂逻辑需要注释
- 测试:新增功能需包含测试用例
📄 许可证
本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。
📞 支持与反馈
- 文档问题 / Bug 报告:附上重现步骤、错误日志与运行环境(Python、pygame、pymunk 版本)
- 功能建议:欢迎直接反馈
- 版本与更新日志:见 PyPI 项目页 与仓库根目录的
CHANGELOG.md
🙏 致谢
感谢以下开源项目:
🚀 下一步计划
- WebAssembly支持(让Walimaker在浏览器中运行)
- 3D渲染扩展(基于OpenGL)
- 网络多人游戏支持
- 可视化编辑器开发
- 更多教学资源和示例
🧭 坐标系说明
- 坐标系统:笛卡尔坐标系,原点位于窗口左上角
- 角度系统:0°指向右侧,逆时针方向角度增加
- 颜色值范围:RGB通道 0-255,透明度 0-255
- 音量控制:0.0(静音)到 1.0(最大音量)
- 物理单位:像素为单位,重力默认 900 像素/秒²
教学提示:Walimaker的设计目标是让编程初学者能够在30分钟内制作出第一个可玩的游戏。从简单到复杂,循序渐进地学习游戏开发的核心概念。
Metadata
Release files for walimaker 2.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| walimaker-2.3.0.tar.gz | 205.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| walimaker-2.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 401.2 kB
Release files / walimaker-2.3.0.tar.gz
| Download URL | walimaker-2.3.0.tar.gz |
|---|---|
| Size | 205.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
daa97de5a67928ad489eb2634bd1f280c7c5cbaeff6af02391da404b5e124506
|
|
BLAKE2b-256 checksum How to use checksums |
2dbdbdd7026d17451b99dc213dae0220b65ebf86e65c8390d62a11ff75635057
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / walimaker-2.3.0-py3-none-any.whl
| Download URL | walimaker-2.3.0-py3-none-any.whl |
|---|---|
| Size | 196.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
47e6c440edf18a3be25d39519487afb6b5659f2e9623f2bb92b2881aba7469f4
|
|
BLAKE2b-256 checksum How to use checksums |
1e43815d99c01b863615d8fdb4c76c8c4bd85b646aa99348707d0ba47a00758f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|