环球今日讯!【翻译】音游开发速成:背景音轨(作者:5argon)

时间:2023-07-02 02:15:51       来源:哔哩哔哩

【文章原载于/native-audio/rhythm-game-crash-course/,授权翻译转载,再次转载请联系原作者获取授权。】


(资料图)

【系列文章目录】

音游开发速成(概论)

背景音轨【本文】

游戏设计与制谱

四类音频应用程序

音频导入设置

与DSP同步

来自Bemuse作者的提示

背景音轨

在这一大节中我们将讨论如何播放背景音轨!(剧透:这可不只是。)这个任务给人一种很简单的错觉,因为其中的数学计算看起来是非常非常简单的加减法,但它将使您大伤脑筋。我甚至不确定本文能否给除我以外的其他人讲明白。

您的接收器运行在“时间”上

接收器是指向前运动的判定线,或者反过来说是Note落到它上面,这取决于您如何看待。本文中我假定接收器以时间为单位,并且它会根据增量时间(delta time)逐帧自增。在此基础上,把“接收器时间”看作该接收器的一种“位置”,而其他位置参数都不会被转换为时间。这样做的优势在于可以在整个游戏中通过增加增量时间来驱动游戏前进。我不知道您目前用什么来代表歌曲中的“位置”,请随意转换本文的定义来适应您的定义,而不是将游戏调整成与本文相同的单位。

接收器时间将用于:

判定:在您检测到输入的那一帧中,您可能需要将当前的接收器时间和每个受影响的Note的时间相比较,从而判断您是否应当为这些Note计分,以及使用什么判定结果来计分。

渲染:举例而言,您的接收器时间是 s,而某个Note在 s。您可以将渲染逻辑实现为:当接收器在2 s时,这个Note应当比之前距离更近。(这就是您所感知到的“Note落在接收器上”,但实际上是接收器在向前运行。)

这里并没有请求音频位置来设置接收器时间。接收器时间的变化只基于增量时间。正如您已经阅读过的内容:请求音频时间并不可靠,我们从扬声器听到的内容很可能早于音频DSP时间,并且音频DSP时间以难以捉摸的步骤进行更新,甚至会在接下来的几行代码内发生改变(抑或不变)。

更好的做法是只在一个关键时刻(即音乐开始的时刻)上确保游戏和音频时间相同步,然后任它自行前进。如果缓存超载/欠载导致音频卡顿,或游戏卡顿导致音频超前,那也就不管了。这比让整个游戏基于音频时间要好得多!请将您的整个游戏建立在增量时间上。

您的任务:从任意接收器时间开始游玩

您当然可以从头启动歌曲,但请记住,您的游戏可能可以暂停和恢复,甚至可能有一个可以从任何位置开始“测试游玩”的制谱器。此处的“播放背景音轨”功能应当能够处理当前接收器时间在任何位置的情况。以常规方式开始游戏只意味着将接收器移动到一个负数时间,然后启动这个我们正在摸索和实现的奇妙功能。

PlayScheduled:请尊重这个方法

Unity内置的PlayScheduled有一个连Native Audio也做不到的优势:准确性(不是指延迟准确,也不能即时响应)。您可以指定一个未来的时间,它将努力在那时启动音频(您依然可以预先将音频设置在任何位置,之后它将从那个时间点开始播放)。

任何您可以提前预知到的音频都应当以此播放,如背景音轨、自动播放的辅助音效、节拍器等。

预定(schedule)的特殊性在于它独立于帧。如果您指定的时间在帧的内部,音频也能按时播放。这是什么神奇技术?帧是Unity引入的一种抽象概念,而原生端通常支持更紧凑的回调或一些帧以外的东西(如果您从事过微控制器或Arduino等设备的开发工作,您可能听说过“中断”信号,它能让您瞬间触发一些东西)。Unity有一些平台专用代码来对接本地的音频预定方法。PlayScheduled实际上比它看起来更有价值。

您在update函数中等待并于正确时间点播放的天真方案总是会比真正想要的时间点更晚,因为无法确保帧时间精确地落在想要的时间点上。您可以假设在完美的情况下,下一帧会在1/60秒后到达,这是您可以实现的最大精度。

使用预定方案引入了新问题,即播放必然发生于未来。这会对我们造成什么影响?

暂且假设延迟为0

为保证思路清晰,让我们先假设音乐将在PlayScheduled上指定的时间点立即而可靠地播放。

修正超时

请先考虑一个简单情况:您的接收器位置是0 s,并且您想从此处开始。此时您想要听到的是哪些音频数据?

当然是音频文件0 s处的数据!也就是说如果下一帧将接收器位置移动到 ms,那么您想在那时听到音频 ms处的数据。所以歌曲应当从接收器时间的0 s处开始。(即没有偏移量,本文将在稍后讨论这个问题)

但是请等一下,我们有“播放必须发生在未来”的规则,而这一帧中我们刚刚收到了播放指令,那么我们怎么可能在此时听到文件中0 s处的音频数据呢?

请考虑这种策略:

将音频时间设置为0 s。

然后预定在当前时间后的2 * ms处开始播放音频(我认为游戏可以在2帧时间内准备好音频)。请记住预定时间以DSP时间为单位,例如本行代码处您请求了DSP时间并得知它是20000 ms,那么您应该“期待”的播放时间是20033 ms。PlayScheduled接收的也是DSP时间轴中的时间点,因此您应该传入20033 ms。

请不要立刻开始您的游戏!正确的计划是在20033 ms时开始游戏。

两轮更新结束后,您再次检查DSP时间,其结果可能是:

20033 ms(实际上极不可能):太幸运了!您现在听到的是0 s处的音频,而接收器当前的位置也是0 s。这一帧中您不会在接收器位置上增加增量时间,因为目前的位置是正确的,而之后的每帧中您将持续地在接收器位置上增加增量时间。增量时间与音频时间无关,但是您寄希望于从现在开始音频时间会与您加到接收器时间上的增量时间保持“远程同步”。至少您已经实现了一个非常好的开始!

20018 ms(糟糕):音频播放的预定计划已经向前推进,只是目前还没有开始播放。但下一帧可能就已经开始播放了,而您的代码错过了这个时间(比如那时可能已经是20041 ms了)!但是目前已经预定的音频还没有开始播放,所以您在音频开始前还有最后的机会来执行一些代码。一个显然的选项是使用StopScheduled取消并尝试重新预定,但这可能产生无限循环。因此我建议让这一帧过去,看看下一帧的情况。

20041 ms(糟糕):音频已经开始播放,并且没法停下来!如何解决呢?对于这一帧,可以增加一个代表超时时间的特定增量时间,即20041 - 20033 = 8 ms。请记住,如果两帧的用时是精确的(第一种情况),我们不会在这一帧上为接收器时间增加增量时间,因为此时接收器时间已经是正确的时间了。增加特定增量时间意味着您的游戏会在这一帧上奇怪地向前移动一点,而下一帧就可以像往常一样持续增加约为1/60 s的增量时间了,并且也要寄希望于“远程同步”(和第一种情况相同,已经解释过了)。

使用这种策略可以通过修正超时来规避“预定”只适用于音频的事实限制,Unity没有“ExecuteCodeScheduled”这种方法来让您在想要的时间点启动游戏。接收器也和音频一样以时间为单位,这使得您可以在自己的方案中使一些小手段,游戏循环会给您机会来强行前移接收器以实现时间匹配。这是您所拥有的唯一一个精确的修正机会,因为您为PlayScheduled方法指示的预定时刻是20033 ms,而目前比那个时刻稍晚一点,并且您知道我们具体晚了多少。我将那个预定时刻称之为NOW!时刻

而未来各帧的同步情况都由增量时间和DSP时间的命运决定。(还取决于玩家的听觉是否能捕捉到游戏和音频间的错位,如果玩家并不在意准度那就更好了。)

从暂停中恢复会怎么样

当游戏暂停时,您并不会将AudioSource暂停(pause),而是完全将之停止(stop)。当玩家点击恢复按钮的那一帧中,我们要将先前说过的事情重做一遍。区别在于当玩家想要再次开始游玩时,您需要将播放头时间事先设置在当前接收器位置上。

这是一种实现暂停和恢复的好方法,因为此时我们可以修正DSP时间和实际接收器时间的任何错位,后者是判定和渲染的依据。我们重做了一次“修正超时”工作,又得到了一次确保二者精确同步的机会。

在歌曲之前开始游戏会怎么样

音频可能在接收器时间的0 s处开始,但您酷炫的UI上有一段先导动画和“READY?”字样。您或许会希望在屏幕上出现“READY?”字样时Note也同时滚动(或在背景中看到一个空白的游戏区在不断滚动)。

解决这个问题只需简单地根据先导动画的长度将接收器时间设置为负数即可。但有一点不同:当从暂停中恢复时,您需要事先将音频时间提前。然而目前您无法事先将音频时间提前到一个负数,最小值是0 s。

没错,您必须在使用预定方法PlayScheduled时加上这个“提前量(under-time)”,并事先将音频设置在0 s(这是它能被设置到的最小值)。

这意味着预定播放将被推后一大段,NOW!时刻被推后一大段。游戏在每一帧中都检查DSP时间,那么最后应该有一帧中返回的DSP时间会稍稍超过我们预定的时间。

区别在于我们需要在NOW!时刻前持续逐帧增加增量时间,从而使游戏在显示“READY?”字样时滚动。在检测到的DSP时间超过了预定的DSP时间的那一帧中,完美的做法是不向接收器位置上增加增量时间,而是将之设置为:与预定的DSP时间相对应的接收器时间,加上当前的DSP时间和预定的DSP时间之差。【译注:此处描述相对混乱,请对比前文20041 ms情况进行理解,原文为:This frame where you detected DSP over your scheduled DSP time, it would be perfect if you rather not add delta time to your receptor position, but set the receptor position to an equivalent time of the DSP time you scheduled plus the difference.】此处的“设置”意味着无论当前接收器位置在哪里(应当在附近),都会跳转到您想要的时间。

这会产生一些副作用:一些设备差但眼力好的玩家将会注意到游戏向前或向后跳了一点,来补齐歌曲开始的NOW!时刻和过往帧的不一致。如果这附近没有Note,那可能就不是什么问题。无论如何,大部分歌曲在开始其音频内容时,屏幕上是没有任何Note的。我认为确保与音乐的同步性值得我们对接收器时间做这样的微调。

您已经考虑了所有情况!您甚至可以在游戏还在显示“READY?”字样时将之暂停和恢复,游戏依然会在歌曲真正开始播放前以恰当的方式等待,因为您对该问题的处理方案已经具备足够的普遍性。

偏移量

在上一节中我们假设当接收器时间为1 s时,您想听到1 s处的音频。

但这种情况并不常见。音频文件的开头往往有一段无声部分,或者有一些前奏内容让您宁可向前或向后移动一些,从而使第一声镲落到您写在2 s处的那个Note(小知识:此处正是120 BPM的4/4拍歌曲的第二小节,因为一拍是 s)。这是音频文件具有的偏移量,可能适用于所有谱面难度。

所以您只要在做各种事情前加上这个时间就可以了。例如偏移量显示歌曲延后了4 s,但游戏在0 s时精确启动【译注:可能是作者笔误,原文为“歌曲在0 s时精确启动”,无法读通】,或者玩家可能在 s时暂停了游戏(被蚊子咬了)。这将会把情况转化为“在歌曲之前开始游戏”,您必须把“提前量”加到预定时间中,这在之前已经解释过了。

负偏移量的做法也是相同的,如果歌曲的偏移量为负数,那么在0 s时您已经听到了歌曲的某些内容。

偏移量通过前后移动歌曲来解决“在当前接收器时间下我们应该听到歌曲的哪一部分?”这个问题,其正值和负值都有意义。或许您真的希望让歌曲的5 s处落在第0小节上,这需要您将歌曲移动到更早处。(或者调整谱面,让Note从更晚的位置开始,而非从第0小节开始。)

您可能为了播放动画和“READY?”字样而在游戏开始时将接收器时间移动到负值,但请确保在实现这个效果时也考虑到歌曲偏移量。即用偏移量作为计算开始时间的被减数,而不是从0 s做减法计算。否则一首将偏移量移动到很晚处的歌曲会导致在显示“READY?”字样和游戏真正开始之间存在过长的间隔。

玩家可调的“校准

有时称作“输入校准”,有时称作“音频校准”,又或是“调整延迟”?

延迟补偿

请您先认可我的这一观点:负延迟是没有意义的。延迟说的是音频播放晚于预期。因此如果您要求补偿 s延迟,那么所有可以提前计划的东西(您已经被迫将之提前过了,从而满足我们的未来预定规则)都需要再提前 s,这让它们可以经由延迟回到正确时间。

延迟的定义使得“我想要- s的延迟补偿!”这一想法是没有意义的。

当从暂停中恢复时(假定我们已经进入了歌曲),您知道有几帧是不会移动接收器时间的,因为我们正在等待NOW!时刻。但现在您必须在检测到DSP时间超过所承诺的NOW!时刻后继续等待,这样您才能修正超时问题并最终让游戏继续。简单地说,就是在预定时间的基础上再加上和所补偿的延迟相等的时间(请不要直接加到预定时间中,只是让游戏在到达预定时间后多等一小会儿就好)。

在前面的例子中,我们等待的是20033 ms位置。假设您已经到达了DSP时间为20035 ms的那一帧,但延迟补偿被设定为10 ms,因此即使您知道预定的音频已经开始播放,但本帧仍然不该为接收器时间上增加任何东西。相反,您需要再等一帧(或多帧),让DSP时间的读数达到20055 ms(例),之后您通过比较20055和20043(而不是20033)来修正超时【译注:可能是作者笔误,原文为“比较20055和20045(而不是20035)来修正超时”】。

在比较极端的情况下做这种修正可能会出问题,想象一下这种情况:玩家将延迟补偿调得很大,比需要的量多出很多。从暂停中恢复后,玩家将听到音乐开始播放,但游戏内容并没有开始移动!这显然是很奇怪的,玩家调整延迟补偿的目的是在游戏内容开始运动时精准地听到歌曲开始播放。

这是利用暂停情况下接收器的静止状态来修正延迟问题带来的副产物。我们能否以某种方式解决这个问题?

您可以通过增加一个恢复倒计时来解决这个问题,而且您必须确保这个倒计时比玩家可调整的最大延迟补偿还要长。(所以您可以锁定选项界面中的最大延迟调整范围,比如说锁定为3 s。)这使得静止的等待时间变得更自然,因为您可以在倒计时中遮住游戏画面。(在倒数到0之前,就已经到预定的播放时间了。)

您可以将接收器后退(到时间更早处)来补偿延迟。然而这会导致一个可利用的漏洞,即玩家可以通过反复暂停和恢复游戏来使接收器持续后退。有些游戏将之作为玩家游戏体验(QoL)的一部分,例如DJMAX Respect不但增加了倒计时,甚至还会为您倒退时间。您可以在倒退时间的过程中掩盖延迟。

