“我拳都收回来了,它才打出去。”这是体感拳击游戏里最常听到的抱怨之一。玩家对着手机摄像头挥出一记直拳,手臂伸直、收回,屏幕里的角色这才慢吞吞地把拳头送出去,打中对手的时候,玩家已经在准备下一拳了。识别本身没有错,确实是一记直拳,可这一拳在玩家心里已经“不算数”了。

体感竞技和体感健身有一个根本区别:健身游戏晚一点告诉玩家“这一下蹲得不错”问题不大,竞技游戏里晚一点出拳,就等于被对手先打中。所以在讨论动作识别准不准之前,得先回答另一个问题:从玩家真实开始挥拳,到游戏角色做出反应,中间到底过去了多久,这些时间都花在了哪里。

一拳进入游戏,要穿过五道关口

玩家按下手柄按键,信号几乎是立即送达游戏的;而摄像头体感没有“按键”,一个动作要先被拍下来、被找到、被拆成关键点、被识别成某种动作,最后才变成游戏里的指令。这段总时长,通常称为 Input-to-Action Delay。下表是一个示例拆分,各环节的数值只是模拟场景下的量级示意,实际情况取决于设备性能、模型大小和实现方式。

环节 发生了什么 延迟从哪来可以怎么压缩
Camera 采集 曝光、读出、传输一帧图像 帧间隔本身,30fps下约33毫秒,另有缓冲 提高帧率、减少缓冲队列
人体检测 找到玩家所在区域 模型推理时间 跟踪代替逐帧检测,只在丢失时重检
姿态估计 输出肩、肘、腕等关键点 模型推理时间,与输入分辨率相关只对玩家区域推理、选择轻量模型
动作识别 判断这是不是一拳、哪种拳 需要积累若干帧才能下结论 起手预测、缩短确认窗口
游戏逻辑与渲染 角色播放动画、结算命中 逻辑帧、渲染帧、屏幕刷新 动画前置、减少渲染排队

单看每一行,好像都不算长,但它们是串联相加的。任何一环多排一帧队列,整条链路就多出一截。更麻烦的是,这里面占比最大、最容易被低估的,往往不是模型推理,而是动作识别为了“确定”而等待的那几帧。

等一拳打完再判定:准确,但玩家早就不耐烦了

最直观的识别方法,是等一个动作完整结束再判断。一记直拳从起手到手臂伸直、再到收回,整个过程会跨越不少帧。如果系统等手臂收回、确认完整轨迹后才判定为“直拳”,再通知游戏播放出拳动画,那角色出拳的时刻就落在玩家收拳之后,开头那句抱怨就是这么来的。

这种做法的优点是几乎不会误判,完整轨迹里信息最充分,直拳、勾拳、摆拳的区别一目了然。它适合对实时性要求不高的场景,比如训练结束后回放每一拳的质量评分,但不适合对抗。

手一动就触发:快,但擦汗也会变成出拳

反过来,如果手腕位置一有明显变化就触发出拳,延迟确实降下来了,可误触发会大量增加。玩家抬手擦汗、推一下眼镜、调整站姿时手臂自然摆动,甚至只是呼吸时肩膀起伏,都可能被当作一次攻击。在对战里,一次误触发意味着角色莫名其妙地出拳、露出破绽,玩家会觉得游戏“不听话”,这比慢一点还难接受。

此外,只看起手时的那一小段,也很难区分拳种。直拳和勾拳在最初几帧里的手腕位移可能很相似,差别要到手臂展开以后才逐渐显现。过早下结论,就可能把勾拳识别成直拳。

折中方案:先让角色起手,再决定这一拳算不算

既然“等完再判”太慢、“一动就判”太乱,那能不能把一次出拳拆成两步:先根据起手阶段做一个预测,让角色开始动;再根据后续几帧做确认,决定这一拳是否真正打出、打中了多少。九游体育在体感拳击玩法里采用的就是这种“预测—确认”的思路。

第一步:从肩、肘、腕的速度里读出“要出拳了”

出拳并不是从手腕开始的。一记有效的直拳,通常伴随着肩部前送、肘部开始伸展、手腕沿着朝向前方的方向加速。系统在连续几帧里同时观察这三个关键点:手腕速度是否超过一个示例阈值,速度方向是否指向前方或对手所在方向,肘角是否正在变大,肩部是否同步前移。几个条件同时满足,就判定为“出拳起手”,而擦汗、推眼镜这类动作,手腕是向上朝向脸部移动的,方向就对不上。

第二步:先播放前摇,不结算伤害

判定为起手后,游戏立刻让角色开始播放出拳前摇,也就是拳头从防守位置向前送出的前半段动画。这一步不结算命中、不扣对手血量,只是让玩家看到“我的角色跟上了我”。由于前摇和玩家的真实起手几乎同步开始,主观上的延迟感会大幅减轻。

第三步:确认以后再结算,判断错了就平滑收回

