资讯动态

用Python实现终端电子宠物TAMX:从状态机到JSON持久化的完整实践

发布时间:2026/8/30 17:23:13 来源:尧图企业网站定制
记得第一次在命令行里“养”一只宠物是什么感觉吗不需要华丽的动画也没有复杂的物理引擎只要一组属性、一个时间循环、几条指令就能模拟出一段真实的“陪伴”体验。TAMX 就是这样一个个人电子宠物项目它把经典的 Tamagotchi 玩法搬进终端用纯 Python 标准库实现不依赖任何第三方包。下面我会从项目背景、核心设计、完整代码到常见问题完整拆解 TAMX 的落地过程。它非常适合用来练习状态机设计、命令行交互、时间系统和 JSON 持久化无论你是刚学 Python 的初学者还是想找一个小型项目练手都能从中获得不少启发。1. TAMX 项目背景从经典电子宠物到个人练手项目1.1 什么是 Tamagotchi提到电子宠物很多人脑海里会浮现 1996 年前后流行的拓麻歌子Tamagotchi。它是一个钥匙扣大小的便携设备屏幕上显示一只像素风的小宠物玩家需要定期照顾它喂食、清理、陪它玩耍。如果长时间不照料它会生病甚至“死亡”。这种“一旦开始照顾就必须持续投入”的机制让电子宠物成为一种非常有代表性的互动玩具。从技术角度看Tamagotchi 本质上是一个状态机模型宠物内部存在多个状态属性例如饥饿、快乐、卫生、健康。时间流逝会让这些属性持续变化。玩家的操作会改变属性的变化方向。属性组合决定了宠物当前的状态甚至影响存活结果。这种模型非常适合用编程语言模拟也是 TAMX 项目的核心出发点。1.2 TAMX 解决什么问题TAMX 的定位不是做一个高仿真的商业游戏而是把电子宠物的核心逻辑用最精简的代码实现出来。它解决的问题可以拆成四层状态设计问题如何用一组属性描述一只宠物的生存状态时间系统问题如何让宠物在没有玩家操作时也能“自然流逝”时间交互问题如何设计一组简洁、易扩展的终端指令让玩家照顾宠物持久化问题如何把宠物状态保存到磁盘下次启动时恢复这四层几乎是所有小型游戏和仿真系统都会遇到的基础问题TAMX 用不到 300 行 Python 代码就把它们完整串起来了。1.3 TAMX 的适用场景与读者定位如果你是下面几类开发者这个项目值得跟着做一遍Python 初学者可以通过类和对象练习属性管理、方法设计、构造与序列化。后端开发入门者可以理解时间驱动的服务状态如何更新以及如何做数据持久化。游戏开发爱好者可以掌握基础的状态机与数值平衡思路。想写点小工具的人一个终端版电子宠物本身就是一个有趣的独立小作品。读完全文后你会拥有一套可运行的 TAMX 代码并掌握它背后“为什么这么设计”的思考方法。2. 环境准备与项目结构2.1 运行环境说明TAMX 只需要 Python 3 环境即可运行建议使用 3.8 或更高版本。代码全部使用 Python 标准库包括time、json、os不需要安装任何第三方依赖。本项目的运行场景是一台普通的本地开发电脑Windows、macOS、Linux 都可以。在 Windows 终端使用时建议把代码文件保存为 UTF-8 编码避免中文输出出现乱码。2.2 项目目录结构TAMX 项目结构非常简单核心只有两个 Python 文件tamx/ ├── pet.py # 宠物核心类负责状态计算与动作处理 └── main.py # 命令行交互程序负责读取指令与展示状态如果想以后发布或备份可以额外补充一个README.md记录启动方式和指令说明但运行本身不依赖它。2.3 快速运行在项目目录下执行python main.py如果当前目录已经有存档文件tamx_save.json程序会尝试恢复宠物如果是第一次运行会让你输入一个宠物名字默认叫TAMX。建议在项目目录下新建一个虚拟环境但不是必须的python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate3. TAMX 核心设计属性、状态机与时间系统3.1 五大核心属性TAMX 的宠物状态由五个属性组成每个属性范围都在 0 到 100 之间属性字段名初始值含义饱食度satiety80越高表示越饱过低表示饥饿过高表示过饱快乐度happiness80越高表示心情越好长期过低会影响健康精力值energy80越高表示越精神运动和清醒状态会消耗精力卫生值hygiene80越高表示越干净卫生过低容易生病健康值health100宠物总体健康状况降到 0 则死亡五个属性之间的关系是前四个是“原因属性”健康值是“结果属性”。这意味着健康值不是一个独立增长的数值而是由其他属性共同推导出来的。这样的设计可以避免玩家只盯着健康值一个数值刷药而是需要均衡照顾宠物的饮食、心情、睡眠和卫生。3.2 Tick 时间驱动机制电子宠物需要体现“时间流逝”。TAMX 采用最简单的Tick 机制也就是把时间切成固定单位每个单位执行一次状态更新。在本地演示中我把 1 个 tick 设置为 3 秒TICK_SECONDS 3。每经过一个 tick宠物的饱食度、快乐度、精力值、卫生值都会发生变化。这里有一个值得思考的设计点为什么不直接写一个死循环while True: time.sleep(3)原因是命令行程序的主循环会被input()阻塞。玩家在等待输入时程序无法执行状态更新逻辑。如果强行用多线程处理时间循环会带来线程安全和平台兼容问题对一个小项目来说太重了。TAMX 采用的替代方案是时间差补偿记录宠物上次更新时间last_tick。每次玩家输入命令前计算当前时间与last_tick的差值。根据差值推算出应该补多少个 tick然后一次性执行。这种设计既简单又能保证玩家长时间不操作时宠物仍然会“感受”到时间流逝。3.3 健康值推导规则健康值的变化不是随意设置的我在tick()方法里实现了一套规则条件健康变化饱食度小于 15健康 -3饱食度大于 95健康 -2卫生值小于 10健康 -2快乐度小于 10健康 -1精力值小于 10健康 -1饱食、快乐、精力、卫生都大于等于 50健康 1从这些规则可以看出TAMX 的“危险状态”往往不是单一属性造成的。比如快乐度低短时间内不会致命但如果同时卫生差、饱食度低健康值就会快速下降。而想要恢复健康也不只是吃药而是需要把四个基础属性整体拉回健康区间。这种推导方式让宠物状态变得更有层次感也符合真实养宠物的直觉。3.4 玩家动作指令集为了让玩家能干预宠物状态TAMX 设计了五个主要动作动作收益代价或限制feed喂食饱食度 20快乐度 5饱食度大于等于 90 时强制喂食健康值 -5play玩耍快乐度 15精力 -10饱食 -5卫生 -5精力小于 20 时拒绝wash洗澡卫生值 30无sleep睡觉精力值 30饱食度 -3heal治疗健康值 20无每个动作都有收益也存在限制。比如play虽然能快速提升快乐度但会同时消耗精力和卫生所以“陪玩”不能无限刷必须考虑时间段和宠物当前状态。4. 完整实战实现 TAMX 核心代码4.1 编写宠物核心类 pet.py先看宠物核心类。这个文件包含宠物属性的初始定义、状态推进、玩家动作、存档数据转换等所有核心逻辑。# 文件路径tamx/pet.py TAMX - Personal Tamagotchi 电子宠物核心类 import time # 每个 tick 的间隔秒数本地演示时可以调小真实游戏可以调大 TICK_SECONDS 3 class Pet: TAMX 电子宠物核心类。 五大核心属性 satiety 饱食度范围 0-100初始 80 happiness 快乐度范围 0-100初始 80 energy 精力值范围 0-100初始 80 hygiene 卫生值范围 0-100初始 80 health 健康值范围 0-100初始 100 def __init__(self, nameTAMX): self.name name self.satiety 80 self.happiness 80 self.energy 80 self.hygiene 80 self.health 100 self.age 0 self.alive True self.born_at time.time() self.last_tick time.time() self.events [] # ---------- 状态推进 ---------- def tick(self): 推进一个时间单位更新宠物全部状态。 if not self.alive: return # 基础损耗 self.satiety max(0, self.satiety - 2) self.happiness max(0, self.happiness - 1) self.energy max(0, self.energy - 1) self.hygiene max(0, self.hygiene - 1) self.age 1 # 健康值推导 if self.satiety 15: self.health - 3 self.add_event(饥饿状态健康下降) elif self.satiety 95: self.health - 2 self.add_event(吃得太饱健康下降) if self.hygiene 10: self.health - 2 self.add_event(卫生状况差健康下降) if self.happiness 10: self.health - 1 self.add_event(心情低落健康下降) if self.energy 10: self.health - 1 self.add_event(精力耗尽健康下降) # 状态良好时健康缓慢恢复 if self.satiety 50 and self.happiness 50 and self.energy 50 and self.hygiene 50: self.health min(100, self.health 1) self.health max(0, self.health) if self.health 0: self.alive False self.add_event(TAMX 永远地离开了...) def catch_up(self, max_ticks2000): 根据 last_tick 与当前时间的差值补算离线期间的状态。 为了防止离线过久导致宠物直接死亡默认设置补算上限。 elapsed time.time() - self.last_tick ticks int(elapsed // TICK_SECONDS) ticks min(ticks, max_ticks) for _ in range(ticks): self.tick() if not self.alive: break self.last_tick time.time() # ---------- 玩家动作 ---------- def feed(self): 喂食提升饱食度和少量快乐。 if not self.alive: return 你的 TAMX 已经没有生命迹象了。 if self.satiety 90: self.satiety min(100, self.satiety 8) self.health max(0, self.health - 5) self.add_event(过度喂食) return f{self.name} 已经很饱了再吃会不舒服健康值 -5 self.satiety min(100, self.satiety 20) self.happiness min(100, self.happiness 5) self.add_event(喂食) return f你喂了 {self.name}它开心地吃完了 def play(self): 玩耍提升快乐度但消耗精力和饱食度还会弄脏身体。 if not self.alive: return 你的 TAMX 已经没有生命迹象了。 if self.energy 20: return f{self.name} 现在太累了不想玩先让它睡一觉吧。 self.happiness min(100, self.happiness 15) self.energy max(0, self.energy - 10) self.satiety max(0, self.satiety - 5) self.hygiene max(0, self.hygiene - 5) self.add_event(玩耍) return f你和 {self.name} 玩了一会儿它非常开心 def wash(self): 洗澡大幅提升卫生值。 if not self.alive: return 你的 TAMX 已经没有生命迹象了。 self.hygiene min(100, self.hygiene 30) self.add_event(洗澡) return f你给 {self.name} 洗了个澡它变得干干净净 def sleep(self): 睡觉回复精力但会消耗少量饱食度。 if not self.alive: return 你的 TAMX 已经没有生命迹象了。 self.energy min(100, self.energy 30) self.satiety max(0, self.satiety - 3) self.add_event(睡觉) return f{self.name} 美美地睡了一觉精力恢复了 def heal(self): 治疗直接恢复健康值。 if not self.alive: return 你的 TAMX 已经没有生命迹象了。 self.health min(100, self.health 20) self.add_event(治疗) return f你给 {self.name} 用了药它的气色好多了 # ---------- 辅助方法 ---------- def add_event(self, message): self.events.append(message) if len(self.events) 20: self.events.pop(0) def get_status(self): 返回宠物当前状态字典。 return { name: self.name, age: self.age, satiety: self.satiety, happiness: self.happiness, energy: self.energy, hygiene: self.hygiene, health: self.health, alive: self.alive, born_at: time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(self.born_at)), } # ---------- 数据持久化 ---------- def to_dict(self): 将宠物状态转换为可序列化字典用于存档。 return { name: self.name, satiety: self.satiety, happiness: self.happiness, energy: self.energy, hygiene: self.hygiene, health: self.health, age: self.age, alive: self.alive, born_at: self.born_at, last_tick: time.time(), } classmethod def from_dict(cls, data): 从字典恢复宠物对象。 pet cls(data[name]) pet.satiety data[satiety] pet.happiness data[happiness] pet.energy data[energy] pet.hygiene data[hygiene] pet.health data[health] pet.age data[age] pet.alive data[alive] pet.born_at data[born_at] pet.last_tick data.get(last_tick, time.time()) return pet这段代码里有几个地方需要重点理解。tick()方法是状态推进的核心。宠物每过一个时间单位基础属性会减少然后根据极限状态推导健康值变化。注意max(0, ...)和min(100, ...)的边界处理它保证属性永远不会出现负值或超过 100 的非法值。catch_up()方法解决的是“离线时间补偿”问题。如果玩家两天没打开程序程序会根据时间差自动补算宠物经历了多少个 tick。我设置了max_ticks2000的上限实际在 main 中调用时还会进一步限制以免一次补算太多导致宠物瞬间死亡。动作方法都返回一个字符串方便直接打印给玩家看。这样的设计让宠物类不依赖任何终端展示逻辑后续即使改成 Web 界面也不需要修改核心类。to_dict()保存的是原始时间戳而不是格式化后的时间字符串。因为时间戳更适合计算格式化只用于展示。4.2 编写命令行主程序 main.py主程序要解决三个问题读取指令、展示状态、管理存档。下面是一个完整的实现。# 文件路径tamx/main.py TAMX - Personal Tamagotchi 命令行交互主程序 import os import time import json from pet import Pet SAVE_FILE tamx_save.json def load_pet(): 尝试从存档文件恢复宠物没有存档则新建。 if os.path.exists(SAVE_FILE): try: with open(SAVE_FILE, r, encodingutf-8) as f: data json.load(f) pet Pet.from_dict(data) pet.catch_up(max_ticks2000) print(f存档恢复成功欢迎回来今天是 {pet.name} 的第 {pet.age} 个时间单位。) return pet except Exception as e: print(f存档读取失败{e}) name input(请输入你的宠物名字默认 TAMX).strip() or TAMX return Pet(name) def save_pet(pet): 保存宠物状态到存档文件。 with open(SAVE_FILE, w, encodingutf-8) as f: json.dump(pet.to_dict(), f, ensure_asciiFalse, indent2) def build_status_bar(value, max_value100, width20): 生成一个简单的文本进度条。 filled int(value / max_value * width) filled max(0, min(width, filled)) bar █ * filled ░ * (width - filled) return bar def show_status(pet): 打印宠物状态面板。 print(\n * 50) print(f {pet.name} | 年龄: {pet.age}) print( * 50) status pet.get_status() print(f 饱食度 {build_status_bar(status[satiety])} {status[satiety]:3d}) print(f 快乐度 {build_status_bar(status[happiness])} {status[happiness]:3d}) print(f 精力值 {build_status_bar(status[energy])} {status[energy]:3d}) print(f 卫生值 {build_status_bar(status[hygiene])} {status[hygiene]:3d}) print(f 健康值 {build_status_bar(status[health])} {status[health]:3d}) if pet.events: print(- * 50) print( 最近事件: - .join(pet.events[-3:])) print( * 50) def show_help(): print( 可用指令 feed 喂食 play 玩耍 wash 洗澡 sleep 睡觉 heal 治疗 look 查看状态 save 保存存档 help 显示帮助 quit 退出并保存 ) def main(): print( TAMX: Personal Tamagotchi ) print(你和一只小宠物相遇了好好照顾它吧。) pet load_pet() show_help() show_status(pet) while True: # 每次交互前根据时间差推进宠物状态 pet.catch_up(max_ticks10) if not pet.alive: print(f\n{pet.name} 因为健康值为 0已经永远离开了……) print(游戏结束。你可以删除存档文件重新开始。) break try: cmd input( ).strip().lower().split() except (KeyboardInterrupt, EOFError): print(\n再见) save_pet(pet) break if not cmd: continue action cmd[0] if action quit: save_pet(pet) print(已保存下次再见) break elif action in (help, ?): show_help() elif action look: show_status(pet) elif action save: save_pet(pet) print(存档完成。) elif not pet.alive: print(你的 TAMX 已经没有生命迹象了。) elif action feed: print(pet.feed()) elif action play: print(pet.play()) elif action wash: print(pet.wash()) elif action sleep: print(pet.sleep()) elif action heal: print(pet.heal()) else: print(未知指令输入 help 查看帮助。) show_status(pet) if __name__ __main__: main()

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价