您可以让接收器在恢复游戏后才开始向前运行,然而您可能被迫需要以静音状态播放一小段歌曲!为什么呢?因为静音播放的那一部分实际上是我们的垃圾Android设备将音频最终播出到我们的耳朵中所用的时间。当预定播放时间到达时,音乐还在以静音状态播放,因此当音乐最终重新出现时所播放的歌曲段落也会比您暂停时所在的段落更靠后一些,因为您为了在不发生奇怪停顿的前提下完成延迟补偿而将其作为“代价”。实现这种方案需要您故意事先将音频位置向未来移动,到比想要矫正的延迟更靠前的位置,并通过PlayScheduled让它准确地回到正确状态,(换句话说,每次您暂停并恢复后,暂停点前方的那一点歌曲就再也听不到了,因为音频会被向前调整一些来对齐静音播放部分的末尾。)这种情况中,在歌曲播放时不会因校准错误而出现奇怪的暂停,但是过度校准会让音乐在静音状态下播放更久。【译注:原文对该方案的描述较难理解,建议阅读时通过画图梳理思路,或先阅读后文中对该方案的详细介绍。抛开原文中引入的“静音播放”这一概念,以如下思路理解可能会更清晰一些:为了不让音乐实际播出时间早于谱面运动时间 → 所以在谱面开始运动的那一帧(或之后)才下达播放音乐的指令(而非预先下达) → 由于延迟,实际听到音频时,谱面已经向前方运动了一段,因此需要预先将音频的播放位置向前方调整一些,才能让听到的音乐和谱面对齐。这里音频需要向前调整的最小值就是玩家设置的延迟补偿值,因此作者将这一段音频内容损失称为补偿延迟的“代价”。】

我更推荐最后一个方案,因为玩家很可能在暂停恢复后将注意力集中于移动中的Note上(使用“视力”而不是耳朵来读谱),所以这种方案可能好于音乐开始重新播放而Note还没有移动起来,也好于接收器位置被自行拽到另一个地方。

如何实现以静音状态播放

在您决定从某个接收器时间开始游戏后,您所听到的内容并非由当前时间决定,而是由向未来方向的校准时间决定。

假定您的接收器在2000 ms,延迟补偿为0 s,偏移量为500 ms。通常情况下您会想要在此刻听到1500 ms的音频,但实际上您需要将等待中的音频时间设置为 ms而非1500 ms(核心区别就在于此)。

接下来,在开始播放的那一帧中尽可能早地请求“当前DSP”,此时请求的结果与我们所依赖的增量时间一致性最强。(请记住DSP时间会在您每次请求间发生变化。)将 ms处的音频预定在当前DSP + ms时开始播放。这一帧中我们不会对接收器时间做任何处理,此处的“不做处理”只有当我们设法在该帧的最开头请求DSP时间(尽可能接近实际的帧时间)才有意义,所以我们准备在下一帧做一些处理并期望增量时间和DSP时间同步前进。

在下一帧中,我们将增量时间加到接收器上(这意味着游戏的游玩过程已经开始,现在需要打开判定和其他所有内容)。回想一下之前的方案,我们不断检查DSP时间,直到它超过DSP + ms时才真正开始移动接收器,然后我们会修正超时。但当前方案中音频已经被前推,所以我们可以立刻开始移动接收器。在本帧中,DSP时间可能是 ms左右,并没有到达预定时间( ms大约是2帧),但我们已经“在静音状态下播放”了!(您可以在这段静音时间中接到或错过Note)当最终到达预定时间时,DSP时间将位于我们以静音状态播放到的时间。这 ms的音频内容完全消失了,就好像他们在静音期间以0音量播放,然后突然恢复了正常音量。

现在让我们试着在这一团乱麻中加入100 ms的延迟补偿。(请记住,负延迟是没有意义的)将音频时间设置为16 ms,但仍然预定在DSP + ms时间点播放(这依然是可以让PlaySchedule正确工作的最小时间)。此时预定的播放行为依然发生在旧的时间点上,但垃圾Android设备的延迟让音频更晚播出,我们将在静音状态下播放更久。但是当音频播放出来时,可以看到音频的位置在 ms而不是 ms。音频当然会因延迟而更晚播出,但音频的位置已经被前推以抵消延迟,计划通。