在接下来的几帧里,系统继续观察手臂是否确实伸展到位、手腕速度是否保持、轨迹是直线还是弧线。确认是直拳,就播放后半段动画并结算命中;轨迹呈弧线,就在后半段切换成勾拳动画;如果手臂很快停下或者方向改变,说明这不是一次出拳,角色就把拳头平滑收回防守位,不产生任何伤害。游戏设计上要让这个“取消”看起来自然,比如表现为一次虚晃,而不是突兀地抽搐一下。

这种方法的关键在于把游戏动作设计成可撤销的:视觉反馈可以提前,但真正影响胜负的结算要等到有足够把握的时候。如何在降低延迟的同时控制误识别,体感体育游戏怎么降低动作延迟又不让误识别变多一文还有更细的讨论。

格挡、闪避和出拳,对延迟的容忍度并不一样

并不是所有动作都需要同样激进的预测。出拳是玩家主动发起的动作,起手信号清晰,适合提前播放前摇;格挡则是对对手进攻的反应,玩家双手护在脸前的姿势会保持一段时间,系统只要在对手拳头落下的那一刻判断双手是否处于防守位置即可,对“什么时候开始格挡”不必过分敏感。

闪避的情况更特殊。玩家向左或向右侧身躲拳,依赖的是躯干和头部的位移,这些部位比手腕大、移动相对平缓,关键点也更稳定,识别起来反而容易。但闪避的判定时机非常关键:对手的拳打过来时,系统要以玩家那一刻的头部位置来结算是否命中,而不是以几帧之前的位置。如果闪避识别的延迟比对手拳头的飞行时间还长,玩家明明躲开了却仍被判中拳,这种挫败感比出拳慢更强烈。因此游戏里对手的重拳往往要留出足够长的前摇,给玩家的闪避识别留出余量。

平滑滤波:去掉抖动的代价,是让一切都慢一点

姿态估计输出的关键点天然带有抖动,尤其是手腕这种小而快的部位。光线不足、衣袖宽松或者手臂快速挥动产生运动模糊时,抖动会更明显。如果不做处理,游戏里的角色手臂会跟着微微颤动,甚至因为一次跳变被误判为出拳。

常见做法是对关键点做时间平滑,比如对最近几帧取加权平均。问题是,任何平滑都依赖过去的数据,平滑得越狠,输出就越落后于真实位置。一个实用的思路是让平滑强度随速度变化:手臂几乎静止时加大平滑,让防守姿势稳稳当当;手臂快速运动时减小平滑,让出拳尽快反映出来。这种自适应滤波的想法在人机交互领域已经相当常见,它本质上是在“稳”和“快”之间按场景切换,而不是一刀切。

同时,关键点的 Confidence 也要参与进来。某一帧手腕置信度很低,与其把这个可疑位置平滑进去,不如直接沿用上一帧的可信状态,不触发任何新判断。低置信度时宁可不动,也不要给出错误动作。

帧率:30fps和60fps差的不只是流畅

很多人把帧率理解成画面是否流畅,但对体感识别来说,帧率还直接决定了系统多久才能“看到”一次新的动作变化。在30fps下,相邻两帧间隔约33毫秒;在60fps下,间隔约16.7毫秒。如果起手预测需要连续三帧满足条件,60fps下这个等待时间就比30fps缩短了一半左右。

但帧率翻倍,意味着检测和姿态估计也要在一半的时间里完成,否则帧会在队列里排队,反而增加延迟。所以在性能一般的手机上,稳定的30fps往往比时断时续的60fps更好。另外还有一个折中办法:采集保持较高帧率,只对玩家所在的局部区域做姿态估计,用较小的输入分辨率换取更快的推理速度。

对战里的延迟,还要对双方一视同仁

当体感拳击变成两个玩家在线对战时,延迟还牵涉到公平,这也是九游体育在设计对战玩法时反复权衡的地方。一方用的是性能强劲的设备、稳定60fps,另一方用的是较旧的手机、只能跑到30fps,两人从出拳到角色出手的时间就不一样。游戏设计上可以给每一记重拳保留一段固定的前摇动画时间,让双方都有一个看得见的起手窗口,设备差异带来的几十毫秒被吸收在这段动画里,而不是直接决定谁先打中。

这种前摇并不是故意拖慢游戏,而是让对抗有“可读性”:对手能看到你要出拳,你也能看到对手要出拳,攻防才有来有回。

本文中的阈值、帧数和延迟数值均为示例设定或模拟场景下的量级说明,不代表特定设备的实测结果。体感游戏属于游戏化运动,出现身体不适时请停止并咨询专业人士。

先把时间算清楚,再谈识别得多准

回到开头那句抱怨:“我拳都收回来了,它才打出去。”问题的根源不是识别不准,而是系统等到太有把握才行动。一个好的体感竞技系统,会在玩家起手的瞬间就让角色跟上,在确认之后才让结果生效,在误判时优雅地收回。

九游体育把这个认识放在体感竞技设计的起点:它首先是一个实时系统,其次才是一个识别系统。每一环的毫秒都要算清楚,每一个游戏动作都要考虑能不能撤销,每一次平滑都要想清楚换来了什么、付出了什么。想了解一个动作从摄像头进入游戏的完整步骤,可以继续阅读玩家挥拳以后AI到底经历了哪些步骤。