昨晚在 iPad 上玩一个叫《变形金刚》的游戏时,遇到了一个无响应的 bug。想了想感觉可以记一下,写在这儿,对自己也是个提醒。


当把游戏放下,过段时间后从解锁屏幕恢复时,这个游戏就无法响应任何的触摸输入了,屏幕上的具体情况如下图:

transformer


有经验的开发者,光靠这个截图,应该就已经大致明白发生了什么问题了。我们简单分析一下吧:

  1. 中间的消息框,是提示会话已过期需重新登录,这一类对话框很常见。为了防止玩家在登录已经失效的情况下操作,这个对话框通常会被设计为模态的,也就是所有其它的界面响应都会被它拦截,只有“确定”那个按钮能响应用户操作。
  2. 而在屏幕下方,呈现的是一个标准的新手引导提示——所有的界面元素全部被遮挡,只有屏幕下方正中间的“剧情”按钮被高亮提示。

明白了各自的作用,理解这个“全屏无响应”的现象就很容易了——它们俩不约而同地觉得自己是全屏__唯一__该被响应的元素,其他所有元素都得被拦截。结果就是它们互相把对方给拦截了,谁也响应不了,整个游戏就死锁无响应了。


原理说明白,解决方案就很简单了。

  • 首先,最简单的方案是,设计上__显式指定响应的优先级__。如让失效提示总是比新手引导更“高”,也就是弹框能无视新手引导的屏蔽(或反过来)。对代码做最小的修改,让他们彼此不冲突即可。(方案A)
  • 其次,稍复杂的方案是,让模态对话框和新手引导使用同一种机制去做屏蔽全屏触摸的操作,而通过那种机制去保证多个独占的界面元素同时发生时不会产生冲突。比如在有的操作系统上,当屏幕上已有一个未处理的模态对话框而又弹出一个时,原有那个会临时隐藏,待新的那个响应之后,原有那个会又弹出来,也就是一个__“栈(stack)”的串行机制__。这个机制的好处是,再有新的独占元素加入,也很容易纳入支持,代码里可以以统一且一致的方式处理。(方案B)
  • 最后,针对新手引导的特点,还有一种做法可能会让代码逻辑更简单和清晰——当新手引导中高亮独占的元素时,总是按照那个元素的区域在屏幕上的一个特定层生成一个隐形的新按钮。当玩家触摸时,总是把触摸事件由这个隐形按钮转发给对应的元素。这么做看起来是把事情复杂化了,但实践中往往能简化问题,因为跟那个被独占的目标按钮 (可能出现在 UI 场景树的任意层次上) 不同,总是临时创建新按钮,可以保证新手引导的所有交互始终发生在指定的那一层,极大地降低了新手引导与其他游戏机制冲突的可能性。(方案C)
    • 大家知道,新手引导通常是纵贯整个游戏的所有功能模块的,一旦管理不善,琐碎的 bug 简直层出不穷。而且如果新手引导与被引导的具体功能交互按钮耦合过紧,模块内部的修改很容易波及到新手引导。(这也是新手引导往往都是项目后期才加进来的原因,当结构还在大改时,加新手引导就是作死啊)
    • 通过一层间接性,把引导系统和每个模块的具体 UI 实现隔离开,就能降低引导系统被无意中破坏的可能性,从而提高整个项目的工程质量。

这三种方案无所谓孰优孰劣,在不同的情境下,它们都有值得被考虑和实现的理由。进度压力和图省事,往往会使得我们选择方案A,但是,只有清楚ABC各自的利弊得失,并作出符合当时情况的选择,才能在项目的不断演进中,对潜在风险的变化情况做到心中有数。


说完了这个交互的 bug,我想把话题转换一下,谈一谈作为一个普通玩家,我自己喜欢什么样的引导。这一部分非常主观,能坚持看下去的同学也挺不容易了,就随便看看吧。

