阿斯特里昂 发布的文章

制作目的

为情侣提供一款休闲、温馨的陪伴型小游戏。玩家无法直接操控主角,而是通过调整参数、布置家园和回应愿望,见证一对恋人在小岛上的生活与成长。在慢节奏的日常中,感受爱情的经营、磨合与真谛,同时打发时间,增进彼此感情。

游戏概述

游戏围绕一男一女两位主角展开,他们共同生活在一座远离尘嚣的小岛上。这座岛是他们的爱巢,玩家可以在此盖房子、兴建设施、改变陈设,亲手塑造一个独一无二的家。

主角的行为由自身性格、愿望、当前环境以及对方状态共同决定,并通过大语言模型实时演绎。玩家的角色是“神明”——你可以调节主角的“爱的维度”、布置岛屿、购买物品赠予他们,并在他们达成目标后响应其祈愿。

在漫长的时光中,无数的愿望诞生、实现或落空,编织成两个人共同的生活与爱情。这些点滴故事,正是我们游玩的目的。

游玩平台

  1. 后端:使用Python编写,稳定运行在服务器上。
  2. 前端:使用网页的形式,语言不限,手机和电脑上都可游玩。

系统说明

  1. API接口
    两位主角的所有行动与对话均由大语言模型实时驱动。玩家需在游戏界面中填写并接入自己的大模型 API 接口(如 OpenAI、Claude 等),游戏会将主角状态、环境信息等组合成 prompt 发送给模型,并解析返回的行为指令。
  2. 存档
    服务端会将当前游戏进程以文本的形式进行存档,重开时会继续之前的存档

    游戏背景

  3. 小岛
    这是一座心形轮廓的南太平洋热带小岛,面积约 3 平方公里,气候温和,四季如春。岛上原本荒无人烟,唯有一间破旧的小木屋、一座简易栈桥和一片野生椰林。随着主角建设,可解锁的区域会逐步扩大。
    初始区域:海滩(商船停靠处)、木屋、一小片可开垦的草地。
    可解锁区域:山丘(可建瞭望台)、淡水湖泊、密林、花海、温泉等。

小岛拥有独立的生态系统:潮汐涨落、海风拂面,夜晚有萤火虫与星空。这是一片只属于两人的秘境,也是他们爱情故事的唯一舞台。

  • 主角 待补充
  • 世界观
    这座小岛存在于一个与我们相似却略有不同的世界。岛外是普通的现代社会,有经济波动、新闻热点、流行文化。岛屿本身似乎被一种温柔的神力庇佑——没有猛兽,没有极端自然灾害,仿佛专为恋人准备。岛上偶尔会出现一些神秘的“信物”(如漂流瓶、刻字贝壳),记录着世界各地恋人的心事,收集这些信物可以解锁特殊剧情或获得装饰品。
    玩家扮演的“神明”正是这座岛的守护灵,通过调节参数和回应祈愿,默默守护着两人的爱情。

游戏玩法

自主行动部分

游戏中的许多内容会随着时间推移自动发生,玩家只需旁观或适时介入。

时间与季节

  • 默认设置下,现实 10 分钟 = 游戏内 1 天,流速可在 1:1 至 1:30 之间自由调节。
  • 完整模拟昼夜交替(日出/日落/夜晚氛围)与四季更迭(春华、夏绿、秋实、冬静),并配有相应的视觉变化和背景音乐。
  • 天气系统:晴天、多云、小雨、暴雨、台风(罕见,需提前储备物资)、薄雾等,影响主角行动(如雨天多在室内活动)。

    节假、纪念日

  • 固有节日:春节(可装饰灯笼、包饺子)、中秋(赏月、做月饼)、圣诞(装饰圣诞树、交换礼物)、情人节(特别事件)等。
  • 专属纪念日:相遇纪念日、告白纪念日、乔迁之喜、结婚纪念日(如有)。系统会提前提醒玩家,并在当天触发特殊对话与愿望(如“想要一束花”“想看日出”)。
  • 玩家也可自行创建自定义纪念日,写入故事记录。

主角行为

主角完全自主行动。系统每隔一段游戏时间(或当环境变化时),会向大模型发送以下信息:

  • 主角当前的性格权重、心情、健康、压力值。
  • 当前时间、天气、季节。
  • 对方主角的状态与位置。
  • 当前愿望单优先级。
  • 可交互的设施与物品列表。
    大模型将按照格式返回具体的行为指引,主角按照这些指引行动,切实影响数值和故事走向。

    自然环境

    岛屿生态动态模拟:

  • 植被会自然生长,杂草每 3 天蔓延一次,若不清理会降低美观并影响农作物生长。
  • 果树会按时开花结果,但需要修剪和浇水。
  • 野生动物(兔子、鸟类、萤火虫等)会在特定季节出没,部分会偷吃作物,需设置围栏或驱赶。
  • 木质建筑与栅栏会随时间老化,需要维修。

    世界背景

    岛外世界通过“商船”与岛屿连接。

  • 商船每天游戏时间中午 12:00 停靠码头,带来商品(种子、工具、家具、服装、书籍等)和当日的“岛外新闻”(由大模型生成,可能影响物价、解锁新物品)。
  • 主角可将岛上产物(果实、手工艺品、画作等)卖给商船换取货币。
  • 商船可升级,升级后货物更丰富、价格更公道,并可能带回特殊订单(如“外岛旅人想要一幅苏晚的画,出价很高”)。

    主角属性

    性格

  • 玩家开局时为每位主角设定 1-3 个核心性格标签(如“乐观”“细心”“急性子”)。标签一经设定不可手动修改。
  • 但在重大事件(如争吵、生病、愿望长期未满足、一次难忘的旅行)发生后,大模型可酌情为角色增加或调整一个性格标签,模拟人的成长与改变。例如,长期相处的男主角可能新增“包容”标签。

兴趣爱好

  • 每位主角默认拥有 2 个随机兴趣爱好(如“钓鱼”“烹饪”“观星”“写日记”),玩家可在开局调整。
  • 兴趣爱好会影响主角的自主行为倾向,并解锁特殊事件。例如,喜欢钓鱼的角色会在清晨自动去海边,并有机会钓到藏着信物的漂流瓶。

    爱的维度

    游戏采用“五种爱的语言”作为核心评价体系,每位主角都从这五个维度去付出和感受爱:

  • 肯定话语:赞美、鼓励、表白。
  • 服务行为:为对方做事,如做饭、修家具、打理琐事。
  • 收礼送礼:赠送精心准备的礼物,并珍视收到的礼物。
  • 品质时间:专注的陪伴,如一起散步、看日落、促膝长谈。
  • 肢体接触:拥抱、牵手、抚摸头发等。
    五个维度的数值总和为 100。女主角和男主角的维度由两位玩家分别控制(一个入口控制男方,另一个入口控制女方)。玩家可随时调整,但每次调整后有 24 小时游戏时间的冷却。维度数值会直接影响 AI 生成行为的倾向,以及主角对另一半行为的满意度,进而影响亲密度。

愿望单

愿望是驱动故事的核心,分为三类:

长期目标

  • “长相厮守”:基础目标,无期限,系统仅记录二人共同生活的天数。
  • 可实现的长期目标:建造带花园的大房子、生养宝宝、攒够一笔环游世界的旅费、在岛上建一座灯塔等。这些目标需要大量资源和时间,完成后会触发极其珍贵的剧情和动画。

短期目标
由大模型根据性格、季节、当前状态自动生成,持续约 1-7 天。示例:

  • “想吃苏晚做的芒果布丁”
  • “周末和林屿一起去湖里划船”
  • “把庭院里的杂草清理干净”
  • “给林屿织一条围巾”

常态目标
持续存在的小期待,玩家可手动添加或删除,AI 也会根据性格衍生。示例:

  • “每天睡前都有一个晚安吻”
  • “每次做饭后希望对方说谢谢”
  • “每周至少一起看一次电影”

主角会根据性格和当前压力值,自动权衡多个愿望的优先级并执行。愿望达成时,会影响心情、健康、亲密度;长期忽视则会积累压力,甚至引发争吵事件。玩家需要在数值和目标之间做出取舍,这正是游戏模拟真实关系的关键。

基础数值

  • 健康度:影响行动效率与生病概率,通过饮食、休息、运动维持。
  • 心情:影响对话语气和行为积极性,美好事件提升,挫折或争吵降低。
  • 亲密度:两人关系的整体温度,双向累计。低亲密度时可能触发冷战、分房等事件;高亲密度解锁新互动(如主动拥抱、合作建造)。
  • 压力值:过高时会做出消极行为或生病,可通过娱乐、倾诉、陪伴降低。
  • 经济情况:共同的账户余额,通过出售产物、完成外界订单获得,用于购买商船商品和升级建筑。

岛内设施

所有设施都需要主角祈愿并由玩家消耗资源建造或升级。

  • 商船与码头:初始即存在,可升级(提升货品等级、降低价格、增加稀有物品)。
  • 房屋:初始为破旧木屋。可逐步扩建为带卧室、厨房、工作室、婴儿房的温馨小屋。家具与装饰由玩家布置。
  • 耕地/果园/牧场:需开垦,可种植蔬菜、水果,圈养鸡、兔、羊。产出用于食用、加工或售卖。
  • 作坊:可建造木工坊、画室、厨房升级等,允许主角制作具有更高价值的物品(如家具、画作、果酱)。
  • 植被与动物:详见上文自然环境部分。
  • 装饰与景观:玩家可放置路灯、秋千、长椅、花坛、风铃等,影响环境美观度,并触发特定互动(如在秋千上聊天)。

玩家行为

玩家作为“神明”,通过两个独立入口(分别对应男方和女方视角)进行非对称操作。

1. 角色控制

  • 调节爱的维度:仅能调节自己所负责主角的五个维度值。
  • 设定性格与兴趣:仅开局时可为负责的主角设定。

2. 购买与赠予
主角无法自己购物。玩家需使用共同资金,在商船界面购买物品,并以“神明的恩赐”形式直接赠予指定主角。陈设类物品(如家具、装饰)无需赠予,可直接在布置模式中使用。

3. 家园布置
主角仅能与现有事物互动(除草、浇水、收获等),无法新建或移动建筑、设施、陈设。当主角产生需求时,会通过对话框向神明祈愿,例如:“好想在院子里放一架秋千啊……神明大人,能帮帮我们吗?”
此时玩家进入家园布置模式:

  • 可移动、旋转、新增或移除建筑/设施/装饰。
  • 布置消耗对应资源和金钱。
  • 每次祈愿只能进行一次布置,完成后需等待下一次祈愿(通常 1-3 天触发一次,取决于主角心情和愿望强度)。

家园布置规则

  • 建筑需放置在平整地面上,部分设施有相邻要求(如农田需靠近水源)。
  • 美观度系统:和谐搭配(同色系、合理间距)提升整体环境评分,影响主角心情和触发特殊访客(如稀有鸟类)的概率。
  • 部分装饰有实用功能:路灯延长夜晚室外活动时间,风铃在特定风向发出音效,信箱可收到岛外来信。

4. 记录与回忆
游戏中发生的所有重要事件,由大模型进行润色总结,生成三种形式的故事记录:

  • 编年史:按时间节点罗列事件概要,配以简短的关键对话。
  • 精彩时刻:标志性事件的详细描述,仿佛短篇故事,可配有游戏截图(如有)。
  • 双视角小说:男主角入口存档生成以男方为第一人称的叙事小说;女主角入口生成女方视角。两种视角阅读时会有截然不同的心理描写和秘密,唯有两人互相分享,才能拼凑出爱情的全貌。这些记录可以随时在游戏中查看,也能导出为纯文本文件。

导语:本文介绍一种基于MDA理论的,理解动作游戏的方式或框架,方便读者在分析、理解、设计动作游戏时使用。

广义和狭义的动作游戏

 title=本节想先讨论一些远离具体的设计的、有关动作游戏的宏观理解,这些作为一些基础铺垫,帮助我们深入理解动作游戏的核心特征与乐趣,逐步导出下文的一些理解、设计方法论。
 title=

广义动作游戏

本文无意对动作游戏的今生往世做细致详细的介绍,但是动作游戏是一个不同人理解起来相当容易产生歧义的游戏类型。归根结底,动作游戏的历史和内涵过于丰富,广泛存在于不同类型游戏的体验与机制上。
从这个角度,我们可以得到维基百科对动作游戏的广义定义:任何以动作为主要表现内容的游戏,都可以算作动作游戏。比如一些跨类别的动作游戏“影子”的例子:MOBA游戏中英雄的技能、射击游戏中近战动作……
https://zh.wikipedia.org/wiki/动作游戏
狭义(日式)动作游戏
以广义去探讨,可能会像面对一整片森林去观察某种特定植物,未必能得到想要的答案。
维基百科中存在于另一个关于日式狭义动作的定义:分为2D和3D,2D分为横版卷轴、纵向卷轴、俯视角、固定画面;3D分为无双类、硬核动作、怪猎、魂like,格斗类则作为掌上明珠单独枚举。
我们所讨论的是
更接近上面狭义(日式)动作游戏的定义,正如“旗舰评论”所言:
日本定义下的狭义动作游戏,是若干个特别强调“反应与操作”的细分类型游戏的松散集合……把这些游戏类型从老到新列成一张表,它本身就是动作游戏设计的发展史:我们几乎找不出由欧美游戏设计师做出的设计创举。从最早的碰撞块和帧数判定理论开始,攻击-防御-投掷的基本三角克制关系是日本动作游戏设计出来的;跳跃和空中战是日本动作游戏设计出来的;群体战斗AI、主动性、QTE、一闪……这些设计也都是日本动作游戏先设计出来的……
https://zhuanlan.zhihu.com/p/25481394
动作游戏的哲学与本质

 title=

“动作”伴随着人类从动物形成社会的全过程,早已写入了人类的基因。当动作这个概念进行抽象并用于游戏娱乐,动作游戏诞生了。

动作游戏本质或者核心逻辑,抽象起来非常简单:玩家 控制 游戏角色 播放 动作。

 title=设计方法论:奖惩导向 上
 title=

控制的乐趣

岔一下话题,按照上文的抽象,如何让“控制”变得有趣?(这是一个很大的话题,也不局限于动作游戏。)
事实上,纯粹的控制的乐趣是很有限的,以游戏感理论框架来解释的话,单纯的控制主要的感受是:即时控制 & 润色(特殊物理感受)。
一种常见的,使得控制变得有趣的方式是,在设计上赋予控制这件事更多意义,也即,游戏感中理论的模拟空间的相关感受。(换个说法,这也是为什么动作游戏讲究观察画面获取信息,再进行控制。)
对于一些动作游戏的高手玩家,一个有意思的说法是,动作游戏就好像音乐游戏。这个说法非常有趣,音乐游戏对于时机和判定的显示十分简单,甚至可能对大多数人都会感到枯燥和重复,对于这些已经完全掌握了游戏规则(设计师的决策导向)和阅读画面信息(完美获取动画关键信息)的玩家而言,要做的事情事实上和音乐游戏,差不太多。当然这对于动作游戏的大部分玩家都是不太成立的,大众玩家不一定知道决策的方式,也不一定能掌握好画面信息的阅读。

奖惩导向
赋予更多意义这个思路下,一个非常有效的做法是奖惩导向,听起来很单纯:在玩家做出正确的控制时奖励,做出错误控制时惩罚。奖惩导向最基本也最广泛的例子是血量。
沿着奖惩这个思路,我们还可以理解,白金工作室GDC2016分享《无国界的动作游戏》中提到的,动作游戏是一种根据情形选择行为的被动游戏,“动作游戏就是设计考验场合与突破考验场合的方法”,这个设计思路。旗舰评论中也有段文字,表达相同的概念:“狭义动作游戏的历史,就是想尽办法去设计玩家可以判读的资讯,然后在他们做出正确的操作时奖励他们,在他们做出错误操作时惩罚他们。”
设计方法论:奖惩导向 下
奖惩设计方向的取舍
在基本的奖惩导向方针以后,可能还会面临一个分配问题,是设计更多的考核场景?还是给玩家设计更多的选项?这里其实有一些选择的方式,比如:场合少选项多(比如无双类游戏,主角性能较强角色较多,怪物考核较弱)、场合多选项少(比如近些年的魂Like游戏,主角能力种类较少,而关卡和敌人丰富度和考核方式极多)、或者两者试图都多(也即,处于相对均衡的状态)。
不同的倾向也可以为不同的游戏带来不同的乐趣,也或者有人会说,这是一个更侧重于主角、或者更侧重于怪物、或者两者相对均衡的游戏。
这里我们没有说两者都非常重要,而是说两者相对均衡,是因为,一般不能要求玩家“左手画圆,同时右手画框”,如果俩都想要,那最好降低各自的难度,或者至少是逐步给玩家提高难度的。
此设计思路下的动作游戏特征
按这个角度,动作游戏会需要:
  1. 能有奖惩的基础要求(满足“获取信息,采取行动”的基本循环):
  2. 动画清晰明确
  3. 判定精准可读(比如空间上遵循严格框体检测、时间上处于动画的合适位置)
  4. 玩家会追求奖励收益最大化:
  5. 设计受击动画僵直时长,以设计不同的连招序列,来引导玩家追求
  6. 设计不同的控制方式:浮空、投技、眩晕等,来引导玩家追求

这里可以带入一些没那么好的游戏作为反向例子理解,比如当一些游戏的动画看不清,就会影响玩家对信息的获取,然后干扰玩家的决策,导致奖惩判定负反馈。
基于M-D-A理论的理解

 title=收一收,我们继续把“玩家 控制 游戏角色 播放 动作。”这个底层逻辑,放入M机制-D动态-A美学理论框架中:
 title=

这里给动作游戏的归纳了两个核心乐趣(虽然不具备啥泛用性)

  • 控制感:内涵较为丰富,1.符合直觉的控制 2.丰富的控制选项 3.丰富的考核场景以带来正反馈
  • 打击感:聚焦于动作本身的美学呈现。

我们可以尝试继续挖掘M-D-A三层:

 title=

设计方法论:底层机制

这部分主要是一些经典或者传统的动作游戏规则和对应的实现方式。比如:
状态机 逻辑轴 系统逻辑

 title=

一些比较典型的动作游戏的底层机制实现过程:

  1. 攻击命中进入受击动画:攻击框与受击框有交集……(后略)
  2. 投技的实现:投技框与受击框有交集……(后略)

我们也会看到一些底层机制相对比较“模糊”的动作游戏(非刻板印象,但是欧美厂商的居多):

  • 比如动画多用融合导致动画切换、帧数感知不清晰;判定和移动方式引入较多辅助算法,导致性能感知弱
  • 动作之间的打断规则不清晰,指令预输入规则不统一影响手感

最近的经验来说,这些问题并不是决定性的缺陷,但是这些细节确实决定了一款动作游戏是否能达到殿堂级的“高度”。
!!设计方法论:微观循环
事实上,动作游戏的玩家不断在重复着:感知、认知、行动的循环过程。
认知和行动是操控的一部分,很好理解;感知的话,前面已经提到了玩家阅读画面获取信息的重要性——本质上是为了利用奖惩机制让玩家的控制有能更多乐趣。
针对感知的设计
可以引入信息传递模型:

 title=

针对发送、噪声、接收等环节都可以对应上一些具体的设计,这里不再具体举例。

针对认知的设计
这部分,理论上,玩家的认知决策规则,应该与设计师设计的规则维持一致(为了让“奖惩”有效且持续有效)。
这里补充一些典型的认知目标,和目标可能侧重的层次,如下:

 title=针对行动的设计
 title=

这部分主要是玩家控制的方式,事实上玩家也有着屏幕、键盘鼠标、手柄等多种输入设备,各自也有一些经典输入模式设计。

注意事项
再次重申,一般不能要求玩家“左手画圆,同时右手画框”,尤其是上面提到了多个层次的设计内容,如果你既要要求玩家精准阅读信息来及时操作,还要要求复杂输入精准瞄准,那多半是太为难玩家了,倒不是说不能为难,只是,“同时要求玩家做多件事情”是件为难玩家的事情,经常被设计师忘记,以至于导致玩家的谩骂。
设计方法论:打击感
这个话题太大了,这里不额外展开,典型打击感有:

  • 攻击动作:开始、攻击、结束
  • 攻击特效:(略)
  • 受击动作:(略)

从微观到宏观

 title=

前面讨论的更多是微观体验的切片,玩家玩到的游戏是一个具体的内容序列。就像离散的画面组成了电影;离散的动作组成了角色,离散的角色(作为敌人而言)组成了关卡,进而构成了游戏。

体验蓝图与玩家阶段
在具体的组成方式上,也是相当具有技巧的(比如,如何控制玩家在心流区间),一种常见的,用于指导构建复杂体验的方式,是体验蓝图,如下图:

 title=

叙事与英雄之旅

考虑到游戏是一个整体,主角怪物都离不开关卡和叙事——对于PVE游戏而言尤甚,叙事或者说剧作已经是一门相当有学问和知识经验积累的单独学科,有很多经典的结构,比如“英雄之旅”。
让动作设计贴合这些结构,会让整体给玩家的呈现,更容易接受,也能留下更强的影响。
简要总结
一图流,如图:

 title=

Simon Wasselin是Remedy Entertainment的首席叙事设计师,也是《心灵杀手2》的叙事总监。在加入Remedy之前,他在Quantic Dream工作了10年。他专注于将游戏玩法和叙事融合在一起,从而创造令玩家难忘的体验。
Molly Maloney是Remedy Entertainment的首席叙事设计师,主要为《心灵杀手2》中的角色萨贾·安德森开发叙事机制。她致力于加强跨部门合作,以开发新颖创新的叙事方式来让故事更具可玩性。

演讲标题:

Making Linear Story Playable: The Narrative Design of 'Alan Wake 2'

如何提高线性叙事可玩性:《心灵杀手2》叙事设计

演讲概述:

Remedy的作品一直以其出色的讲故事能力和复杂的角色设定而出众,在《心灵杀手2》中采用了双主角设定,玩家既要操控一位出色的FBI侦探来解开超自然谜团,还要扮演一个试图从黑暗之地中走出的饱受折磨的作家。

因此,游戏设计师们面临着以下问题:

  • 如何在一个固定的线性故事情节中为玩家提供令人满意的互动体验?
  • 当主角被固定在特定身份中时,游戏如何允许玩家进行自我表达?
  • 如何利用游戏的互动性来将复杂、多层次的理念变得易于玩家理解?

本次演讲的重点是《心灵杀手2》中如何通过叙事机制的设计,从而在AAA游戏中创造更加真实的故事体验

_01__.《__**心灵杀手2》的双线叙事

**_

《心灵杀手2(Alan Wake 2)》是由Remedy Entertainment制作,于2023年10月27日发行的一款生存恐怖游戏。游戏讲述了FBI特工萨贾·安德森和失踪多年的作家艾伦·韦克在美国西北部的辉落镇(旧译亮瀑镇)和黑暗之地展开的一场惊心动魄的冒险。在本作中,游戏采用双主角设定,玩家需要在萨贾和艾伦所处的两个不同世界之间来回切换,利用灯光和枪械对抗黑暗,收集故事元素和谜题线索,揭开超自然黑暗力量的秘密。

首先,演讲者就如何让游戏能够从一开始就吸引玩家,从而创造游玩的驱动力方面进行了大量的探讨。演讲者提到,按照Remedy以往所擅长多支线叙事的角度来看,通常是通过两部分来打造游戏的吸引力的:其一为独特的框架组织,比如在故事情节中选择某个选项或行为会产生怎样的影响等,从而增加故事表达的独特性、让玩家觉得他们所体验的故事是独一无二的;
其二为多维的互动信息传达,比如说拾取到某个物体时会提示是否与线索有关的内容,从某种程度上这也是对故事框架的支持与验证。

 title=

但《心灵杀手2》本质上是一款没有分支的线性叙事游戏,演讲者遗憾的表示,之前他们的经验以及方法论在这款游戏上并不能直接套用与适配。他们最擅长且最实用的部分独特的叙事框架组织,在这款游戏中并没有用武之地。

对此,他们分享了关于《心灵杀手2》中底层的设计支柱——通过双线叙事、故事设定、可探索性、核心玩法机制、恐怖体验五个维度,创造出了在线性叙事(关卡)中,多维且具有压迫感的核心体验。

 title=

其中在关卡设计上的双线叙事也正是演讲者最终确认的方案,一方面可以通过萨贾以及艾伦的错位视角更方便地埋下叙事暗线,另一方面也可以通过两个不同的人物线来创造不同的关卡内容体验。

Simon进一步解释,其双线叙事关卡下的设计原则可以分为三个方面:

  • 第一是关卡与叙事的高度绑定,以关卡承载叙事,以叙事支撑关卡,二者紧密结合;
  • 第二是给予玩家自主权,在合适的时候为玩家提供看得到的交互内容,让玩家自主推进剧情关卡以及剧情内容,避免被动且单一的展示,尽可能减少叙事与互动的联系;
  • 其三则是将玩家扮演的身份与游戏机制相统一,以满足玩家的想象。

 title=_02__._  _萨贾_“心灵空间”的设计
___为了在双线叙事的关卡设计中满足玩家的探索驱动力,《心灵杀手2》还需要一个与众不同的切入点,那便是两名角色的“心灵空间”**。
**_

游戏中“心灵空间”的设定

游戏内的“心灵空间”是什么?Simon给出了解答。在《心灵杀手2》中,萨贾以及艾伦均有着可以随时进入和退出的“心灵空间”,这是一个虚拟空间,不仅仅承担着整合游戏功能菜单的职能,同时玩家还可以随时进入这里访问剧情案件板,筛选线索,推理案件

萨贾线里的心灵空间是案件办公室,在这里玩家可以进入案件板,将萨贾收集的线索放置到对应的未解之谜上,以此来推理线索,推进游戏进程。

 title=

Simon表示,他们在这个空间中布置了大量现实生活中的常见元素。为了让玩家更容易理解并与空间互动,设计师们使用了隐喻现实的方法,也就是一切都基于现实生活的原型进行设计,这大大减少了玩家们的学习成本,同时它也集成了一些游戏功能菜单,例如记录游戏内的关键情节,或是隐藏起来的纪念物等内容。

这个设计在开发过程中并不是一帆风顺的,因为它其实也是一个“十分昂贵”的设计。一方面它增加了菜单的制作成本,将系统功能扩展为玩家可以进入的空间场景;另一方面,随时可以进入的设定也导致它无法控制玩家的行为,因此它需要时时刻刻占用系统内存。

但设计师们还是选择了这种方法。首先,它将游戏中的功能转化为了角色本身的探索内容,这同时也是角色自身的想象内的表达,贴合了玩家的直觉;其次是它可以为玩家提供独立的空间,脱离本体恐怖压抑的氛围,让玩家获得暂时的清醒与理智,这也能够让设计师在其中加入更多区别于人物表达的内容设计;最后,它还能够驱动或改变后续关卡故事的发展,以满足玩家的期待。

 title=此外,演讲者还表示其团队运用了很多技巧,其中最重要的便是通过在视觉和互动上来模仿现实世界的元素,来减轻玩家的心理负担。对于《心灵杀手2》这一款包含怪谈、高概念等复杂理念的游戏而言,利用玩家在现实世界中所熟知的元素构建内容,无疑降低了玩家的理解成本,以便玩家将其精力花费在游戏的关卡与解谜内容之中。
 title=

值得一提的是,这一设计也不仅仅存在于《心灵杀手2》中,在 Remedy 的上一款产品《控制》中,游戏中的“异化物”均采用了现实生活中常见的物品,其“异化特征”也贴近现实物品的特征。这一设计不仅能够让这些高概念设计更易于玩家理解,同时,在现实中的常见物品具有的“异化特征”与玩家的现实经验的冲突,也进一步强化了游戏的“诡异感”,让玩家的沉浸式体验更深一步。

案件板的设计

在上文“心灵空间”带来的优点上,演讲者提到了“它还能够驱动或改变后续关卡故事的发展,以满足玩家的期待”。那么其在游戏中的具体展现,便是类似于由玩家拼凑线索组成的“案件板”。为了契合双线叙事的设计理念中“玩家扮演的身份与游玩机制的统一”,“案件板”在两个角色上的表现形式有所差异。演讲者首先以具有出色战斗能力与强大内心的FBI探员萨贾·安德森为例,通过“案件版”,玩家可以通过探索游戏关卡以及询问来收集信息,逐渐完善“案件板”的线索,推进游戏的流程。

 title=

  • 设计之初,案件板自由组合

设计之初,Molly表示曾想过可以让玩家在案件板上自由的摆放、链接线索,不同的组合能够产生不同的线索,赋予玩家自由体验的权利。但在后续的测试中这一设计的反馈并不好——在设计师看来是开放并赋予权力的,在玩家看来则是令人焦虑的。

比如有玩家反馈到“如果我去心灵空间,我又能如何知道我收集了全部的线索,因此我可能在整理案件的思考过程中,冒出我可能错过的线索的想法,然后又回到了现实开始探索,往复循环。”

 title=因此,围绕测试人员的反馈,Molly在案件板的设计上总结了三条经验,第一是让线索更容易找到;第二则是加入画外音提示,例如在线索附近时,会提示“那里好像有东西,我最好过去看一下”;第三则是对正确的线索加入高亮闪烁提示,更容易让玩家组合线索。
 title=

  • 案件板调整:更具针对性和逻辑性

上述方案虽然给予了玩家更高的自由度,但演讲者提到,玩家的感受才是最重要的。玩家会产生焦虑是因为他们不知道自己是否找到了前进所需要的所有线索。因此,比起更容易找到线索,让玩家知道自己是否可以继续前进更为重要

对此团队对案件板重新进行了调整,不再采用之前自由摆放、链接的形式,而是采用了“固定布局,且用绳子将所有线索联系在一起的”流程图形式。

 title=

虽然它在线索的组合上没有那么自由,但更具针对性和逻辑性。例如玩家可以根据收集到的线索一层一层推进关卡进度,而不用担心错过线索影响全盘逻辑的推断,确保了玩家能够顺利推进。同时高频地解决问题,也会强化玩家自身的成就感。

但这种改动不可避免地改变了游戏的玩法,它让游戏从一个复杂组合中寻找最正确结果的破案玩法,转变成了单纯寻找物品的解谜驱动游戏 ,从玩家主动探索事件发生的过程转变为了被动告知玩家事情发生的经过,变得更像是一个叙事长片。

人物调查

当然,案件板只是萨贾的“心灵空间”推进关卡以及叙事的设计之一,而另一个重要的设计则是“人物调查”。

萨贾有这样的能力,她可以将调查的关键人物映射到自己的“心灵空间”中进行询问和取证。之所以会这样设计,是因为设计师并不想让玩家满世界的寻找NPC,且这一设计也更贴合萨贾FBI的角色身份,满足玩家角色扮演的想象。

 title=

与案件板不同的是,在人物调查上最初的设计要简陋许多,就是NPC与玩家面对面的谈话,但这种表现方式并不能表现出“心灵空间”的独特性。设计师本想在其中加入新的机制来增加其独特性,但考虑到在一个复杂的故事中引入更为复杂的设计,其不确定性太大,因此团队最终决定回到“对话”本身进行设计,但采用了多层次的表现形式。

对话在叙事游戏中起到至关重要的作用,为了增强玩家的代入感,团队并没有采用简单的对话形式,而是围绕视觉、听觉和感觉三个维度来营造一个更具沉浸感的氛围,使玩家深度的参与到推理当中,产生身临其境的感觉。 title=

萨贾的“心灵空间”设计,也正是在有限的设计空间中实现了区别于传统叙事关卡的体验,而通过上述“心灵空间”及其内容上的“案件板”、“人物调查”三部分的相互联系,实现出的效果的确比额外的独立复杂叙事更好。

_03__._ _艾伦_ _**“心灵空间”的设计
**_

艾伦的身份是一名职业作家,在前作《心灵杀手》中,他在游戏结尾被困于“黑暗之地”中。在这里艾伦写下的故事将会影响到现实,因此在《心灵杀手2》中,他要努力写出自己的出路。而这也是本作的一大特色——元叙事

整个游戏剧情以“源起”和“回归”两条故事线交织展开,艾伦和玩家之间的这种角色设定打破了游戏和现实的界限,玩家游玩的“源起”章节的过程就是在讲诉艾伦创作故事《源起》的过程。

所以,与身为FBI且可以使用枪械对抗“阴影”的萨贾的最大区别,正是艾伦的“元叙事”能力。艾伦分为两个视角一个是在黑暗之地中正在写作的艾伦,他笔下的故事正逐渐化作现实,影响现实;而另一个视角则是作为侦探的艾伦,他将见证故事改变后所发生的一切。玩家将在这两个视角中不断切换。

 title=

遵照叙事与关卡设计贴合角色的设计理念,在艾伦的关卡设计上,设计师利用三个节点来创造一个循环,分别是寻找灵感通过案件板整理线索探索过程

艾伦写作的灵感来源于其作为侦探时的经历,想要改变已经发生过的现实来弥补遗憾;随后其化作作家艾伦尝试对剧本进行修改,试图重塑结局,在这一过程中又映射出新的侦探艾伦;最后,新的侦探艾伦按照剧本演绎出了故事的结局,这段经历又重新成为作家艾伦写作的灵感,从而不断探索前进的过程。

艾伦拥有通过写作改变现实的能力,玩家所需要做的就是寻找写作的灵感,然后在案件板上整理,并在特定的场景中将灵感转化为故事文本,从而改变黑暗之地的场景,消除前进的阻碍。玩家在游戏中也会不断往复这个循环,在循环中逐渐推进宏观剧情的发展。

 title=

至于“心灵空间”的设计,艾伦的心灵空间是他在黑暗之地中写作的房间。与萨贾的设计理念类似,均是围绕角色身份而展开的,因此身份的不同,会进而带来叙事与关卡形式的区别,从而带来足够差异化的体验。

04__.  _总  结_

叙事设计远不只是简单的人物对话,当这个过程中充分融入故事剧情和游戏玩法时,叙事设计也会成为玩家体验故事的强大驱动,同时也能够让玩家获得绝佳的游戏体验。

《心灵杀手2》中,制作团队通过两位主角的错位视角和双线叙事,为玩家创造出了不同的关卡体验。同时,为了满足玩家的探索驱动力,团队通过设计两名角色独有的“心灵空间”,整合了游戏功能菜单的职能,让玩家更大程度地参与和推进了关卡内容。

作者:APlayBoy
链接:https://zhuanlan.zhihu.com/p/679668818
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1. 引言:快速入门Gradio —— 你的AI展示利器

Gradio的简介

在人工智能飞速发展的今天,向世界展示你的AI模型变得越来越重要。这就是Gradio发挥作用的地方:一个简单、直观、且强大的工具,让初学者到专业开发者的各个层次的人都能轻松展示和分享他们的AI模型。

选择Gradio的理由

\quad\quad Gradio的魅力在于它的易用性。无需复杂的前端知识,只需几行代码,你就能将任何机器学习模型转化为一个美观、交互式的界面。这不仅使模型展示变得简单,还为非技术背景的人群提供了探索和理解AI的窗口。

\quad\quad 而对于追求深度定制和企业级应用的开发者来说,Gradio同样提供了强大的功能和灵活的配置选项。无论是定制复杂的用户界面,还是在不同的环境中部署你的应用,Gradio都能胜任。

\quad\quad 在这里,我们将一起探索Gradio的各个方面。从基础概念的讲解到高级应用的实践,再到企业级部署的策略,我们将逐步深入,帮助你全面掌握Gradio。无论你是AI领域的新手,还是资深的技术专家,相信在这里,你都能找到值得一读的内容。

本教程中的所有示例和代码都是基于Gradio的新版本API编写的。在新版本的Gradio中,一些输入输出组件的调用方式已经得到简化。在旧版本中我们可能会使用gr.inputs.Audio来创建一个音频输入组件,用gr.outputs.Audio来创建一个音频输出组件,而在新版中,您只需使用gr.Audio即可。这种变化旨在使API更加直观和易于使用,另外inputs组件的参数可能也有所修改,在使用组件的时候需要根据实际情况传入参数。

2.基础入门:第一步,掌握Gradio

安装与配置

  • 环境要求:Gradio 需要Python 3.8 或更高版本的Python版本
  • 操作系统:Gradio可以在Windows、MacOS和Linux等主流操作系统上运行。
  • 安装步骤:使用pip安装,即打开你的终端或命令提示符,输入以下命令来安装Gradio
pip install gradio
  • 检查安装:安装完成后,可以通过运行以下Python代码来检查Gradio是否正确安装
import gradio as gr
print(gr.__version__)
# 4.15.0

Gradio基础教程:讲解Gradio的基本概念和操作

1. 初识Gradio

  • Gradio简介:Gradio是一个开源的Python库,用于创建机器学习模型的交互式界面。它使得展示和测试模型变得简单快捷,无需深入了解复杂的前端技术。
  • 使用场景:Gradio广泛应用于数据科学、教育、研究和软件开发领域,尤其适合于快速原型设计、模型验证、演示和教学。

2. 核心组件

  • 界面(Interface):Gradio的核心是Interface类,它允许用户定义输入和输出类型,创建交互式的Web界面。
  • 输入类型:Gradio支持多种输入类型,如gr.Text用于文本输入,gr.Image用于图像上传,gr.Audio用于音频输入等。
  • 输出类型:输出类型与输入类型相对应,包括gr.Textgr.Imagegr.Audio等,用于展示模型的输出结果。

3. 基本操作

  • 创建界面
import gradio as gr

def greet(name):
    return "Hello " + name + "!"
iface = gr.Interface(fn=greet, inputs=gr.Textbox(), outputs=gr.Textbox())
iface.launch()

这段代码创建了一个简单的Gradio界面,用户可以输入名字,点击提交后界面会显示问候语。

4. 交互流程

  • 处理和输出:上面的示例中,greet函数接收用户输入的名字,并返回问候语。Gradio自动处理这种输入输出流程,使得交互流畅自然。
  • 回调函数:在Gradio中,界面与Python函数(如greet)直接关联,这种函数被称为回调函数,负责处理输入数据并生成输出。

5. 界面定制

  • 修改样式:Gradio界面可以通过参数定制,如增加titledescription属性来提供界面的标题和描述:
iface = gr.Interface(
    fn=greet,
    inputs=gr.Textbox(),
    outputs=gr.Textbox(),
    title="简单问候",
    description="输入你的名字,获得个性化问候。"
)

  • 实用属性Interface类提供了多种属性,如layout用于改变输入输出组件的布局,theme用于改变界面主题风格等。

创建Gradio应用:创建一个简单的“Hello World”示例

在这个例子中,我们将创建一个简单的Gradio应用,它接受用户的名字作为输入,并返回一个问候语。

  1. 设置开发环境: 首先,确保你的Python环境中已经安装了Gradio。如果尚未安装,可以通过以下命令安装:
    pip install gradio
  2. 编写Python脚本: 打开一个新的Python脚本文件,比如命名为gradio_hello_world.py
  3. 导入Gradio库: 在脚本的开始处导入Gradio库:
    import gradio as gr
  4. 定义处理函数: 接下来,定义一个处理用户输入的函数。这个函数将接收一个字符串参数(用户的名字),并返回一个问候语。
    def greet(name): return f"Hello {name}!"
  5. 创建Gradio界面: 使用Gradio的Interface类来创建一个交互式界面。这个界面将有一个文本输入框和一个文本输出框。
    iface = gr.Interface(fn=greet, inputs="text", outputs="text")
  6. 运行应用: 最后,使用launch()方法启动你的应用。
    iface.launch()
  7. 尝试你的应用: 运行脚本后,你的默认Web浏览器会打开一个新的页面,显示你的Gradio应用。在文本框中输入你的名字,点击提交,你会看到问候语出现在下方。

界面元素介绍:详解不同的输入输出组件

\quad\quad Gradio提供了多种输入和输出组件,适应不同的数据类型和展示需求。了解这些组件对于设计有效的Gradio界面至关重要。

