在游戏类练手项目里,“宝可梦机甲变身盲盒”是一个特别容易让人产生动手欲望的主题。它把盲盒的随机感、机甲的养成感和宝可梦的收集感组合在一起,可以用来练习面向对象设计、随机算法、数据持久化,甚至可以进一步扩展成一个带页面的小应用。很多朋友一开始只想做一个“随机抽卡”的小脚本,但真正开始写以后才发现,概率怎么配、重复卡怎么处理、变身之后的属性怎么算、存档怎么保存,每一点都需要仔细设计。如果一开始没有想清楚数据模型,后面只会越写越乱。
这篇文章会从一个可运行的控制台版盲盒模拟器入手,逐步拆解数据模型、抽取逻辑、变身逻辑和存档机制,再带大家用 Streamlit 快速做一个网页版原型。读完以后,你不仅能把代码跑起来,还能理解一套“小游戏向项目”的通用设计思路,之后换成自己的角色、机甲和玩法规则也完全没问题。
1. 背景:这个项目到底在做什么
1.1 从玩法到技术
我们先把这个主题拆成三个词:宝可梦、机甲、盲盒。这三个词分别对应了游戏系统里的三件事:
- 宝可梦:玩家要收集的对象,每只宝可梦有自己的属性、攻击、防御、速度等基础数值。
- 机甲:可叠加在宝可梦上的“变身部件”,装备后改变外观,同时提升部分属性。
- 盲盒:随机玩法,玩家每次打开盲盒有概率获得不同稀有度的宝可梦或机甲。
把它们组合起来,就是一个典型的“抽卡 + 状态切换 + 收集养成”系统。技术上需要解决的核心问题有三个:
- 如何按概率从卡池中随机抽取一张卡。
- 如何表达一只宝可梦的普通形态和机甲变身形态,以及变身后的数值变化。
- 如何长期保存玩家的图鉴和抽卡记录。
这三个问题覆盖了随机数、面向对象、数据持久化三个方向,非常适合作为 Python 练手项目。
1.2 适合谁与学习收益
这篇文章适合以下几种读者:
- 刚学完 Python 基础语法,想找一个有完整结构的项目练习的同学。
- 想理解“盲盒/抽卡系统”背后概率逻辑的开发者。
- 想把控制台小项目扩展成网页版,但还不知道怎么分层的初学者。
- 游戏后端、测试或产品同学,想快速理解抽卡机制实现原理。
学完之后,你会掌握:
- 用
dataclass设计游戏数据模型。 - 用
random.choices实现带权重的随机抽取。 - 用“组合”的方式实现机甲变身,而不是生硬地使用继承。
- 用 JSON 保存玩家进度,并做损坏恢复。
- 用 Streamlit 将控制台脚本包装成网页应用。
1.3 项目边界与版权提醒
这里要特别说明:本文中的“宝可梦”“皮卡丘”“喷火龙”“超梦”等名称,只作为教学项目里的概念演示使用,并不是任天堂或宝可梦公司的官方项目。如果要把这个项目做成正式产品、发布到应用市场,或者用于任何商业活动,需要替换成自有原创角色,或者获取正规授权和素材版权。
这一点不是客气话,而是做游戏类项目时最容易忽略的法律风险。
2. 需求分析与功能拆解
2.1 功能清单
为了让项目足够完整,但又不会一次写得太复杂,我给这个模拟器定了这些功能:
| 功能 | 说明 |
|---|---|
| 初始化卡池 | 预置一批宝可梦和机甲数据,每张卡有自己的权重 |
| 随机抽取 | 支持 1 次抽取和 10 连抽,结果严格按照权重产生 |
| 机甲变身 | 抽到带机甲的卡时,实时计算变身形态与属性变化 |
| 图鉴收集 | 记录玩家拥有的宝可梦、数量,以及已获得的机甲形态 |
| 数据存档 | 将图鉴、抽卡次数、抽取记录保存到本地 JSON 文件 |
| 数据恢复 | 启动时自动读取存档,损坏时自动备份并重新开始 |
这个功能集大约在 200 行代码以内可以完成,不会让人觉得“项目太大难以下手”。
2.2 整体交互流程
控制台版的交互流程可以用一个有序列表描述:
- 程序启动,读取本地存档文件
data/save.json。 - 如果存档不存在,则创建一个新的玩家对象。
- 玩家选择抽 1 次或抽 10 次。
- 程序按权重从卡池中随机抽取卡片。
- 每抽到一张卡,程序会判断:
- 这张卡是否自带机甲部件。
- 如果有机甲,就生成一个“变身形态”对象并展示属性变化。
- 将此结果写入玩家图鉴。
- 玩家可以查看图鉴、查看统计、退出。
- 退出前自动保存进度。
2.3 数据模型设计
从数据角度看,这个项目至少需要三个核心对象:
Pokemon:宝可梦本体,包含名称、属性、基础攻击、基础防御、基础速度、稀有度。Mecha:机甲部件,包含名称、攻击加成、防御加成、速度加成、技能描述。MechaPokemon:变身形态,表示“某只宝可梦装备了某个机甲之后的完整形态”。
在卡池设计中,我们把“一张盲盒卡”定义成一个字典结构。它包含三部分:一只宝可梦、一个可选的机甲、一个随机权重。
{ "pokemon": "宝可梦对象", "mecha": "机甲对象或 None", "weight": 30 }这样的设计简单直接,后续无论是增加卡池还是调整概率,都只需要修改数据文件,不需要改动主要逻辑。
3. 环境准备与项目结构
3.1 环境说明
控制台版只需要 Python 3.8 以上版本即可运行,因为它只用到了标准库中的random、json、pathlib、dataclasses。网页版需要额外安装streamlit,安装方式见第 8 章。
版本需要根据你的实际环境调整,本文重点演示实现思路,不建议把某一个具体版本写死在项目里。
3.2 初始化项目
建议新建一个虚拟环境,避免污染本机 Python 环境:
mkdir pokemon-mecha-blindbox cd pokemon-mecha-blindbox python -m venv venvWindows 激活虚拟环境:
venv\Scripts\activatemacOS 或 Linux 激活虚拟环境:
source venv/bin/activate激活后确认 Python 版本:
python --version如果你本机还没有安装 Python,请先去 Python 官网下载并安装。安装时注意勾选“Add Python to PATH”。
3.3 目录结构
整个项目按模块拆分,目录结构如下:
pokemon-mecha-blindbox/ ├── models.py # 数据模型 ├── pokemon_data.py # 卡池数据 ├── blind_box.py # 抽卡逻辑、玩家对象、存档 ├── main.py # 控制台入口 ├── web_app.py # Streamlit 网页版入口 ├── requirements.txt # 网页版依赖 └── data/ └── save.json # 运行时自动生成这样做的好处是 data、logic、presentation 三层分开。数据改动不影响逻辑,逻辑改动不影响入口,入口启动后控制逻辑流转。
4. 核心代码:数据模型
4.1 Pokemon 数据类
我们需要一个Pokemon类来表示宝可梦的基础信息。这里使用dataclass,比手写__init__更简洁,也自带to_dict的辅助能力。
文件路径:models.py
from dataclasses import dataclass, asdict from typing import Optional @dataclass class Pokemon: name: str element: str base_attack: int base_defense: int base_speed: int rarity: str = "R" @property def info(self) -> str: return f"{self.name}({self.element}) 稀有度:{self.rarity}" def to_dict(self) -> dict: return asdict(self) @classmethod def from_dict(cls, data: dict) -> "Pokemon": return cls(**data)这里有几个设计点需要注意:
rarity字段表示稀有度,这里用R、SR、SSR三个等级。info是只读属性,用于展示时拼接字符串,不用每次调用都手写格式。to_dict和from_dict是一对“序列化/反序列化”方法,方便之后保存到 JSON。
4.2 Mecha 数据类
Mecha表示机甲部件。它不包含宝可梦的信息,只描述“机甲本身能提供什么”。
@dataclass class Mecha: name: str atk_bonus: int = 0 def_bonus: int = 0 speed_bonus: int = 0 skill: str = "" @property def info(self) -> str: return ( f"{self.name} [攻击+{self.atk_bonus} " f"防御+{self.def_bonus} 速度+{self.speed_bonus}]" ) def to_dict(self) -> dict: return asdict(self) @classmethod def from_dict(cls, data: dict) -> "Mecha": return cls(**data)机甲和宝可梦是独立对象。这样设计的好处是,同一个机甲部件可以复用到多只宝可梦身上,在后续开发中非常灵活。
4.3 MechaPokemon 变身形态
变身形态是“宝可梦 + 机甲”的组合结果。这里有一个非常重要的设计选择:为什么不用继承,而是用组合?
如果用继承,很可能会写出MechaPikachu(Pokemon)这样的类,每加一种机甲