音游判定原理详解——从触摸屏幕到判定音符【Project SEKAI攻略】
“音乐游戏”一般简称为“音游”,玩家需要配合音乐的节奏来进行一定的动作。
《Project SEKAI》作为一个“移动端音游”,绝大多数玩家会使用手机、平板电脑等移动设备的触摸屏进行游玩,也有极少数的玩家不按常理出牌,使用手台、键盘乃至于触控板等非常规输入设备进行游戏。同时,作为“下落式音游”的一员,在游戏中音符会从界面的上方落下,玩家需要根据音符时机和类型在正下方的判定区域做出一定的操作,当音符与判定线完全重合时,便是音符完美的判定时机。
本篇文章作为音符具体判定机制分析的前置攻略,将会以使用Unity引擎编写的《Project SEKAI》为例子带领各位读者简要了解一下一款音游是如何实现判定机制的,或许对其他音游也能有所启发。为了便于理解,下文会尽量避免对程序代码的讨论,仅说明基本原理与过程,部分细节可能不够严谨,还请谅解。
本篇文章主要分为3个部分:
第1部分《从触摸屏幕到触摸对象》,介绍操作系统和Unity框架处理触摸事件的流程
第2部分《从触摸对象到触摸处理》,介绍游戏的主循环和触摸事件处理逻辑
第3部分《从触摸处理到音符判定》,介绍音符的判定时间、下落速度、状态机以及判定过程
一、从触摸屏幕到触摸事件
1.1 触摸事件生成与传递
触摸屏作为移动设备上最主要的输入设备,当用户触摸时,硬件会以一定频率对屏幕进行触控采样,采样过程主要是获取用户触摸的位置信息,驱动程序会获取来自硬件的事件,经过处理后将触摸位置的坐标、用于追踪手指的追踪ID等信息生成内核事件。越高的触控采样率会让硬件采样时间间隔变短,对手指运动的追踪也更为准确。例如,iPad Pro提供了240 Hz的触控采样率,代表每秒钟会从触摸屏中采样240次,约4毫秒1次。
在程序的执行过程中,如果需要获取触摸事件,会通过声明对触摸事件的监听器来实现。当触摸事件来临后,操作系统会从内核中取出相关事件,并经过一定处理和封装后,将触摸事件传递给正在监听这一事件的程序进行处理。
这一过程可以简化为下图:
操作系统封装的触摸事件有以下程序关心的内容:
触摸动作:操作系统会识别出按下、移动、松开等动作
触摸位置:触摸位置的坐标
历史触摸位置:上一次触摸事件的触摸位置坐标
事件时间:触摸事件发生的时间
触摸点编号:为当前每个触摸点分配单独的编号
1.2 记录触摸事件
Unity作为游戏引擎,会为游戏预处理来自操作系统的触摸事件,这样做的目的是使用Unity引擎的游戏可以使用统一的接口获取输入事件,有效减少了实际运行的操作系统给游戏带来的差异性。
当接收到触摸事件时,Unity会记录这些触摸点的许多信息,游戏着重关注以下内容:
触摸阶段:按下、移动、按住不动、松开等阶段
触摸位置:触摸位置的二维坐标,以屏幕左下角为原点
手指编号:会为正在触摸的手指各分配一个编号
位移向量:如果产生了一定滑动位移,将会记录滑动的位移向量
例如,一根手指在极短时间内快速执行了“按下”、“移动”、“松开”的过程,Unity会记录下3个“手指编号”相同、“触摸阶段”不同的触摸事件:
二、从触摸事件到触摸处理
2.1 游戏主循环
在设计游戏框架时,需要一个游戏主循环(Game Loop)每隔一段时间循环处理游戏逻辑,比如完成音符判定、音符移动位置等。不过,无论使用什么策略来确定间隔时间,由于硬件的性能限制,是很难做到完全等间隔的。例如,如果在这一步固定让音符位移10像素会因为时间间隔不均匀导致无法匀速运动,需要根据和上一次处理的时间差来进行进一步的运算。
为了方便起见,大部分游戏会以“1帧”作为时间间隔进行循环,“帧”指的是游戏中的单幅画面,例如帧率为每秒60帧代表1秒中之内会有60个画面。同样的,每帧之间的时间间隔并非完完全全固定,也会因为性能原因产生波动。值得一提的是,并非所有游戏会在每帧都处理一遍游戏逻辑,例如知名的沙盒游戏《Minecraft》,无论显示帧率有多少,会以每秒20游戏刻的固定速度进行游戏更新,当然如果卡顿了也会导致游戏刻变少。
同样在Unity引擎中游戏主循环也不需要开发者自己来实现,Unity为游戏提供了2种不同的循环模式:每帧处理一次、与帧率不同的固定频率处理。《Project SEKAI》采用了每帧更新一次的策略,判定相关的逻辑也是每一帧执行一次。
2.2 触摸事件获取
Unity收到操作系统传递的触摸事件后,做的事情仅仅是记录触摸事件,并不会在收到事件后立刻交给游戏处理,需要等待游戏在处理游戏逻辑时主动获取上一帧之后的触摸事件。特别的是,虽然操作系统在传递触摸事件的时候提供了事件发生的时间,但Unity既不会记录事件发生的时间也不会记录收到事件的时间。
例如,玩家在第k帧后立即进行触摸操作,在触控采样后这一事件进入Unity引擎,但游戏到了第k+1帧的时候才能得知这一事件,且游戏认为按下的时间是第k+1帧的时间,而非实际按下的时间:
这样的设计使得Unity引擎下的音游在判定时会产生与真实输入的时间差,会导致“拖判”更容易发生,这一时间差的最大值为两帧的间隔时间,帧率越高间隔越小,拖判也越不明显。
为了从根源上解决拖判的问题,游戏可以使用“Native Touch”插件等手段绕开Unity的触摸处理逻辑,直接接收操作系统的触摸事件。遗憾的是,可能是碍于技术水平或者是性能的问题,《Project SEKAI》并没有进行类似的改进,而是直接使用了Unity提供的触摸事件。更为遗憾的是,虽然提高游戏帧率能在一定程度上改善拖判的问题,但拥有120帧显示屏的iPad Pro却被锁死在了60帧,不得不接受拖判的现实。
2.3 触摸事件处理
无论使用什么方法获取到触摸事件后,都需要对输入事件进行进一步的处理。作为一个下落式音游,一个非常重要的处理就是找到点击位置对应的下落轨道。
《Project SEKAI》将主要的游戏区域分为12根轨道,Unity作为一个支持3D的引擎,这些轨道在三维空间中倾斜一定角度,通过近大远小的视觉效果,给玩家产生一种音符从远处逐渐接近判定线的“距离感”。当玩家触摸判定线及其上下位置时,会通过Unity将二维的屏幕坐标换算为点击位置的三维空间坐标,并使用这一坐标计算对应的轨道。值得注意的是,这一步得到的轨道并非诸如第1轨、第2轨的某一条轨道轨道,而是类似在第1轨的左起33%这样的准确位置。《Project SEKAI》每帧至多处理10个触摸事件。
例如,假设只有2条轨道,下图所示的这条线便是第2轨的50%位置,这条线并非在平面上垂直于判定线,而是在空间上垂直:
当然,在具体实现上可以认为每个轨道的宽度为1,直接以1个小数来表示触摸事件的轨道位置,例如2.5等。
虽然《Project SEKAI》有12根轨道,但实际上音符会拥有一定宽度以达成某种意义上的“无轨下落”,音符可以通过左侧和右侧所在的轨道位置来表示其位置和宽度信息。
三、从触摸处理到音符判定
3.1 音符判定时间
音游讲究的是玩家操作与音乐节奏的配合,一般来说会根据玩家完成操作的时机和音符与判定区域重合的时间进行对比,根据时间差给予一定的结果,这一过程称为“判定”,部分音游也会允许玩家微调判定区域的位置。判定后,根据不同的判定结果可能会获得不同的分数,也可能会发生减少生命、断COMBO等惩罚措施。
例如,《Project SEKAI》会提供PERFECT、GREAT、GOOD、BAD、MISS五个判定结果,GREAT会减少得分、GOOD既会减少得分又会断COMBO、BAD和MISS不仅断COMBO还会扣除生命且不得分。
每种音符有着自己的具体判定时间范围,甚至同一判定在延后和提前的情况下时间范围也不一定相同,但大体上可以总结为下图,比例仅作示意不代表真实比例:
可以看出,两侧的BAD判定时间范围决定了音符最大的判定时间范围,比BAD提前不会进行任何判定、比BAD还延后就会得到MISS。
3.2 音符下落速度
作为一个下落式音游,音符需要从屏幕上方逐渐“下落”到达屏幕下方,大部分音游都提供了调速功能,可以改变音符下落的速度。《Arcaea》等部分音游也会根据BPM的变化来改变音符实际下落速度。
《Project SEKAI》为玩家提供了[1.0, 12.0]区间内步长为0.1的下落速度调速。然而,12速的下落速度并不是1速的12倍,实际上音符从出现在轨道中开始直到到达判定线的时间(以下简称“下落时间”)与下落速度有以下关系:
也可以通过描点法画一个直观的函数图像,请注意这并不是一个连续函数且有定义域的限制:
可以看出,下落时间最长为4秒(1速)、最短为0.35秒(12速),速度约为11.4倍。下落速度决定了音符何时进入画面,只有已经出现在画面中的音符才可以参与到判定过程中,即使音符判定时间范围为无穷大也不可以盲点还未进入屏幕的音符。
3.3 音符状态机
为了控制音符从初始化到消失的生命周期,游戏需要一些方法来管理各个音符,给予每个音符高度定制化的状态便是一个非常好的选择,这些状态之间可以根据预设的条件进行转移,并可以画出直观的状态转移图。
例如,如果要设计一个需要点击3次才能完成判定的音符,可以画出如下状态转移图:
在状态转移图上,圆圈代表状态、有向弧代表状态之间的转移,有转移条件并可以在转移时执行一些操作(比如进行判定)、从空白地方指向的状态代表初态(上图中的“等待”)、同心圆代表终态(上图中的“结束”)。到达终态后,一般认为音符的生命周期已经结束,不应该再进行进一步的操作。这样的数学模型也被称为“有限状态自动机”(简称“状态机”)。
3.4 音符判定过程
为了实现上文所述的状态机,在游戏主循环中每次判定处理时,需要根据音符原始状态、当前条件(比如时间、触摸事件等)确定音符的新状态,并在状态转移过程中执行进入画面、判定等操作。
这样的操作需要遍历当前可用(可以进入画面、未进入终态)的音符。工程上除了从第1个音符开始遍历以外,还可以使用链表加快遍历速度:将音符按时间排序后放入链表,进入终态后从链表中删除,遍历时从链表头开始,当音符超过“当前时间+下落时间”后结束遍历。还有一个更为简单的实现方式也能达到不错的性能:将音符按时间排序后,从第一个非终态的音符依次向后遍历,如果这个音符也到达了终态则更新这一位置,以此类推直到超过显示范围。
《Project SEKAI》在每一帧执行的音符判定过程主要如下:
预处理音符:遍历可用音符,根据当前时间,为音符完成进入画面、离开画面等与触控无关的状态转移
检查音符判定时间:遍历可用音符,如果当前时间在音符判定范围内,就将这个音符放入可分配给触摸事件的音符列表
为触摸事件分配音符:遍历触摸事件,根据触摸轨道位置、触摸阶段等信息,主要检查触摸阶段是否符合当前状态的要求,以及触摸轨道位置是否离音符过远(不同音符类型宽松程度也不一样)。通过检查后为触摸事件分配对应的音符,如果有多个可用判定的音符,则取到达时间最近的音符,如果仍然有多个则取距离最近的音符。1个触摸事件最多只能对应1个音符,1个音符可以有多个触摸事件与之对应
对触摸事件所对应的音符进行判定:遍历触摸事件,寻找离音符中心距离最近的触摸事件,使用这一触摸事件和当前时间判定对应的音符,判定也会导致音符状态的变更。然后给剩下的触摸事件重新执行分配音符,然后继续这一过程
举几个例子方便读者理解,下图的红点代表触摸位置,假设在音符边缘触摸的位置均符合音符要求:
这几种情景下的触控事件分别起到如下效果:
情景1:下方的音符更早出现,触摸事件将用于下方音符的判定
情景2:触摸位置离左侧的音符较近,触摸事件将用于左侧音符的判定
情景3:虽然一开始会将2个触摸事件均按最近距离分配给左侧音符,但优先判定离音符中心最近的左侧触摸事件,左侧音符判定完成后,会将右侧触摸点重新分配给右侧音符完成判定
参考资料
多点触控协议 - Linux 内核文档(英文):https://www.kernel.org/doc/html/v4.16/input/multi-touch-protocol.html
触摸设备 - Android 开源项目:https://source.android.com/devices/input/touch-devices
MotionEvent - Android 开发者(英文):https://developer.android.com/reference/android/view/MotionEvent
MonoBehaviour-Update() - Unity 脚本 API:https://docs.unity.cn/cn/2019.4/ScriptReference/MonoBehaviour.Update.html
Input-touches - Unity 脚本 API:https://docs.unity.cn/cn/2019.4/ScriptReference/Input-touches.html
UnityEngine.Touch - Unity 脚本 API:https://docs.unity.cn/cn/2019.4/ScriptReference/Touch.html
TouchPhase - Unity 脚本 API:https://docs.unity.cn/cn/2019.4/ScriptReference/TouchPhase.html
结语
需要说明的是,操作系统相关内容参考了Android的实现,它在操作系统开发方面提供了较为全面的文档与源代码。期待更为专业的玩家编写更详实的解析。
相关文章:

音游判定原理详解——从触摸屏幕到判定音符【Project SEKAI攻略】
“音乐游戏”一般简称为“音游”,玩家需要配合音乐的节奏来进行一定的动作。 《Project SEKAI》作为一个“移动端音游”,绝大多数玩家会使用手机、平板电脑等移动设备的触摸屏进行游玩,也有极少数的玩家不按常理出牌,使用手台、键…...

【论文阅读】Self-Paced Boost Learning for Classification
论文下载 bib: INPROCEEDINGS{PiLi2016SPBL,title {Self-Paced Boost Learning for Classification},author {Te Pi and Xi Li and Zhongfei Zhang and Deyu Meng and Fei Wu and Jun Xiao and Yueting Zhuang},booktitle {IJCAI},year {2016},pages {1932--1938} …...

通过CSIG—走进合合信息探讨生成式AI及文档图像处理的前景和价值
一、前言 最近有幸参加了由中国图象图形学学会(CSIG)主办,合合信息、CSIG文档图像分析与识别专业委员会联合承办的“CSIG企业行——走进合合信息”的分享会,这次活动以“图文智能处理与多场景应用技术展望”为主题,聚…...

流程图拖拽视觉编程--概述
一般的机器视觉平台采用纯代码的编程方式,如opencv、halcon,使用门槛高、难度大、定制性强、开发周期长,因此迫切需要一个低代码开发的视觉应用平台。AOI缺陷检测的对象往往缺陷种类多,将常用的图像处理算子封装成图形节点,如抓直…...

深度学习中的卷积神经网络
博主简介 博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的,…...

vue3的介绍和两种创建方式(cli和vite)
目录 一、vue3的介绍 (一)vue3的简介 (二)vue3对比vue2带来的性能提升 二、vue3的两种创建方式 方式一:使用vue-cli创建(推荐--全面) 操作步骤 方式二:使用vite创建 操作步…...

camunda工作流user task如何使用
在Camunda中使用User Task通常需要以下步骤: 1、创建User Task:使用BPMN 2.0图形化设计器(如Camunda Modeler),将User Task元素拖到流程图中,并为任务命名,指定参与者(用户或用户组…...

三元运算符
三元运算符 三元运算符通常在Python⾥被称为条件表达式 这些表达式基于真(true)/假(not)的条件判 断 在Python 2.4以上才有了三元操作。 下⾯是⼀个伪代码和例⼦: 伪代码: 如果条件为真,返回真 否则返回假 condition_is_true if condition else c…...

Vue3 Element-plus el-menu无限级菜单组件封装
对于element中提供给我们的el-menu组件最多可以实现三层嵌套,如果多一层数据只能自己通过变量去加一层,如果加了两层、三层这种往往是行不通的,所以只能进行封装 效果图 一、定义数据 MenuData.ts export default [{id: "1",name…...

( “树” 之 BST) 669. 修剪二叉搜索树 ——【Leetcode每日一题】
二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。 二叉查找树中序遍历有序。 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&…...

【C语言】浅涉结构体(声明、定义、类型、定义及初始化、成员访问及传参)
简单不先于复杂,而是在复杂之后。 目录 1. 结构体的声明 1.1 结构体的基础知识 1.2 结构的声明 1.3 结构成员的类型 1.4 结构体变量的定义和初始化 2. 结构体成员的访问 3. 结构体传参 1. 结构体的声明 1.1 结构体的基础知识 结构是一些值的集合&…...

设计模式-结构型模式之装饰模式
3. 装饰模式 3.1. 模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制 使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能…...

【Chatgpt4 教学】 NLP(自然语言处理)第九课 朴素贝叶斯分类器的工作原理 机器学习算法
我在起,点更新NLP自然语言处理》《王老师带我成为救世主》 为啥为它单独开章,因为它值得,它成功的让我断了一更,让我实践了自上而下找能够理解的知识点,然后自下而上的学习给自己的知识升级,将自己提升到能…...

基于html+css的图片展示17
准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…...

Jupyter Notebook小知识
目录 1 快捷键1.1 常用快捷键1.2 魔法函数 2 常用快捷键2.1 模式切换2.2 命令模式快捷键2.3 编辑模式快捷键3 Matplotlib绘图 4 小技巧4.1 文件默认目录的查看以及更改4.2 更改主题颜色 5 其它5.1 python中 r, b, u, f 的含义5.2 f/format():格式化操作 6 常见问题6.1 查看模块…...

redis原理及进化之路
Redis 的主从复制经历了多次演进,本文将从最基本的原理和实现讲起,并层层递进,逐步呈现 Redis 主从复制的演进历史。大家将了解到 Redis 主从复制的原理,以及各个改进版本解决了什么问题,并最终看清 Redis 7.0 主从复制…...

ai智能写作助手-ai自动写作软件
为什么要用ai智能写作工具 在数字化时代,AI(人工智能)技术已经被广泛应用于各种领域,其中之一是写作。AI智能写作工具是利用自然语言处理技术和机器学习算法来生成高质量的文章、博客、新闻稿等。这些工具不仅提供了便捷、高效的…...

redis持久化
redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)。那么这两种持久化方…...

Vue项目基于driverjs实现新用户导航
引导页就是当用户第一次或者手动进行触发的时候,提示给用户当前系统的模块介绍,比如哪里是退出,哪里是菜单等等相应的操作。 无论是开发 APP 还是 web 应用,新手引导都是一个很常见的需求,一般在这2个方面需要新手引导…...

自编码器简单介绍—使用PyTorch库实现一个简单的自编码器,并使用MNIST数据集进行训练和测试
文章目录 自编码器简单介绍什么是自编码器?自动编码器和卷积神经网络的区别?如何构建一个自编码器?如何训练自编码器?如何使用自编码器进行图像压缩?总结使用PyTorch构建简单的自动编码器第一步:导入库和数…...

redis单机最大并发量
redis单机最大并发量 布隆过滤器多级缓存客户端缓存应用层缓存Expires和Cache-Control的区别Nginx缓存管理 服务层缓存进程内缓存进程外缓存 缓存数据一致性问题的解决引入多级缓存设计的时刻 Redis的速度非常的快,单机的Redis就可以⽀撑 每秒十几万的并发,相对于MySQL来说,性…...

MTLAB绘图
这里写目录标题 一、图例1、散点图 二、绘图1、总体图形参数2、坐标、图框、网格图框去上右边框小刻度网格坐标范围和刻度控制旋转 坐标、刻度 3、图例图例位置和方向 Location和Orientation图例加标题 、分多列 4、文本 字、字体、字号5、线型 符号6、颜色栏 colorbar7、颜色8…...

自媒体必备素材库,免费、商用,赶紧马住~
自媒体经常需要用到各类素材,本期就给大家安利6个自媒体必备的素材网站,免费、付费、商用都有,建议收藏起来~ 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库可以找到设计、办公、图片、视频、音频等各种素材。视频素…...

ESP32设备驱动-BMP388气压传感器驱动
BMP388气压传感器驱动 文章目录 BMP388气压传感器驱动1、BMP388介绍2、硬件准备3、软件准备4、驱动实现1、BMP388介绍 BMP388 是一款非常小巧、低功耗和低噪声的 24 位绝对气压传感器。 它可以实现精确的高度跟踪,特别适合无人机应用。 BMP388 在 0-65C 之间的同类最佳 TCO,…...

攻防世界-Reversing-x64Elf-100
Reversing-x64Elf-100 18最佳Writeup由 yuchouxuan 提供 收藏 反馈 难度:1 方向:Reverse 题解数:15 解出人数:2460 题目来源: 题目描述: 暂无 note:undefined8 FUN_004006fd(long param_1){int local_2c;char *local_28 …...

C/C++每日一练(20230419)
目录 1. 插入区间 🌟🌟🌟 2. 单词拆分 🌟🌟 3. 不同路径 🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日…...
[自注意力神经网络]Mask Transfiner网络-论文解读
本文为CVPR2022的论文。国际惯例,先贴出原文和源码: 原论文地址https://arxiv.org/pdf/2111.13673.pdf源码地址https://github.com/SysCV/transfiner 一、概述 传统的Two-Stage网络,如Mask R-CNN虽然在实例分割上取得了较好的效果ÿ…...

漫画:是喜,还是悲?AI竟帮我们把Office破活干完了
图文原创:亲爱的数据 国产大模型烈火制造。阿里百度字节美团各科技大佬不等闲。 大模型嘛,重大工程,对我等“怀保小民”来说,只关心怎么用,不关心怎么造。 我来介绍一下自己,我是一个写稿男团组合的成员&am…...

ChatGPT的原理分析
1.前言 ChatGPT是一种基于自然语言处理和人工智能技术的聊天机器人,它的基础是由OpenAI研发的GPT模型,其中GPT是Generative Pre-trained Transformer的缩写。GPT模型的训练使用了海量的语料库,可以预测下一个单词、短语、句子或文本…...

在线免费把Markdown格式文件转换为PDF格式
用CSDN的MarkDown编辑器在线转换 CSDN的MarkDown编辑器说实话还是挺好用的。 导出PDF操作步骤,图文配合看: 在MD编辑模式下写好MarkDown文章或者直接把要转换的MarkDown贴进来; 使用预览模式,然后在预览文件上右键选择打印&…...