输入组件 (Inputs)

  1. Audio:允许用户上传音频文件或直接录音。参数:source: 指定音频来源(如麦克风)、type: 指定返回类型。 示例:gr.Audio(source="microphone", type="filepath")
  2. Checkbox:提供复选框,用于布尔值输入。参数:label: 显示在复选框旁边的文本标签。 示例:gr.Checkbox(label="同意条款")
  3. CheckboxGroup:允许用户从一组选项中选择多个。参数:choices: 字符串数组,表示复选框的选项、label: 标签文本。示例:gr.CheckboxGroup(["选项1", "选项2", "选项3"], label="选择你的兴趣")
  4. ColorPicker:用于选择颜色,通常返回十六进制颜色代码。参数:default: 默认颜色值。示例:gr.ColorPicker(default="#ff0000")
  5. Dataframe:允许用户上传CSV文件或输入DataFrame。参数:headers: 列标题数组、row_count: 初始显示的行数。示例:gr.Dataframe(headers=["列1", "列2"], row_count=5)
  6. Dropdown:下拉菜单,用户可以从中选择一个选项。参数:choices: 字符串数组,表示下拉菜单的选项、label: 标签文本。示例:gr.Dropdown(["选项1", "选项2", "选项3"], label="选择一个选项")
  7. File:用于上传任意文件,支持多种文件格式。参数:file_count: 允许上传的文件数量,如"single""multiple"、type: 返回的数据类型,如"file""auto"。示例:gr.File(file_count="single", type="file")
  8. Image:用于上传图片,支持多种图像格式。参数:type图像类型,如pil。示例:gr.Image(type='pil')
  9. Number:数字输入框,适用于整数和浮点数。参数:default: 默认数字、label: 标签文本。示例:gr.Number(default=0, label="输入一个数字")
  10. Radio:单选按钮组,用户从中选择一个选项。参数:choices: 字符串数组,表示单选按钮的选项、label: 标签文本。示例:gr.Radio(["选项1", "选项2", "选项3"], label="选择一个选项")
  11. Slider:滑动条,用于选择一定范围内的数值。参数:minimum: 最小值、maximum: 最大值、step: 步长、label: 标签文本。示例:gr.Slider(minimum=0, maximum=10, step=1, label="调整数值")
  12. Textbox:单行文本输入框,适用于简短文本。参数:default: 默认文本、placeholder: 占位符文本。示例:gr.Textbox(default="默认文本", placeholder="输入文本")
  13. Textarea:多行文本输入区域,适合较长的文本输入。参数:lines: 显示行数、placeholder: 占位符文本。示例:gr.Textarea(lines=4, placeholder="输入长文本")
  14. Time:用于输入时间。参数:label: 标签文本。示例:gr.Time(label="选择时间")
  15. Video:视频上传组件,支持多种视频格式。参数:label: 标签文本。示例:gr.Video(label="上传视频")
  16. Data:用于上传二进制数据,例如图像或音频的原始字节。参数:type: 数据类型,如"auto"自动推断。示例:gr.Data(type="auto", label="上传数据")

输出组件 (Outputs)

  1. Audio:播放音频文件。参数:type 指定输出格式。示例:gr.Audio(type="auto")
  2. Carousel:以轮播方式展示多个输出,适用于图像集或多个数据点。参数:item_type 设置轮播项目类型。示例:gr.Carousel(item_type="image")
  3. Dataframe:展示Pandas DataFrame,适用于表格数据。参数:type 指定返回的DataFrame类型。示例:gr.Dataframe(type="pandas")
  4. Gallery:以画廊形式展示一系列图像。
  5. HTML:展示HTML内容,适用于富文本或网页布局。
  6. Image:展示图像。参数:type 指定图像格式。 示例:gr.Image(type="pil")
  7. JSON:以JSON格式展示数据,便于查看结构化数据。
  8. KeyValues:以键值对形式展示数据。
  9. Label:展示文本标签,适用于简单的文本输出。
  10. Markdown:支持Markdown格式的文本展示。
  11. Plot:展示图表,如matplotlib生成的图表。
  12. Text:用于显示文本,适合较长的输出。
  13. Video:播放视频文件。

示例应用

让我们以一个简单的应用为例,演示如何使用文本输入和标签输出:

import gradio as gr

def greet(name):
    return f"Hello, {name}!"

iface = gr.Interface(
    fn=greet,
    inputs=gr.Textbox(label="Your Name"),
    outputs=gr.Label()
)
iface.launch()

在这个示例中,用户可以在文本框中输入名字,点击提交后,应用将在标签中显示问候语。

3. 中级应用:提升你的Gradio技能

多样化输入输出处理

\quad\quad 在Gradio中,有效地处理多种输入(Inputs)和输出(Outputs)类型是提升用户交互体验的关键。不同类型的组件可以帮助用户更直观地与模型进行交互,并获得清晰的反馈。
处理不同类型的输入

1、组合不同输入类型: 在Gradio中,你可以在同一个界面上结合使用多种输入类型。
* 示例:结合文本框(Textbox)和图片上传(Image)输入,用于同时接收用户的文本描述和相关图片。
2、输入类型的选择:根据你的模型需求选择合适的输入类型。

  • 例如,如果你的模型进行图像分类,那么应选择gr.Image();如果是文本生成模型,则应使用gr.Textbox()
    3、自定义输入设置:利用输入组件的参数自定义用户的输入体验。
  • 例如,为gr.Slider()设置最大值和最小值,或为gr.Dropdown()提供一个选项列表。

处理不同类型的输出

展示多样化的输出:Gradio允许你以多种方式展示模型的输出。

  • 示例:对于图像处理模型,使用gr.Image()来展示处理后的图像;对于文本分析,使用gr.Text()来展示分析结果。
    输出类型的选择:根据模型的输出选择合适的输出类型。
    如果模型输出为结构化数据,可以考虑使用gr.Dataframe();对于音频处理模型,使用gr.Audio()
    增强输出可视化:使用合适的输出类型增强模型输出的可视化效果。
  • 例如,使用gr.Gallery()来展示一系列生成的图像,或使用gr.Plot()来展示数据图表。

实例应用

让我们通过一个实际的例子来演示如何处理多样化的输入输出:

import gradio as gr

def process_data(text, image):
    # 假设这里有数据处理逻辑
    processed_text = text.upper()
    return processed_text, image

iface = gr.Interface(
    fn=process_data,
    inputs=[gr.Textbox(label="输入文本"), gr.Image(label="上传图片")],
    outputs=[gr.Text(label="处理后的文本"), gr.Image(label="原始图片")]
)
iface.launch()

在这个示例中,我们创建了一个Gradio应用,它接收文本和图片作为输入,并返回处理后的文本和原始图片作为输出。这样的应用展示了如何有效地结合和处理不同类型的输入输出。

界面定制

\quad\quad 在Gradio中,界面的定制化是提升用户体验的关键。你可以调整布局、样式和界面元素的显示方式,使其更符合特定需求和审美。

自定义布局

组合布局:在Gradio中,你可以灵活地组合不同的输入和输出组件。

  • 示例:创建一个界面,其中包括文本输入、图片上传和按钮,以实现不同功能的模块化布局。
    调整元素排列:利用布局参数调整元素的排列方式。
  • 示例:使用layout="grouped"layout="stacked"来更改组件的排列方式,使界面更加紧凑或分散。

定制样式

更改界面风格:使用CSS样式来定制界面的外观。

  • 示例:添加CSS代码来更改按钮的颜色、字体的大小或元素的边距。
    使用主题:Gradio提供了内置的主题选项,可用于快速更改界面风格。
  • 示例:使用theme="dark"theme="huggingface"来应用暗色主题或Hugging Face风格。

响应式设计

适配不同屏幕大小:确保你的Gradio界面在不同设备上均有良好的显示效果。

  • 示例:测试在手机、平板和电脑上的显示情况,调整布局以适应不同屏幕。
    界面元素的适配性:调整输入输出组件的大小和排列,使其适应不同的显示环境。
  • 示例:为小屏幕减少边距和间距,或在大屏幕上增加额外的空间。

实例应用

让我们通过一个具体的例子来展示如何定制一个Gradio界面:

import gradio as gr

def process_data(text):
    return text.upper()

css = ".input_text { color: blue; } .output_text { font-weight: bold; }"

iface = gr.Interface(
    fn=process_data,
    inputs=gr.Textbox(lines=2, placeholder="输入文本"),
    outputs="text",
    css=css,
    theme="dark"
)
iface.launch()

在这个示例中,我们创建了一个简单的文本处理应用,应用了暗色主题,并通过CSS改变了输入输出文本的颜色和样式。(貌似没有起作用,原因待排查!)

与预训练模型相结合

\quad\quad 在Gradio中,结合预训练模型可以让你快速创建强大的交互式界面,展示模型的能力。以下是如何实现这一目标的步骤和建议。

选择合适的预训练模型

  1. 模型源:选择适合你需求的预训练模型。常见的来源包括TensorFlow Hub、PyTorch Hub或Hugging Face模型库。
  2. 模型类型:确定你的应用场景,如图像识别、文本生成或语音处理,然后选择相应类型的模型。

集成模型到Gradio应用

  1. 加载模型:根据所选模型的文档加载模型。这通常涉及导入相应的库并加载预训练权重。
  2. 创建处理函数:编写一个处理函数,该函数接收Gradio输入,并使用模型进行预测或处理,然后返回输出。
  3. 构建Gradio界面:根据模型的输入输出类型,选择合适的Gradio输入输出组件。然后将处理函数绑定到Gradio界面。

示例:集成图像分类模型

假设我们使用Hugging Face的预训练图像分类模型。以下是一个简单的示例:

import gradio as gr
from transformers import pipeline

# 加载预训练模型
model = pipeline('image-classification')

# 定义处理函数
def classify_image(img):
    return {i['label']: i['score'] for i in model(img)}

# 创建Gradio界面
iface = gr.Interface(
    fn=classify_image,
    inputs=gr.Image(type="pil"),
    outputs=gr.Label(num_top_classes=5))
iface.launch()

在这个例子中,我们使用了一个预训练的图像分类模型来识别上传的图片,并显示前五个最可能的类别。

动态界面与实时反馈

\quad\quad 在Gradio应用中,实现动态界面和实时反馈可以极大地提高用户的交互体验。以下是如何实现这些功能的步骤和建议。

实现动态界面

条件显示组件:使用Gradio的内置功能来根据用户输入动态显示或隐藏某些组件。

  • 示例:根据用户选择的选项,显示不同的输入字段。
    界面元素更新:根据用户的交互实时更新界面元素。
  • 示例:用户上传图片后,立即在界面上显示预览。

提供实时反馈

即时处理与展示结果:设计应用逻辑,使其能够快速响应用户输入并展示结果。

  • 示例:用户输入文本后,立即显示文本分析结果。
    使用状态管理:利用状态管理来保存和更新用户交互的状态。
  • 示例:记录用户的选择或输入,以便在整个会话中使用。

示例:实现图片处理应用的动态界面

假设我们正在构建一个图片处理应用,以下是如何实现动态界面和实时反馈的示例:

import gradio as gr

def process_image(img, filter_type):
    if filter_type == "Black and White":
        img = img.convert("L")
    return img

iface = gr.Interface(
    fn=process_image,
    inputs=[gr.Image(type="pil"), gr.Radio(["None", "Black and White"])],
    outputs="image"
)
iface.launch()

在这个例子中,用户上传图片并选择滤镜类型后,应用会立即处理并显示处理后的图片。这个过程实现了动态交互和实时反馈。

高级特性和组件

\quad\quad 在Gradio的中级应用部分,引入高级特性和组件是提升应用交互性和功能性的关键。以下是Gradio提供的一些高级特性和组件及其应用方式。

热加载支持

  • 快速迭代开发:利用热加载特性,使得在开发过程中对代码所做的更改能够即时反映在应用界面上,无需重启应用。这对于调试和快速迭代开发非常有帮助。

Jupyter Notebook集成

  • Notebook内交互:Gradio应用可以直接嵌入Jupyter Notebook中,便于在数据科学和机器学习的探索性分析中直接展示和交互。用户可以在Notebook环境中实时演示和测试Gradio应用。

共享和展示

  • URL共享:Gradio允许用户通过生成的URL共享他们的应用,这使得在不同设备和环境中的演示和测试变得简单。用户可以通过设置share=True来获取可以公开访问的URL。

自定义组件

  • 个性化界面设计:用户可以根据特定需求创建自定义的输入输出组件,包括利用HTML、CSS和JavaScript进行定制。这使得应用界面可以高度个性化,更好地满足特定用途。

4. 高级功能:成为Gradio专家

高级界面和布局

使用ChatInterface

  • 聊天界面ChatInterface允许创建类似聊天应用的界面,适用于构建交云式聊天机器人或其他基于文本的交互式应用。
import gradio as gr

def slow_echo(message, history):
    for i in range(len(message)):
        time.sleep(0.05)
        yield "机器人回复: " + message[: i+1]

demo = gr.ChatInterface(slow_echo).queue()

if __name__ == "__main__":
    demo.launch()

使用ChatInterface创建聊天界面,构建一个简单的聊天机器人界面,接收用户输入,并回复相应的文本信息。

使用TabbedInterface

  • 标签界面TabbedInterface允许在一个应用中创建多个标签页,每个标签页可以包含不同的界面和功能。
import gradio as gr

def function1(input1):
    return f"处理结果: {input1}"

def function2(input2):
    return f"分析结果: {input2}"

iface1 = gr.Interface(function1, "text", "text")
iface2 = gr.Interface(function2, "text", "text")

tabbed_interface = gr.TabbedInterface([iface1, iface2], ["界面1", "界面2"])
tabbed_interface.launch()

这里展示了如何使用TabbedInterface来创建包含多个标签的界面。界面1效果

这里展示了如何使用TabbedInterface来创建包含多个标签的界面。界面2效果

使用Blocks进行自定义布局

  • Blocks布局Blocks是Gradio中用于自定义布局的一种强大工具,允许用户以更灵活的方式组织界面元素。

布局组件:Row, Column, Tab, Group, Accordion

Row和Column:分别用于创建水平行和垂直列的布局。

  • 示例:使用Row来水平排列几个按钮,使用Column来垂直排列一系列输入组件。
    Tab:用于在TabbedInterface中创建各个标签页。
  • 示例:在一个应用中创建多个Tab,每个标签页包含特定主题的内容。
    Group:将多个组件组合成一个组,便于统一管理和布局。
  • 示例:创建一个包含多个相关输入组件的Group
    Accordion:创建可以展开和折叠的面板,用于管理空间和改善界面的可用性。
  • 示例:将不常用的选项放入Accordion中,以减少界面的拥挤。
# 使用Blocks及Row、Column实现自定义布局
import gradio as gr

with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            input_text = gr.Textbox(label="输入")
            submit_button = gr.Button("提交")
        with gr.Column():
            output_text = gr.Label(label="输出")

    submit_button.click(fn=lambda x: f"你输入了: {x}", inputs=input_text, outputs=output_text)

demo.launch() 

这个示例中使用Blocks及Row、Column实现自定义布局。

# 使用Group和Accordion组织组件
import gradio as gr

with gr.Blocks() as demo:
    with gr.Group():
        input1 = gr.Textbox()
        input2 = gr.Slider()
    with gr.Accordion("详细设置"):
        checkbox = gr.Checkbox(label="选项")
        dropdown = gr.Dropdown(choices=["选项1", "选项2"])

    submit_button = gr.Button("提交")
    output_label = gr.Label()

    submit_button.click(fn=lambda x, y, z: f"{x}, {y}, {z}", inputs=[input1, input2, checkbox], outputs=output_label)

demo.launch() 

在这个示例中,我们使用Group将一些组件组合在一起,并使用Accordion创建了一个可折叠的面板,用于包含更详细的设置选项。

构建复杂界面

\quad\quad 在Gradio中构建复杂界面意味着整合多种输入输出组件、利用高级布局技巧,以及实现复杂的交互逻辑。这些技巧对于创建高级的机器学习和数据科学应用至关重要。

组合多种组件

多输入多输出界面:结合多种输入和输出组件,以处理复杂的数据类型和格式。

  • 示例:创建一个界面,包含文本输入、图像上传、滑动条等多种输入类型,并同时展示文本、图表、图片等多种输出。
    复杂的数据处理:设计能够处理多种输入并产生多种输出的复杂函数。
  • 示例:一个接收文本和图像作为输入,同时输出文本分析结果和图像处理结果的应用。

高级布局技巧

自定义布局:使用CSS和HTML自定义界面布局,以适应特定的视觉设计和用户体验需求。

  • 示例:利用CSS调整组件的大小、间距和颜色,或使用HTML布局元素。
    响应式设计:确保界面在不同设备和屏幕尺寸上保持良好的可用性和视觉效果。
  • 示例:调整布局以适应手机和平板屏幕,确保元素在小屏幕上也易于操作。

复杂交互实现

状态管理和动态更新:利用Gradio的状态管理功能来保存用户交互的状态,并根据状态动态更新界面。

  • 示例:根据用户先前的选择或输入来调整后续展示的选项和结果。
    集成外部资源和API:将Gradio界面与外部资源或API集成,以实现更复杂的功能。
  • 示例:集成外部数据源,如数据库或API,以实时获取和展示数据。

示例:创建一个综合数据分析应用

让我们通过一个实例来展示如何构建复杂界面:

import gradio as gr

def complex_analysis(text, image, threshold):
    text = "我的回复:" + text
    return text, ~image + threshold

iface = gr.Interface(
    fn=complex_analysis,
    inputs=[
        gr.Textbox(lines=2, placeholder="输入文本"),
        gr.Image(type="numpy"),
        gr.Slider(minimum=0, maximum=100)
    ],
    outputs=[
        "text",
        "image"
    ]
)
iface.launch() 

在这个例子中,我们创建了一个具有文本输入、图像上传和滑动条的复杂界面,用于综合分析文本和图像,并展示处理后的结果。

高级交互组件运用

\quad\quad 在Gradio中,高级交互组件的运用可以让你的应用更加动态和互动性强。这些高级特性允许你创建更为复杂和有趣的用户界面,从而提高用户参与度。

动态控制元素

动态显示/隐藏组件:根据用户的操作或输入动态地显示或隐藏某些界面元素。

  • 示例:根据用户在一个下拉菜单中的选择,显示不同的输入框。
    更新组件选项:实时更新组件的选项,如下拉菜单或单选按钮的选项。
  • 示例:根据用户在一个输入框中的文本,更新下拉菜单的选项。

高级输入输出处理

复杂输入数据处理:处理多维数据或多格式数据输入。

  • 示例:创建一个应用,用户可以上传CSV文件,并选择一系列处理选项。
    多步骤输出展示:分步骤展示处理结果,提供更详细的信息和解释。
  • 示例:在数据分析应用中,先展示初步结果,然后提供进一步的详细分析。

交互式图表和可视化

集成交互式图表:使用诸如Plotly之类的库,创建交互式的图表和数据可视化。

  • 示例:展示一个交互式的数据散点图,用户可以通过滑动条调整参数。
    自定义可视化组件:利用HTML和JavaScript创建自定义的交互式可视化组件。
  • 示例:创建一个自定义的数据地图,展示地理位置相关的数据。

实时反馈和动态更新

实时数据反馈:设计应用逻辑,以便在用户进行输入时即时展示反馈。

  • 示例:在用户输入文本的同时,显示文本的实时情感分析结果。
    动态内容更新:根据用户的操作或其他外部事件动态更新内容。
  • 示例:创建一个新闻聚合应用,根据用户的兴趣动态更新新闻列表。

示例:创建一个动态数据探索工具

import gradio as gr
import pandas as pd
import plotly.express as px

def explore_data(dataset, columns):
    df = pd.read_csv(dataset)
    fig = px.scatter(df, x=columns[0], y=columns[1])
    return fig

demo = gr.Interface(
    fn=explore_data,
    inputs=[
        gr.File(label="上传CSV文件"),
        gr.CheckboxGroup(choices=['Column1', 'Column2', 'Column3'], label="选择列")
    ],
    outputs=gr.Plot()
)
demo.launch()

在这个示例中,用户可以上传CSV文件并选择要探索的数据列,应用将展示这些列的交互式散点图。

状态管理技巧

\quad\quad 在Gradio中利用状态管理技巧,可以有效地保存和更新用户在界面上的交互状态。这对于创建交互式的数据分析工具、多步骤表单或任何需要记住用户之前操作的应用尤为重要。

理解状态管理

  1. 什么是状态管理:状态管理指的是在应用的生命周期内跟踪和更新用户界面的状态,如用户的输入、选择或界面的显示状态。
  2. 状态的重要性:在复杂的交互过程中,状态管理允许应用“记住”用户之前的操作,这对于提供个性化体验和维护数据一致性至关重要。

应用状态管理

初始化状态:使用Gradio的State组件来初始化状态。

  • 示例:初始化一个状态来跟踪用户是否点击了某个按钮。
    更新状态:根据用户的交互来更新状态。
  • 示例:当用户提交表单时,更新状态来反映新的用户输入。
    利用状态进行逻辑控制:根据当前状态来控制应用的逻辑和界面展示。
  • 示例:如果用户选择了特定选项,显示额外的输入字段。

状态管理实践

实现多步骤界面:利用状态管理来创建多步骤的用户界面,如分步表单或多阶段数据输入过程。

  • 示例:在用户完成第一步输入后,显示第二步的相关选项。
    保存用户会话数据:在用户与应用交互期间,保存用户的选择和输入,以便在后续步骤中使用。
  • 示例:保存用户在一个查询界面中的搜索历史,以便于后续快速访问。

示例:创建具有状态管理的数据分析应用

import gradio as gr

def update_output(input_text, state_counter):
    state_counter = state_counter or 0
    return f"您输入了:{input_text}", state_counter + 1, state_counter + 1

iface = gr.Interface(
    fn=update_output,
    inputs=[gr.Textbox(), gr.State()],
    outputs=[gr.Textbox(), gr.Label(), gr.State()]
)
iface.launch()

在这个例子中,应用通过State组件跟踪用户输入次数,并在每次输入后更新计数器。

性能优化秘籍

\quad\quad 在Gradio中,性能优化是确保应用能够高效处理大量数据和复杂计算的关键。以下是一些优化Gradio应用性能的策略和技巧。

优化数据处理

高效的数据加载:对于需要加载大量数据的应用,考虑使用高效的数据存储和读取方法,如使用Pandas的高效文件读取函数。

  • 示例:使用pandas.read_csv()时,指定usecols参数只加载需要的列。
    数据预处理:在应用启动之前进行数据预处理,以减少实时处理的负担。
  • 示例:在应用启动前,对数据进行清洗、筛选和预计算。

优化模型使用

模型加载策略:如果使用机器学习模型,考虑在应用启动时预加载模型,避免每次请求时重新加载。

  • 示例:在脚本的全局作用域中加载模型,而不是在处理函数内部。
    批处理和缓存:对于重复的请求,使用缓存来存储和复用结果,减少不必要的计算。
  • 示例:使用缓存装饰器或字典来存储已处理的请求。

界面优化

简化界面元素:避免在界面上使用过多复杂的组件,这可能导致加载时间增加和性能下降。

  • 示例:仅保留核心的输入输出组件,移除不必要的装饰和复杂布局。
    异步操作:对于耗时的操作,考虑使用异步处理,以防止界面卡顿。
  • 示例:在处理函数中使用异步库或线程处理耗时任务。

性能监控

监控应用性能:使用性能监控工具来跟踪应用的响应时间和资源消耗。

  • 示例:使用Python的timecProfile模块来监控函数执行时间。
    响应时间优化:根据性能数据优化慢速的操作或瓶颈。
  • 示例:优化数据处理流程,或替换效率低下的算法。

示例:性能优化的数据分析应用

import gradio as gr
import pandas as pd
import time

# 预处理数据
data = pd.read_csv("large_dataset.csv").preprocess()

def analyze_data(filter_option):
    start_time = time.time()
    filtered_data = data[data["column"] == filter_option]
    analysis = filtered_data.compute_statistics()
    execution_time = time.time() - start_time
    return analysis, f"处理时间: {execution_time:.2f}秒"

iface = gr.Interface(
    fn=analyze_data,
    inputs=gr.Dropdown(["选项1", "选项2", "选项3"]),
    outputs=["text", "text"]
)
iface.launch()

在这个示例中,我们对数据进行了预处理,使用了时间监控,并在处理函数中实现了快速的数据筛选和统计。

5. 企业级应用:Gradio在商业环境中的部署

多种部署方式

\quad\quad 在企业级应用中,选择合适的部署方式对于确保应用的稳定性、可扩展性和安全性至关重要。Gradio应用可以通过多种方式部署,包括本地部署、云服务和容器化。

本地部署

服务器部署:将Gradio应用部署到内部服务器,适合对数据隐私和安全性有严格要求的场景。

  • 示例:在公司的内部服务器上设置Gradio应用,确保数据不会离开内部网络。
    性能考虑:评估服务器的性能,确保足够处理应用的负载。
  • 示例:选择有足够CPU和内存的服务器,以支持大规模用户访问。

云服务部署

利用云平台:在云平台(如AWS、Azure、Google Cloud)上部署Gradio应用,享受可扩展性和灵活性。

  • 示例:在AWS EC2实例上部署应用,利用云平台的扩展能力来处理不同的负载需求。
    自动伸缩和负载均衡:利用云平台的自动伸缩和负载均衡特性,以应对流量波动。
  • 示例:设置自动伸缩策略,根据访问量自动增减实例数量。

容器化和编排

Docker容器:使用Docker容器化Gradio应用,提高部署的灵活性和一致性。

  • 示例:创建Docker镜像,并在不同环境中部署相同的镜像。
    Kubernetes编排:对于需要高可用性和复杂编排的场景,使用Kubernetes进行容器编排。
  • 示例:在Kubernetes集群中部署Gradio应用,实现服务的自我修复和水平扩展。

安全性和监控

安全性考虑:确保应用的安全性,特别是在处理敏感数据时。

  • 示例:实施SSL加密,设置防火墙和访问控制。
    性能监控:监控应用的性能,确保稳定运行。
  • 示例:使用Prometheus和Grafana等工具监控应用性能和资源使用情况。

Docker化部署

\quad\quad Docker容器化技术使得应用部署变得更加简单和一致,特别适合于企业级的生产环境。以下是利用Docker部署Gradio应用的步骤和建议。

创建Docker镜像

编写Dockerfile:创建一个Dockerfile来定义如何构建你的Gradio应用的Docker镜像。

  • 示例:在Dockerfile中指定基础镜像,复制应用代码,并安装所需的依赖。
DockerfileCopy code
FROM python:3.8 COPY . /app WORKDIR /app RUN pip install gradio CMD ["python", "your_app.py"]  

构建镜像:使用docker build命令来构建镜像。

  • 示例:docker build -t gradio-app .

部署Docker容器

运行容器:使用docker run命令来在本地或服务器上运行你的Gradio应用容器。

  • 示例:docker run -p 7860:7860 gradio-app
    * 端口映射:确保在运行容器时正确映射Gradio应用的端口(默认为7860)。
    示例:上面的命令将容器的7860端口映射到宿主机的7860端口。

容器编排和管理

Docker Compose:如果应用有多个服务(如数据库、后端服务),考虑使用Docker Compose进行管理。

  • 示例:创建docker-compose.yml文件来定义和运行多服务应用。
    Kubernetes集群部署:对于需要高可用性和大规模部署的应用,考虑使用Kubernetes进行容器编排。
  • 示例:编写Kubernetes部署配置来管理Gradio应用的容器。

安全性和监控

安全最佳实践:确保遵循Docker安全最佳实践,如使用非root用户运行容器。

  • 示例:在Dockerfile中创建并使用新用户。
    容器监控:使用工具监控容器的健康状况和性能。
  • 示例:使用Prometheus和Grafana监控Docker容器。

示例:Docker化部署Gradio应用

bashCopy code
# 创建Dockerfile
# Dockerfile内容如上所示

# 构建Docker镜像
docker build -t gradio-app .

# 运行Docker容器
docker run -p 7860:7860 gradio-app

\quad\quad 在这个示例中,我们首先创建并构建了Gradio应用的Docker镜像,然后在本地运行了该容器,实现了应用的Docker化部署。

安全与隐私保护

加强网络安全

使用HTTPS:通过HTTPS部署Gradio应用来确保数据传输过程中的加密和安全。

  • 示例:使用SSL/TLS证书实现HTTPS,保护数据不被窃听。
    防火墙和访问控制:设置防火墙规则,限制对Gradio应用的访问。
  • 示例:只允许来自特定IP地址或网络的访问请求。

数据保护和隐私

数据加密:在存储和传输过程中对敏感数据进行加密。

  • 示例:使用AES或RSA算法加密存储在服务器上的数据。
    遵守数据隐私法规:确保应用符合GDPR、HIPAA等数据保护法规的要求。
  • 示例:实施数据处理和存储的合规性措施。

身份验证和授权

身份验证机制:为Gradio应用实现强大的身份验证系统。

  • 示例:集成OAuth2.0或OpenID Connect进行用户认证。
    角色基础的访问控制:根据用户角色设置不同的访问权限。
  • 示例:为不同的用户角色定义不同的界面和功能访问权限。

日志记录和监控

审计日志:记录用户活动和系统事件,以便于事后审计和问题追踪。

  • 示例:记录用户登录、数据查询和修改等关键操作。
    实时监控和警报:实现实时监控系统,及时发现和响应潜在的安全威胁。
  • 示例:使用SIEM系统监控异常活动,并设置自动警报。

实现高可用性和扩展性

高可用性(High Availability)

冗余部署:在多个服务器或数据中心部署应用的副本,以防单点故障。

  • 示例:在不同地理位置的数据中心部署Gradio应用的副本。
    负载均衡:使用负载均衡器分配流量,以避免单个服务器的过载。
  • 示例:配置Nginx或AWS ELB作为负载均衡器来分配请求。
    故障切换和恢复:实现自动故障切换和快速恢复机制。
  • 示例:使用自动化脚本或服务如Kubernetes的自我修复能力来处理故障。

扩展性(Scalability)

水平扩展:设计应用以支持通过增加更多服务器来扩展(而不是仅仅升级现有服务器的硬件)。

  • 示例:在容器编排平台如Kubernetes上运行Gradio应用,实现容易的水平扩展。
    自动伸缩:实现基于负载的自动伸缩,以适应流量波动。
  • 示例:使用AWS Auto Scaling或Kubernetes HPA(Horizontal Pod Autoscaler)自动调整实例数量。
    无状态设计:尽可能使应用无状态,以简化扩展过程。
  • 示例:避免在单个实例中存储状态,使用中央数据库或缓存来存储会话和状态数据。

性能优化

优化资源利用:确保应用高效使用资源,避免不必要的资源浪费。

  • 示例:优化代码和数据库查询,减少CPU和内存的使用。
    缓存策略:利用缓存来减少重复的计算和数据库访问。
  • 示例:使用Redis或Memcached来缓存常见查询结果或计算密集型操作的结果。

监控和日志

实时监控系统:实现实时监控,及时了解应用的健康状况和性能指标。

  • 示例:使用Prometheus和Grafana监控应用和基础设施的性能。
    详细日志记录:记录详细的应用和系统日志,以便于故障排查和性能分析。
  • 示例:使用ELK堆栈(Elasticsearch, Logstash, Kibana)来收集和分析日志。

示例:在Kubernetes上部署高可用性Gradio应用

# Kubernetes部署配置示例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gradio-app
spec:
  replicas: 3  # 多副本以实现高可用性
  selector:
    matchLabels:
      app: gradio-app
  template:
    metadata:
      labels:
        app: gradio-app
    spec:
      containers:
      - name: gradio-app
        image: gradio-app:latest
        ports:
        - containerPort: 7860
---
apiVersion: v1
kind: Service
metadata:
  name: gradio-app-service
spec:
  selector:
    app: gradio-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 7860
  type: LoadBalancer

\quad\quad 在这个示例中,我们通过Kubernetes部署了具有多个副本的Gradio应用,确保了应用的高可用性和容易的水平扩展。

6. 实战案例

案例1:数据可视化探索工具

场景描述:创建一个数据可视化工具,用户可以上传数据集,选择不同的图表类型进行数据探索。

功能实现

  • 使用File组件上传数据文件。
  • 利用Dropdown组件让用户选择图表类型,如柱状图、折线图等。
  • 使用Plot组件展示生成的图表。

代码示例

import gradio as gr
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

def plot_data(file, chart_type):
    df = pd.read_csv(file)
    if chart_type == "柱状图":
        plt.figure(figsize=(10, 6))
        sns.barplot(data=df)
    elif chart_type == "折线图":
        plt.figure(figsize=(10, 6))
        sns.lineplot(data=df)
    plt.tight_layout()
    return plt

iface = gr.Interface(
    plot_data,
    inputs=[gr.File(), gr.Dropdown(["柱状图", "折线图"])],
    outputs="plot"
)
iface.launch() 

创建一个数据可视化工具,用户可以上传数据集,选择不同的图表类型进行数据探索。

案例2:多功能聊天机器人界面

场景描述:构建一个具有多个功能的聊天机器人,如天气查询、新闻更新等。

功能实现

  • 使用Chatbot组件作为主要交互界面。
  • 结合API调用来提供不同的服务。

代码示例

import gradio as gr
import time


def chatbot_response(message, history):
    if "天气" in message:
        # 假设的天气API调用
        text =  "今天的天气是晴朗。"
    elif "新闻" in message:
        # 假设的新闻API调用
        text =  "最新新闻:..."
    else:
        text = "对不起,我不理解你的问题。"
    for i in range(len(text)):
        time.sleep(0.1)
        yield "机器人回复: " + text[: i+1]
        
        
demo = gr.ChatInterface(chatbot_response).queue()

if __name__ == "__main__":
    demo.launch()

构建一个具有多个功能的聊天机器人,如天气查询、新闻更新等。

这是一个未知时代,未知地域发生的故事。

故事1:塔上人

人物原型来自卡尔维诺《树上的男爵》

柯西莫有一个酷爱施用家庭暴力的父亲,在连绵不断的痛楚之中,他产生了逃避的念头。一次争吵之后,父亲又要打他,他一路逃到了附近一座废弃的铁塔之上,面对追来的父亲的咒骂和责难,他发誓永远不会下到地面。

柯西莫决定在铁塔上度过余生,并为此克服了诸多的困难:他得到了邻居的帮助,讨了些救济,拉上了电线和水管,用苫布搭起雨棚,排泄问题也可以靠塔边的河解决。吃、喝都靠交换,偶尔还可以在河里钓钓鱼。凭借出色的幽默感和文字功底,他一开始靠撰稿,后来又当起主播维持生计,柯西莫反而习惯了这种其实并不幽闭的生活。他和邻居的关系都不错,甚至还借助视野的优势,通报了几次火情,预防了几次犯罪。

几年过去,柯西莫已经再也不想回到地面了,附近经历了拆迁,建起了高楼,但因为他几个出色的小诡计,拆迁没有蔓延到他的铁塔上。家里人搬远了,时常过来的劝告也越来越无力。柯西莫在塔上屯了些书。借助阅读,他的视野并没有落后于时代。

后来父亲病危,家里人来劝柯西莫回去见最后一面,但柯西莫只是把父亲当年打折在他身上的半截腰带递了回去。父亲死的那一刻,得知消息的柯西莫熟练地爬上塔顶,向父亲的方向注视了很久。

故事2:套中人

人物原型来自契诃夫《套中人》

别里科夫活在套子里。不管白天黑夜,刮风下雨,寒来暑往,他永远穿着厚厚的衣服,拿着雨伞,脸上还戴着口罩。他连吃饭、喝水时也背着人,没有人可以看清他的表情,也很少人知道他的容貌。

渐渐的,他变得日趋保守,不肯讲话,没有朋友亲人。他的装扮太过怪异,经常被当作嫌疑人盘问,所以离群索居,搬到了一处郊外,除了采买必要的生活用品,基本不出门。

然而有一天,在他刚刚买完食物回家的路上,他遭到了挟持,对方是一个逃犯,被追击时挟持他当作人质并且问他附近的出路。没想到二人误打误撞,跑到了一处冰库里面,因为近期冰库拆迁,所以没什么人看管,但仍在运行。

冰库能进不能出,逃犯发现之后,企图杀死别里科夫,但围巾太厚了,未能一刀致命,反而被他挣脱,两人对峙。随着时间流逝,只穿着单衣的逃犯渐渐失去力气,别里科夫却因为穿着厚厚的衣服而若无其事。

逃犯最终坚持不住,向别里科夫请求一件衣服穿,别里科夫答应给他一个机会,让逃犯走过来,却突然摘下口罩,逃犯吓了一大跳,远远地跑开了。别里科夫静静戴上口罩,他知道逃犯最后的机会没有了。

实际上,幼时的一场大火毁掉了别里科夫的皮肤,他的脸就像烈阳下化掉的沥青和奶油的黑白相间的混合物,狰狞可怕。从小到大,他受尽了别人的屈辱和嘲笑,还有数不尽的嫌恶。无奈之下,他把自己笼罩在一层厚厚的壳里,让自己的行为变得愚蠢可笑,这样别人见到他,只会说:“看那个蠢货!”而不是“看那个怪物!”

从此别里科夫自我厌弃于人群,但他痛恨一切犯罪行为,这个逃犯,也是他故意带到这里的。

说完了自己的故事,逃犯也渐渐快僵死了,别里科夫平静地把他捆住,在冰库门上输入密码,拖着他离开了冰库。

故事3:小巨人

人物原型来自君特·格拉斯《铁皮鼓》

奥斯卡身高只有一米二,是个侏儒。据他自己讲,小时候有人把一颗鞭炮扔到院子里,吓到了还在玩耍的他,导致他失去了发育期,身高停滞在12岁。

但奥斯卡从不在意,别人戏弄他,嘲笑他,他并不放在心上。他有一颗伟大的心灵,乐于助人,宁可自嘲当做别人的开心果,也不愿意反唇相讥。他勤勉,乐观,随叫随到,身边的人看不起他,却都知道离不开他,因为他宁可牺牲自己的利益,也要让他人快乐,这样的伙伴哪里找呢?

尽管行走在大街上时时都要仰视,奥斯卡觉得自己是不折不扣的巨人。

奥斯卡有个女朋友,是个小户人家的女儿,叫做爱玛,相貌漂亮,心肠不错,是被奥斯卡的乐观精神和殷勤态度打动的。因为她的存在,奥斯卡对自己的人生有了非常积极的期待,他觉得自己很幸福。

但最近他遇到了困难,女朋友想要去国外进修,但缺乏费用。奥斯卡只是个小酒吧里乐队的鼓手,无法给予她很多的帮助。

无奈之下,奥斯卡到各个酒吧去串场演出,筹措费用,还利用多年以来累积下来的“信用”,各处借钱。

千方百计之下,奥斯卡终于弄到了足够的钱,还都是现金,甚至来不及存到卡里,奥斯卡就给爱玛送过去了。

然而见面之后,爱玛却提出了分手,原来奥斯卡借钱的窘态被她看见了,那种低三下四的神态让她觉得丢脸,而且家中房子落实了拆迁,款项很多,她也不用过穷日子了,奥斯卡是个侏儒,除了好心肠一无所有,并不能继续匹配她的条件。

奥斯卡感到失落和颓丧,但他还是笑着祝爱玛好运,并把钱交给她,因为他自己不需要。然而就在两人向着相反方向离开时,有一个人突然蹿出来,抢下提包,很快地跑走了。

爱玛吓瘫在地,尖叫起来。奥斯卡奋起直追,虽然他身材矮小,但仗着地形熟悉,渐渐追上了抢劫者,两人一路扭打。奥斯卡力气小,身上负了很多伤。

跑了很久,到了一个僻静角落。奥斯卡支撑不住了,他的血越流越多,但还在咬牙坚持,就在他随着一次摔倒再也爬不起来时,一块砖头斜刺里飞来,打晕了抢劫犯,原来这块砖头是从旁边的一个铁塔上飞来的,上面一个奇怪的人在向他招手。

这时又走来一个奇怪的戴着口罩的人,还拖着一个捆着的半死的家伙。合力把抢劫犯捆住后,奥斯卡才发现爱玛早已不知去向,连警都没有报。

故事4:嫌疑人

人物原型来自动画片《维克多和雨果》

雨果和维克多是一对发小,童年时就顽皮捣蛋。在一次恶作剧时,他们把鞭炮分别扔进了好几家人的院子里,却没想到酿成了火灾(并导致奥斯卡变成侏儒,和柯西莫父亲以为儿子闯祸而责打他),因为恐惧责罚,他们相约逃走,从此流浪,靠偷窃和抢劫谋生。

几年后,他们又回到故乡,因为外貌大变,没人认得他们了。他们又能肆无忌惮地犯案。

没想到一次作案时被人报警(柯西莫),两人分头逃跑,雨果走投无路时,想挟持人质,结果误入冰库,被别里科夫冻僵制服。维克多流浪了几天,身无分文时发现了爱玛背着的钱,贪婪之下,他飞身抢夺,然后被奥斯卡追赶并和其他人合力制服。

结局

查清了来龙去脉,三个人的前半段人生有了一个共同的句号,他们成了很好的朋友。但柯西莫仍然没有下过地,因为见义勇为,原本要拆迁的铁塔被保留了。别里科夫和奥斯卡也决定陪着柯西莫住在塔上,他们不再关心世态炎凉或红尘起落,只欣喜于找到了朋友。他们并不会彻底离开尘世,但还是要和它保持距离。

也许事情的结局就应该是这样,伤害既然已经发生,有的时候就会无可挽回,比起事后追悔,还是善待身边的人吧,不然,他们也会住在塔上。