这里需要注意一件非常重要的事:无论什么情况下(指延迟补偿、接收器时间和偏移量的取值),预定的播放时间似乎都固定为当前DSP + ms。这是因为我们将一切其他问题都用推后音频时间(并且忍受静音播放)来解决,而我们对预定播放的唯一需求来自PlayScheduled正确工作所需的未来时间。(请告诉我您在此时已经完全理解并点头认同,否则您可以试着喝点含糖饮料后再来阅读这篇文章)。稍后我会揭示这并非100%正确(哈哈),但注意到这一点很有用。

额外内容:您注意到了当预定时间到来时,接收器已经提前运行了起来。而我们仍然可以融合“超时修正”方案,不断询问DSP时间直至其超过预定时刻,并在此时如先前一样微调接收器时间。(不同点在于此时接收器时间已经在运行,被推后的音频时间反而在等待。延迟使得我们在进行微调的时刻依然听不到任何内容。)如果您更倾向于让接收器流畅运行或害怕玩家会感受到接收器时间的跳转(这会影响渲染),您可以跳过这个部分。与先前不同的是,我们在先前方案中并没有使接收器运动起来,所以有可能在静止状态中完全掩盖“修正”过程。而现在这里变成一个权衡点:您是否愿意在这个唯一确定的时刻修正它,而付出一点连续性为代价?这取决于设备的糟糕程度。如果您选择不修正,那么即使是最差的设备也能在预定时刻流畅地继续游戏,但缺失修复使游戏时间存在偏差。

现在让我们考虑这样一种情况:计算结果要求“听到”的音频位置为负数。如果接收器位置在200 ms,偏移量为500 ms,那么我们现在想要听到的音频时间为-300 ms,这显然没有什么实际意义。真实情况是音频被偏移到了未来,以至于200 ms的接收器位置下音频还没有开始。或者反过来说,偏移量使得当前的接收器时间过于靠前,从而进入了负数时间的范围内而不是在音频的开头。

如果我们和先前一样计算,则音频时间会被设置在 -300 ms + ms + 延迟。这可能仍然是个负值……或者当延迟补偿设置得比较大时可能会是正值。我指的是接收器时间 – 偏移量 + ms(最小未来时间) + 延迟的计算结果是负值的情况。如果您能计算出正值,那么可以像之前那样处理。问题在于我们并不能事先将等待播放的音频时间设置为负值,必须要做一些其他工作来解决。

这就是我让您留意的那个“并非100%正确”的东西:固定为当前DSP时间 + ms的预定播放时间!这种情况不正是可以被视为“仍在音频播放前”吗?您要做的就是将这一段负数时间加到预定时间上,现在预定时间变为当前DSP + ms + (负数时间 * -1)。您只需要把这一段负数时间扔进去,然后立刻进行预定。这样就可以事先将音频设置在0 s处而非无法实现的负值。这里有一个陷阱,当该值为正值时不能在当前DSP + ms上再加任何量(因为这种情况通过事先设置音频时间来处理)。您可以简单地使用if来区分正负两种情况,不要冒着大脑过载的风险尝试总结出一个通用表达。

我相信您已经设计出了一个算法,可以从任何接收器时间正确地播放音频,无论正负,也无论在歌曲前、歌曲中甚至是歌曲后!(由于AudioSource并不会循环,因此若您事先设置的音频时间在歌曲结束之后,您将听不到任何内容。)恭喜您!  

请您在从暂停中恢复时设置一些延迟时间,以防玩家在预定的播放时间还未到达时再次按下暂停按钮。否则歌曲可能会在暂停界面上播放出来,或者您可以做一些工作来取消预定的播放。

其他几种“校准”

还没有结束,让我们再多讨论一些!

