球员动作生成
Input Response
万利App生成新的球员动作以后,为什么玩家真正感受到的第一件事不是画质,而是按键以后角色什么时候动?
产品设计笔记 · 预计阅读 7 分钟 · 关联模块:球员动作生成
万利App里第一次看到新的球员动作生成结果时,很多人会先盯着画面细节看——步频顺不顺、转身角度自然不自然、球衣有没有跟着风向摆动。但真正决定这段动作是否好用的,往往不是这些视觉细节,而是一个更朴素的问题:玩家按下方向键或者射门键之后,角色到底隔了多久才开始动。这个间隔,内部一般叫Input Response,也就是输入到动画真正启动之间的延迟。
这件事听起来简单,做起来却很容易被忽略,因为生成式动作系统天然更容易在动作好不好看上投入精力,毕竟这是能被截图、能被拿来展示的部分。但万利App在实际测试里反复看到同一个结果:只要Input Response超过某个阈值,哪怕生成的动作再流畅、再贴近真实球员风格,玩家的第一反应也是操作是不是卡了,而不是这个动作做得真好。画质和动作细腻度是加分项,响应速度是及格线,及格线没过,加分项根本没有机会被玩家感知到。
万利App对动作生成模块设定的优先级很直接:先保证按键到角色开始反应的时间稳定在可接受区间内,再谈动作过渡的自然程度。两者冲突时,响应优先。
角色在静止、跑动、冲刺、转身等状态之间的切换,都要先满足输入响应,再由生成模型补上过渡细节。
这也是为什么万利App的动作过渡系统不能简单地生成一段最好看的动画再播放。更现实的做法是分层处理:角色对输入的第一步反应必须尽快启动,哪怕先用一小段轻量过渡顶上,真正由生成模型输出的高质量动作可以在后续几帧里再逐步接管、覆盖或者混合进来。玩家感受到的是我一按键角色就动了,生成模型负责的是动起来之后这段动作看着值不值,这是两件被分开对待的事情,混在一起做,往往两头都做不好。
另一个容易被忽视的地方是,Input Response不是一个孤立的动作模块参数,它会牵连整个球员动作生成流程的调度顺序。如果生成系统在等待更完整的上下文信息,比如队友位置、球的轨迹、对手动作,才决定该生成哪一种过渡,那这段等待时间就会直接叠加在玩家能感知到的延迟上。万利App处理这类情况时,会让第一步反应动作先用当前已知的最小上下文触发,更完整的判断放在动作已经开始播放之后再补上,用来微调后续几帧,而不是卡住整个反应链条去等一个更准确的生成结果。
从玩家角度看,这套逻辑不需要被解释,也不会被感知为一种技术选择,他们只会觉得万利app玩起来跟手或者不跟手。但对做这套系统的人来说,这恰恰是最值得较真的地方:动作生成的质量决定了这个系统能不能被称为体育游戏生成式AI的一部分,而Input Response的稳定性,决定了这套系统能不能被玩家真正接受并长期使用下去。这两件事都重要,但顺序不能反。
更细的动作过渡策略和状态切换逻辑,可以看万利球员AI里关于
动作过渡 的部分;如果想了解万利App这套响应逻辑背后依赖的比赛数据基础,也可以参考首页
真实比赛数据 的介绍。
生涯剧情
Career State
万利App进入生涯模式以后,为什么AI生成的新剧情必须先读取当前赛季而不是直接从一句Prompt开始?
产品设计笔记 · 预计阅读 7 分钟 · 关联模块:生涯剧情 / 生涯事件
万利App的生涯模式如果只靠一句Prompt去生成剧情,会出现一种很尴尬的情况:生成出来的故事读起来很像那么回事,但跟玩家实际正在经历的赛季对不上。比如球员这个赛季其实刚从伤病里恢复、目前只是替补席上的轮换球员,生成结果却写出一段带领球队逆转夺冠的高光剧情;或者球员上一场比赛的关键选择明明是拒绝转会,剧情里却突然提到一次并不存在的转会传闻。这类问题不是文笔不够好,而是生成的起点从一开始就选错了。
万利App在处理这类生成任务时,会把当前赛季阶段、所在俱乐部、场上位置、首发或替补状态、最近的伤病记录,以及玩家此前在关键节点做过的选择,统一整理成一份可以被读取的Career State,再把这份状态交给生成系统作为前提条件,而不是让生成系统只凭一句开放式的提示词自由发挥。剧情可以有创意,但创意必须建立在这些既定事实之上,不能绕开它们重新编一套。
万利App对生涯剧情生成的基本要求是:先读取Career State,再决定这段剧情能往哪个方向发展;顺序反过来,生成结果几乎必然会跟玩家实际经历的生涯产生冲突。
生涯历史、球员状态、球队情况与赛季阶段先汇入Career State,再驱动新剧情与生涯事件的生成。
这套顺序背后有一个很现实的原因:生涯模式最容易伤害体验的,不是剧情写得平淡,而是剧情前后矛盾。玩家对自己的生涯记得比想象中清楚,上赛季有没有降级、这场比赛是不是被换下过、跟哪位队友闹过矛盾,这些细节一旦被生成的新剧情忽略或者写反,代入感会立刻碎掉。相比之下,剧情本身是不是足够精彩,反而是可以容忍一定波动的。也正因为这样,万利App宁可让生成系统先花时间对齐Career State,也不愿意用一个更快但可能对不上的直接生成方案。
实际实现上,Career State不是一次性读取就结束的静态快照,而是随着每一场比赛、每一次生涯事件的选择持续更新的一份记录。生成新剧情之前,系统会先确认这份记录里哪些字段跟本次生成直接相关:赛季进度决定剧情基调,位置和首发状态决定剧情视角,最近的伤病和选择决定哪些情节分支应该被排除。只有把这些条件过滤完,剩下的空间才交给生成模型去组织语言、安排冲突和铺陈细节。生成模型负责讲好这个故事,Career State负责保证这个故事讲的是同一个玩家、同一段生涯。
把这套顺序坚持下来的代价是,生成一段生涯剧情要比单纯丢一句Prompt给模型慢一些,需要先做状态整理和字段过滤。但换来的结果是,玩家在生涯模式里遇到的新剧情,几乎不会出现明显对不上号的低级错误,这对一个需要玩家长期投入几十个赛季的模式来说,比多几句华丽的台词更重要。
Game State
系统架构
万利App把动作、球场、解说、生涯和动态任务放进同一套体育游戏AI以后,为什么真正共同的底层能力其实是Game State?
系统设计笔记 · 预计阅读 8 分钟 · 关联模块:全部功能模块
从功能列表上看,万利App像是把八件不相干的事情拼在了一起:球员动作生成负责让角色动起来,AI球场生成负责搭场景,AI比赛解说负责讲比赛,生涯剧情和生涯事件负责讲故事,AI训练挑战和动态任务负责给玩家安排目标,万利虚拟人负责呈现角色形象。单独看每一项,确实可以是各自独立的模块,分别找不同的团队、用不同的技术方案去做。但万利App没有这么拆分,原因很简单:这八项功能背后依赖的其实是同一份数据,如果各自为政,很快就会互相打架。
举一个具体的例子:比赛正在进行时,球员的体能、位置、比分、剩余时间同时被动作生成、AI比赛解说和动态任务读取。如果这三个模块各自维护一份自己的比赛状态,稍微有一点不同步,就会出现解说说体能充沛而角色动作已经明显跑不动、或者动态任务提示还剩五分钟扳平而画面上时间早就过了的情况。这种割裂对玩家来说是最容易察觉的破绽,也是最难靠增加内容来掩盖的破绽。
万利App架构上的核心判断是:动作、球场、解说、生涯、任务这五类生成能力,看起来是五个功能,实际共用的是一套Game State——比赛状态、生涯状态、球员状态和世界状态的集合。
比赛状态、生涯状态、球员状态与世界状态共同构成Game State,向各个生成系统提供依据。
Game State在万利App里承担的角色,更接近一份所有生成系统都要先读、有变化都要先写回的公共记录,而不是某一个功能模块的内部数据。球员动作生成读取球员当前的体能和位置来决定该触发哪一种过渡;AI球场生成读取比赛所在的赛事级别和天气设定来决定场景细节;AI比赛解说读取比分、时间和关键事件来组织解说内容;生涯剧情和生涯事件读取赛季阶段和历史选择;AI训练挑战和动态任务读取球员的当前能力短板和进度。这些读取的字段并不完全相同,但都指向同一份Game State,而不是各自维护一份互不相通的副本。
这套设计带来的好处不是让某一项功能单独变得更强,而是让整套系统在长期使用中不容易出现自相矛盾的地方。生成模型本身可以持续迭代、持续替换,只要它们都遵守同一份Game State的读写规则,替换某一个模块不会波及其他模块。反过来,如果一开始就让八个功能各自维护数据、各自决定何时生成,短期内看起来功能都能跑起来,但用得越久,各模块之间对不上的情况只会越来越多,到时候要修复的不是某一个功能的生成质量,而是要把整套数据结构推倒重新对齐,代价要大得多。
所以从系统设计的角度看,万利App真正值得被反复打磨的,其实不是某一项生成能力做得多花哨,而是Game State这一层是否足够稳定、字段是否足够清晰、读写顺序是否足够明确。这层做扎实了,动作、球场、解说、生涯、任务这些具体功能才有一个可靠的地基去持续迭代。
Game State具体包含哪些状态类别、各模块如何分工读取,可以参考万利体育AI中的
Game State与设计目标 一节;如果想了解这套引擎背后的团队和产品定位,也可以看首页
关于万利 的介绍。