相比那些全屏独占,一步一步强制引导玩家完成整个引导流程的游戏而言,我更喜欢那种不主动打断玩家的,不强制执行的,比较温柔的引导提示,用黑话讲叫__“非侵入式的引导”__。当打开一个新游戏的时候,与其被引导强制带着完成十几甚至几十步操作(这个过程有的游戏甚至长达5分钟以上),我更喜欢自己戳戳点点,看看会发生什么,这其实是一种很重要的乐趣。就好像新买了一个游戏机,我们一般不会去捧着说明书按部就班地走一遍流程(不管它印刷得再精美),而是会插上游戏抄起手柄立刻来两盘。


非侵入式的提示有很多种,比较常见的有这些例子:

non-intrusive-1.jpg

图标或按钮的右上角红点或数字——常用于新的功能开启,新的事件发生,新的消息收到,新的奖励可领,等等。

non-intrusive-2.jpg

不需要手动确认的“气泡或文字标签”——“点点这里会有奇妙的事情发生哦~~”

Medieval

中世纪的战役视角,是非常典型的温和型提示系统。注意看左边侧边栏的一竖排事件图标提醒——如果你不处理,它就静静待在那里,处理之后即刻消失。而左上角的语音和文字提示是纯被动的,完全不影响任何玩家当下做出的操作。这些小的细节交织在一起,给整个游戏营造出一种非常__温和__,__克制__,与__友善__的氛围。


总得来说,非侵入式的提示比一步一步的机械引导,对于设计者而言需要更多的思考和尝试,因为玩家和非玩家,对不同游戏类型的熟悉度,都会导致不同玩家对引导完全不同的需求。常见的是,有的玩家拿起来就能玩,他们会跳过任何提示;而有的玩家不管你怎么引导都不知道该怎么玩(无关智商)。有时,我们也许只是太久没玩一个游戏,忘了在游戏里能干些什么,应该怎么操作,而引导系统又怎么能知道我是否还记得怎么玩,啥时候想要再重温一遍哪个系统的引导呢?


一些单机游戏在这方面显然有着非常细致的考虑,它们会把游戏的玩法(和剧情的进展)以完整的百科全书 (或可交互的方式)放在一个角落里。随着游戏的展开,玩家随时可以回去查看和熟悉:

game1

《英雄传说:闪之轨迹2》里有非常完善和排版精美的百科全书式游戏机制说明。

game2

《讨鬼传·极》中玩家可以随时以新手任务的形式重温各种不同武器的玩法。

说起来,如果我们不能把引导系统设计得__那么__聪明,那不如下些笨功夫,像这些单机游戏一样,做得细致一些罢。


Gu Lu


本文遵循 Creative Commons BY-NC-ND 4.0 许可协议。

Comments
Write a Comment

Tags

游戏开发   随笔   Programming   C/C++   优化   Unity   C++   知乎   游戏设计   比特币   Unity3D   区块链   软件开发   引擎设计   系统架构   Production   idtech   中国文化   加密货币   项目管理   Bitcoin   游戏评论   资源管理   资源流水线   效率   道德经   网络   方法论   模板编程   Blockchain   Lua   Blockchain Computing   Oculus   GDC   渲染   VR   PerfAssist   Unity MemoryProfiler   BCH   经济学   信息过载   行业报告   字体   Productivity   图形   网络编程   Dice   协程   EMC   Premake   测试   中间件   Game Engine   新手引导   区块链游戏   Methodology   CI   命令行解析   goroutine   ndk   Ethereum   nanomsg   自动化   Scripting   摘录   Debugging   同步技术   cppcon   C++模板   DOOM3   技术评估   Unity GC   C++11   学习方法   Surface Pro 3   Engine Evaluation   CRT   文化   笔记   golang   图形编程   多线程   ETH   Bitcoin Cash   cppcon14   Bitcoin SV   Visual Studio   Unity Coroutine   跨语言可变参数列表   团队协作   货币   Deployment   Visual Assist   工程改进   Michael Abrash   exp   开放世界   域名   虚拟现实   系统重构   slua   遮挡剔除   完美转发   协作式调度   Modern C++   类型推导   Memory Debugging   个人成长   小故事   BTC   暴雪   产品   历史   错误处理   Unity Profiler   MOD  

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。