在许多游戏的选项界面中可以看到,它允许您通过按“+”和“-”按钮来以一种未知的单位对游戏进行“校准”。现在“校准到”和“校准到-”都具有了意义,这是什么情况呢?负数延迟不是没有意义的吗?

游戏没有直白地说明校准单位是什么,或者只是在玩家使用“+”和“-”按钮校准时显示一个由运动的小节构成的测试游戏区,正是因为这个话题太伤脑筋了。(看看本文已经写了多长,只为了播放这该死的音乐。)

第一,这些值有可能实际上是对音乐的偏移量进行增减,但有时这会导致一种延迟并没有改变的感觉。这种情况下该值的正负均有意义。如果游戏只是如此设计而不运用任何其他技巧,那么它只能在从头重启时进行补偿。一些游戏可能会尝试将正值校准转换为我们一直讨论的延迟补偿,而负值校准转换为偏移量。

调整歌曲的偏移量在一些情况下是有用的,例如当玩家不信任开发者提供的偏移量时,或者只是不同玩家对一些歌曲的听感不同,有人觉得晚了,有人觉得早了。额外提供偏移量校准也许是对偏移量出错的一种很好的兜底保障。

第二,这些值也可能是一种输入校准/判定校准。这种校准让您即使在接收器时间刚好是Note时间的那一帧上检测到输入,也无法达到完美判定,因为输入(或判定)已经发生了偏移。采用这种做法是为了帮助输入延迟较差的设备。玩家的眼力是完美的,所以他会尝试在Note真正和接收器重合的时刻点击屏幕。(该帧正是接收器时间和Note时间相同的那一帧,请记住接收器时间是如何影响渲染的。)当然,输入并不会在精确重合的这一帧中到达,而是可能在一帧后或几帧后。如果您的眼力真的很强,那么可以看到Note从接收器上移过(因为输入到达需要时间),最终程序在某一帧前检测到了输入,并且让Note消失。

但如果您将游戏设计成“在Note和接收器重合的那一帧点击”,输入将永远更晚到达。虽然我认为这是正确的设计,因为这样向玩家描述会比解释“好吧,其实您的输入稍后才能到达代码中,哈哈”要容易得多。但是您无法让Note在玩家手指接触到屏幕的那一帧中立刻消失,这些Note会不可避免地继续移动一段时间。

输入延迟为0 ms的设备是不存在的,所以如果您想让在Note和接收器视觉上重合时进行点击的玩家能获得最佳判定分数,那么您应当在默认情况下就做一些输入校准,此时接收器再向下一点的地方才是真正的最佳位置。这让游戏变得以玩家为中心(优先考虑玩家视觉所见)而非以代码为中心(代码并不关心输入多久才能到达)。

否则游戏就会变得经常被玩家评论为:“嘿,您需要在Note到达那条线之前一点的位置点击屏幕,才能得到完美判定。”这种方案也不错!因为玩家会明白不同设备的性能不同,买不起输入延迟更低的设备是他自己的问题,并且他会理解为什么他需要稍早一点进行点击。之后他就会一直提前点击。

或者您可以通过设置一些默认的输入校准来平衡这种情况,因为您知道输入延迟为0 ms的设备并不存在。但如果您不想让游戏设置包含输入校准的话,一些便宜的设备仍然需要提前点击。而提供延迟、音乐偏移量和输入三种校准有时可能显得太多且难以理解。

结语

终于结束了!您忍受我阐述了这么久,所以作为额外内容,这一部分其实是我自己的一次规模庞大的小黄鸭调试(/wiki/Rubber_duck_debugging)。如果我不把这些文字都写出来,我的思维可能永远无法超越前文向您呈现的思路中的前几个小段。这个方案只是……可以正确工作。

并且很抱歉的是后面的话题完全否定了前面的推论,但我发现如果不先经过前面的部分就无法理解最终的解决方案。本文到此结束!!好耶!

关键词: