PvZ-Portable
笔者在大一时曾经尝试写过 Python 版植物大战僵尸。那时候笔者还在起步阶段,用 Python 和 Pygame 做了一个简单的练习,主要目的是学习 Python 和面向对象编程。那个项目虽然能玩,但在还原度上和功能完成度上存在不少局限。
时隔几年,随着技术栈的深入,在开源社区前人大量代码1 2的基础上,笔者带来了一个强大得多的新项目 —— PvZ-Portable。
这是一个跨平台的社区驱动项目,是对《植物大战僵尸:年度版》(GOTY Edition)的完整源码重实现。与之前的玩具项目不同,PvZ-Portable 的目标是 100% 还原原版游戏体验,同时让它能在现代软件、硬件和各种官方未支持的平台上流畅运行。项目开源开发,用于交流学习跨平台移植技术、引擎现代化以及研究如何将经典游戏逻辑适配到各种不同的软硬件平台上。
| 🌿 原汁原味 | 🎮 可移植/跨平台 | 🛠️ 开源开放 |
|---|---|---|
| 几乎 100% 复刻原版所有特性 | 支持 Linux, Windows, macOS, Switch… | 基于 OpenGL & SDL |
为什么要重写?
原版《植物大战僵尸》虽然经典,但毕竟是十几年前的游戏。原版使用了 DirectX 7 等过时技术,且只提供了 32 位可执行文件,在现代操作系统上运行可能会遇到兼容性问题,而且它从未官方支持过 Linux,也没有适配过 LoongArch 等新兴指令集架构。
在开源社区,已经有前人基于逆向工程得到的文档和社区研究,3重写出了最初的游戏引擎。PvZ-Portable 在此基础上进一步开发,作为一个专注于跨平台移植技术的研究项目,主要实现了:
- 现代化渲染:使用 SDL2 和 OpenGL 替代了古老的 DirectX 74,支持硬件加速,并且终于支持调整窗口大小了!
- 由于游戏分辨率仅有 800x600,在高分辨率屏幕上运行原版时窗口会非常小,只有开启全屏模式才能放大。
- PvZ-Portable 支持任意缩放比例,也支持窗口最大化和全屏。
- 真正、全面跨平台:
- OS: Linux, Windows, macOS
- 32 位和 64 位支持
- ISA: i686, x86_64, aarch64, riscv64, loongarch64, …
- 字节序: 小端和大端均支持,且可移植存档相互兼容
- 主机: Nintendo Switch
- 其他: Haiku OS 等小众系统
- OS: Linux, Windows, macOS
- 音频升级:基于 Headshotnoby 的适配工作,使用 SDL Mixer X 和 libopenmpt,支持 MO3 音乐格式。
- 修复原版 Bug:在保持原汁原味的同时,本项目还可选修复一些原版游戏中存在的逻辑错误(例如有关特殊的魅惑僵尸的某些行为等)。当然,如果你喜欢那些“特性”,也可以选择不开启修复。(默认不启用额外修复,保证体验与原版一致)
- 全平台 Unicode 路径支持:原版游戏在 Windows 上不支持非 ASCII 路径,PvZ-Portable 彻底解决了这个问题,在所有平台上支持 Unicode 路径。
- 现代化实现:使用
std::string取代原版的宽字串,使用std::thread实现进程管理,使用std::filesystem实现文件操作,代码更简洁易懂。
⚠️ 版权与使用说明
重要:本项目仅包含代码引擎,不包含任何游戏素材!
PvZ-Portable 严格遵守版权协议。游戏的 IP(植物大战僵尸)属于 PopCap/EA。
要研究或使用此项目,你必须拥有正版游戏(如果没有,请在 Steam 或 EA 官网 上购买)。你需要从正版游戏中提取以下文件放到 PvZ-Portable 的程序所在目录中:
main.pakproperties/目录
本项目仅提供引擎代码,用于技术学习,不包含上述任何游戏资源文件,任何游戏资源均需要用户自行提供正版游戏文件。
本项目的源代码以 LGPL-3.0-or-later 许可证开源,欢迎学习和贡献。
使用指南
程序下载
你可以从 GitHub Releases 页面 下载预编译的二进制文件,或者从源代码自行编译(见下文)。预案构建二进制仅包含若干主流架构和操作系统搭配,实际支持的平台远远不止这些,如果你需要其他平台的版本,也请自行从源代码编译。预构建二进制均使用 GitHub Actions 编译,主要用于测试,没有进行任何签名。macOS 用户如果不想处理签名问题,推荐自行编译。本项目编译流程较为简单,也推荐其他有条件的用户尽量自行编译。若没有条件自行构建且有对应平台的预构建文件,从 GitHub Releases 下载使用亦可。
再次提醒,本项目需要自行提供正版游戏资源,二进制包和源码仓库中均不包含任何游戏素材。
数据存储
PvZ-Portable 会自动在各操作系统的标准应用数据目录下存储存档和配置:
- Linux:
~/.local/share/io.github.wszqkzqk/PvZPortable/ - Windows:
%APPDATA%\io.github.wszqkzqk\PvZPortable\ - macOS:
~/Library/Application Support/io.github.wszqkzqk/PvZPortable/ - Nintendo Switch:
sdmc:/switch/PvZPortable
你可以手动将原版的用户进度文件复制到上述路径的 userdata 子目录下,以继续你的游戏进度(例如复制 users.dat, user1.dat 等)。但是请注意,由于关卡内进度(例如 game1_13.dat)的保存涉及到内存数据,无法兼容原版。虽然笔者自己实现的存档格式 v4 支持跨平台使用,但很遗憾,原版的存档格式是与 ABI 高度绑定的,不具有可移植性。
构建与测试
作为开源项目,你可以自由地编译它。本项目使用了现代化的 CMake 构建系统。
在构建前首先克隆 Git 仓库:
git clone https://github.com/wszqkzqk/PvZ-Portable.git
cd PvZ-Portable
构建
这部分涉及引擎的编译。
依赖安装
确保安装了 CMake, Ninja, SDL2, OpenGL, libopenmpt 等依赖。这里列出了部分平台的依赖安装命令:
- Arch Linux:
sudo pacman -S --needed base-devel cmake glew libjpeg-turbo libogg libopenmpt libpng libvorbis mpg123 ninja sdl2-compat - Debian/Ubuntu:
sudo apt install cmake ninja-build libogg-dev libglew-dev libjpeg-dev libopenmpt-dev libpng-dev libvorbis-dev libmpg123-dev libsdl2-dev - Windows (MSYS2 UCRT64):
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-glew mingw-w64-ucrt-x86_64-libjpeg-turbo mingw-w64-ucrt-x86_64-libopenmpt mingw-w64-ucrt-x86_64-libogg mingw-w64-ucrt-x86_64-libpng mingw-w64-ucrt-x86_64-libvorbis mingw-w64-ucrt-x86_64-mpg123 mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-SDL2 - macOS (Homebrew):
brew install cmake dylibbundler glew jpeg-turbo libogg libopenmpt libpng libvorbis mpg123 ninja sdl2
基本配置
这里列出的是最基础、不含编译器优化等其他选项的编译步骤。进入项目根目录,执行以下命令:
cmake -G Ninja -B build
性能优化
在实际使用中,推荐使用 Release 模式编译以获得更好的性能:
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release
对于需要调试的用户,可以使用 RelWithDebInfo 模式:
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
构建选项
在配置 CMake 项目时,你可以使用以下选项来启用或禁用特定功能:
| 选项 | 默认值 | 说明 |
|---|---|---|
PVZ_DEBUG |
OFF(如果 CMAKE_BUILD_TYPE 是 Debug 则默认为 ON) |
启用作弊键、调试显示和其他调试功能。 |
LIMBO_PAGE |
ON |
启用隐藏关卡页面(Limbo Page)。 |
DO_FIX_BUGS |
OFF |
应用社区对官方 1.2.0.1073 GOTY 版的“错误”修复。5 不过这些“错误”通常被许多玩家视为“特性”。 |
CONSOLE |
OFF(如果 CMAKE_BUILD_TYPE 是 Debug 则默认为 ON) |
显示控制台窗口(仅限 Windows)。 |
例如,如果需要使用作弊键 -tod 等功能,可以启用 PVZ_DEBUG 选项:
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DPVZ_DEBUG=ON
这样如果在运行时向程序添加 -tod 参数,就可以启用作弊功能。6
编译
cmake --build build
编译完成后,你需要手动将正版游戏的 main.pak 和 properties/ 复制到生成的可执行文件所在目录才能运行。
Arch Linux 打包与环境测试
为了方便在 Arch Linux 环境下进行测试,仓库中提供了 PKGBUILD 脚本;笔者创建这个文件的原因主要是为了研究引擎在不同显示服务器(Wayland vs. X11)下的行为差异。
由于法律原因,我们无法在软件包中分发游戏资源。在打包前,你需要自行提供正版游戏资源:
- 找到你购买的正版游戏安装目录,常见路径包括:
- Steam (Linux/Proton):
~/.steam/steam/steamapps/common/PvZPortable/ - Steam (Windows):
C:\Program Files (x86)\Steam\steamapps\common\PvZPortable\ - PopCap (Windows):
C:\Program Files (x86)\PopCap Games\PvZPortable\或C:\Program Files\PopCap Games\PvZPortable\
- Steam (Linux/Proton):
- 将
main.pak和properties/目录打包为Plants_vs._Zombies_1.2.0.1073_EN.zip。- 确保
main.pak位于 ZIP 文件的根目录,而不是子目录内。例如,可以使用以下命令(假设你在游戏目录下):7z a Plants_vs._Zombies_1.2.0.1073_EN.zip main.pak properties/
- 确保
- 将该 ZIP 文件放置在
archlinux/目录下。
然后执行打包命令:
cd archlinux
makepkg -si
关于 Wayland 的测试
在 Linux 平台上,我们特别关注 SDL2 后端在 Wayland 和 X11 环境下的表现差异(例如全屏下的黑边闪烁问题)。为此,Arch Linux 包中引入了一个特殊的启动脚本,用于自动检测环境并在必要时调整 SDL 视频驱动:
#!/usr/bin/env sh
# Default to Wayland SDL video driver if running in a Wayland session and $SDL_VIDEODRIVER is not set
if [ -n "$WAYLAND_DISPLAY" ] && [ -z "$SDL_VIDEODRIVER" ]; then
export SDL_VIDEODRIVER="wayland,x11"
fi
exec /usr/share/pvz-portable/pvz-portable "$@"
在运行的时候,这个脚本会检查当前是否在 Wayland 会话中运行,如果是且没有设置 SDL_VIDEODRIVER 环境变量,则会将其设置为 wayland,x11,以优先使用 Wayland 后端。在需要测试 Xwayland 的情况下,可以在启动时手动设置 SDL_VIDEODRIVER=x11。
DeepWiki AI 助手
如果你在测试、学习或开发 PvZ-Portable 过程中遇到问题,可以询问项目的 DeepWiki AI 助手。
由于本项目高度精准地实现了原版的游戏逻辑,你也可以通过 DeepWiki AI 助手来查询原版游戏的详细内部机制和规则。
致谢
这个项目站在了巨人的肩膀上。
- 特别感谢 Patoke 和 Headshotnoby 对引擎的跨平台移植的杰出贡献!
- 感谢 SDL 开发团队提供的强大跨平台库!
- 感谢所有为游戏研究做出贡献的社区成员!
- 感谢宝开创造了这个经典游戏,并使用宽松的 PopCap Games Framework License 开放
SexyAppFramework,让开源社区能够更方便地研究这个游戏引擎!
如果你对游戏引擎开发或者跨平台移植感兴趣,欢迎访问项目仓库给个 Star,或者参与贡献!
👉 项目地址: https://github.com/wszqkzqk/PvZ-Portable
备注
-
互联网上存在大量关于植物大战僵尸游戏机制的研究文档,部分基于逆向分析,例如在 植物大战僵尸吧, PVZ Wiki 和 PvZ Tools 等平台上都有丰富详尽的游戏机制细节资料。但笔者从未对游戏进行过任何逆向工程分析。笔者仅通过公开的社区研究资料和实际游戏测试来理解游戏机制,并在此基础上进行重实现。 ↩
-
原版植物大战僵尸使用 DirectX 7 进行渲染,无法跨平台且性能较差。将游戏移植到 OpenGL 的大量工作离不开 Patoke 和 Headshotnoby 的贡献。 ↩
-
目前
DO_FIX_BUGS包含以下修复:- 修复我是僵尸关卡中蹦极僵尸同时命中同一朵向日葵时重复掉落阳光的问题。
- 使魅惑的巨人僵尸攻击敌方僵尸,而非植物。
- 使魅惑的巨人僵尸投掷魅惑小鬼(修正比例、生命值和方向)。
- 使魅惑的巨人僵尸在解谜模式中可以砸碎花瓶。
- 使魅惑的豌豆/机枪头僵尸向前射击而非向后。
- 使魅惑的辣椒/窝瓜僵尸伤害敌方僵尸而非植物。
- 修正魅惑南瓜僵尸追踪和砸碎敌方僵尸的坐标问题。
- 使魅惑的辣椒僵尸正确清除僵王博士的技能(冰球/火球)和梯子。
- 同步舞王僵尸动画(修复“女仆秘籍”)。
- 修复扶梯僵尸手臂恢复的视觉故障。
- 修复僵王博士的攻击(扔车、火球/冰球)和6车道(泳池)关卡的召唤范围覆盖问题。
-
以下为作弊键清单(仅在编译时启用
PVZ_DEBUG且运行参数带-tod时有效,且不少只在特定界面/模式生效):- 标题/主菜单:
- 按键记录“快速进入”目标:
End→ 直接加载禅境花园。M→ 正常进入主菜单。S→ 直接进入生存模式选择页。C→ 直接进入小游戏选择页。P→ 直接进入解谜模式选择页。U→ 直接进入试玩/引导关。I→ 直接进入序章关。R→ 直接进入片尾。T→ 直接加载冒险模式。
- 按键记录“快速进入”目标:
- 选卡界面:
Esc随机选卡。 - 模式选择界面:
u:解锁冒险进度、模式、奖杯记录并加金币(用于开发测试)。c/C:临时解锁小游戏/解谜/生存入口。
- 关卡内快捷键:
- 通用:
l打开关卡跳转对话框<打开选项。8自由种植开关(无需冷却、阳光、位置检测)。7放慢游戏速度。6加快游戏速度。z切换调试文字。?//触发下一波倒计时。0+100 阳光;9+999999 阳光;--100 阳光。$+100*10 金钱并显示钱袋。%切换渲染模式(窗口/3D)。M调整音乐 Burst Override。#生存模式快速推进 5 轮(10面旗帜)。!/+快速过关(随模式做收尾逻辑)。q一键布阵/补波/开罐(随模式变化)。O前三列自动补花盆。B吹散迷雾。t召唤雪橇小队并铺冰道。r从墓碑刷怪。1杀死 (0,0) 处植物并计入被吃。Ctrl + C触发崩溃测试并强制下一波倒计时。
- 僵王博士:
b/u/s/r/h/d分别触发蹦极/召唤/踩踏/扔车/吐球/对僵王造成10000伤害。 - 直接刷僵尸:
b蹦极、o橄榄球、s铁门、L扶梯、y雪人、a旗帜、w读报、F气球、n潜水(泳池)、c路障、m舞王、h铁桶、D矿工、p撑杆、P蹦极杖、R海豚(泳池)、j小丑、g巨人、G红眼巨人、i冰车、C投石。- 植物僵尸相关关卡:
w/t/j/g/s分别刷出坚果/高坚果/辣椒/机枪/倭瓜僵尸。
- 禅境花园:
m加一盆金盏花(随机颜色);+加随机植物;a加完全长大的随机植物。f自动照料当前需要的植物;r重置所有植物计时。s蜗牛唤醒/重置计时;c加巧克力次数。]循环修改手推车中植物的类型。
- 智慧树:
f施肥;g快速生长;b重置阶段计数。0~8设置智慧树高度为0/9/19/29/39/49/98/498/998,并触发生长。
- 通用:
- 片尾字幕:
1~7、q~t、a~g跳转到不同字幕段。n切换字幕与音乐同步。
- 标题/主菜单: