Relicaisland测试经验
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
游戏开发者看别人玩自己创造的作品,这种体验和自个儿每天接触这款游戏的感觉明显不同。
因为你每天都在玩同一款游戏,就会在无意识中形成一套驾轻就熟的特定玩法,只有把游戏交给新手,你才有可能发现它的动画设置、操作提示、间歇性漏洞等问题都在此时被放大了,自己和他人的游戏体验根本就是两码事。
无论你自己优化了多少回,修补了多少个漏洞,但由于你已经形成了特定的玩法,而且对这款游戏内容了如指掌,所以很容易忽视其他玩家可能遇到的问题。
这也正是玩法测试对打造一款优秀游戏极其关键的原因所在。
如果想获得更多玩法测试信息,你就得善于从中收集相关数据,并进行有效分析。
下文是我在这种操作上的一些心得。
ReplicaIsland
简单的玩法测试
我初涉这一行时主要编写GameBoyAdvance游戏,当时我们的测试很简单,就是把附近的一些孩子叫进来,人手发放一个特制的GBA,这个掌上游戏机系统与VCR相连接,这样孩子们玩一会儿游戏后,我们就能倒带查看他们的游戏过程,可以马上找出那些具有直接影响作用的漏洞。
但我们并没有留意到,这种方法并不能反映这玩家在游戏中受困的原因。
只有当一定数量的目标用户都栽倒在特定环节时,大家才会意识到这款游戏有些地方需要修改。
就这样,我们靠一帮小孩的多次配合,以及通过VCR的反复观察,极大地完善了游戏设计。
现在我是一名Android手机游戏开发者及支持者,第一款Android作品就是《小绿人历险记》,它也是一款side-scroller风格的游戏,和我十年前制作的GBA游戏并没太大区别。
不同的是,我已经不再给游戏工作室打工了,仅靠一个美工的协助,在闲暇时间一个人开发了《小绿人历险记》。
而且我也已经不再找那些孩子测试游戏了,如果非如此不可的话,我也会找一些更年长的目标用户来执行测试。
但是问题又来了,要输出玩家在手机上试玩游戏的测试信息,可真不是一桩易事。
唯一的办法就是站在他们背后看,但这种举动多少有点唐突,而且也会影响玩家的游戏体验。
面对这种情况,我一个独立手机游戏开发者究竟能怎么办?在快完成《小绿人历险记》的时候,我才意识到自己对它到底好不好玩实在没有把握。
这款游戏是在闭门造车的情况下完成的,只有让更多人试试效果,我才有信心向世人推广它。
我尝试的第一套方案就是用户问卷调查。
我将游戏投放到了一个内部网站,并向用户发送了一封电子邮件,邀请他们试玩游戏并提供反馈意见。
我甚至专门创建了一个反馈论坛,上面有针对这款游戏的一些提问。
但这种方法真是彻头彻尾的失败,虽然有许多人下载了游戏,可是只有极少数(不到1%)人愿意搭理仅有五道题的调查问卷;而这些提交了调查问卷的用户,也并没有提供什么具有参考价值的信息,我无从判断这款游戏是否难度太大,究竟是玩家控制系统、关卡设计、益智设计,还是入门引导中的哪一个环节出现了问题。
ReplicaIsland
向他人取经
遭遇这次挫折之后,我想起了NaughtyDog工作室针对《CrashBandicoot》原版本开发的玩家反馈系统。
这个系统可以将玩家在游戏过程中的相关统计资
料保存在记忆卡里,开发者可以在离线状态下对数据进行整理,查看玩家在哪个游戏环节耗时最长,哪个区域的玩家死亡率最高。
依靠这个系统提供的数据,NaughtyDog重新修改了游戏“事故频发”区域的设置,也调整了游戏的动态难度调节系统。
NaughtyDog 设计这个系统的有趣理念之一就是,无论如何都要防止游戏玩家过早败下阵来。
他们的终极目标是清除导致玩家无故被卡,不能动弹的漏洞。
我觉得这是一个很酷的主意,但不确定它在手机平台上是不是同样可行。
我问了周围一些人,打听目前的大型游戏是怎么执行测试操作的,发现有许多公司都已经有一些不同的测试方法。
但有些人告诉我,虽然他们可以搜集到很多信息,但要从中分析出有助于改进游戏设计的数据却非常困难。
还有一些工作室使用的是可以再现玩家闯关过程的分析工具,甚至可以统计出玩家最喜欢的武器、最难战胜的敌人、可视性最强的地图区位等资料。
这种搜集用户试玩信息的系统,适用于多种类型的游戏,但如果要从中获取有价值的信息,这些游戏工作室还得花费大量时间创建可以分析数据的工具。
由此可见,搜集数据并不难,难的是获取有价值的信息。
这种情况听起来很让人沮丧,因为我的目标就是让游戏测试工具越简单越好。
但我还是决定先用一些关键的参数,试试这种记录系统究竟是否可行。
当时我的Android手机没有记忆卡,但可以稳定连接互联网。
所以我想,也许可以先让系统将玩家的重要活动记录下来,发送到一个服务器,然后再由服务器输出玩家的测试信息。
我希望能用最简单的系统,获得最多的玩家信息。
ReplicaIsland
推出初级版测试系统
我编写的这个活动记录系统很简单,只有三个内容:一、在游戏运行过程中搜索玩家活动情况,并将其发送到服务器的控制流;二、服务器本身;三、负责分析服务器所记录数据的工具。
在这三者中,“服务器”最为关键。
我用PHP脚本编写了一个服务器,大约30行的代码,可以搜集针对HTTP发送的调查内容,将结果编写到 MySQL数据库中。
调查内容十分简单,仅包括:活动名称、关卡名称、XY坐标定位、版本代码、用户访问名、时间标识。
这些数据都会根据字段,逐条记录到数据库;这些数据处理也是通过PHP来完成(但从长远来看,这是个失误的决策),只有在必要的时候,才会加载一个特殊的仪表板页面。
我最先开始测试的是玩家死亡率和闯关级别。
每当一名玩家死亡或者闯过一关时,系统都会把这些活动记录到服务器。
通过这些数据,我就可以观察出玩家闯哪一关时耗时最长,哪一个环节阵亡的人员最多,哪一个难关居然轻易被攻破。
通过这些数据,我还可以统计出某一关卡上的死亡率,每名玩家的平均死亡次数。
这个系统的空间定位功能,还能帮助我判断玩家的死因,知道他们哪一次是死于敌人之手,哪一回是因陷阱而丧命。
事实证明,游戏首次植入这个活动记录系统后的效果出奇理想。
在这个初级版记录系统的帮助下,我又推出了一个游戏升级版本,继续观察相关数据,很快又发现了新问题:有一些关卡无人过关,玩家几乎立即毙命; 玩家在另外一些环节中经常被卡长达数小时(表明这个关卡设计很失败,因为按原来的设计,玩家只需要5分钟就能过关)。
有了这些数据资料,我就很清楚哪些关卡的修改工作量最大。
但仅仅找出问题关卡是远远不够的,有时候我还是不知道它们的问题出在哪里。
所以我又使用同样的数据,编写了可以监测玩家死亡位置的工具,这样我就可以通过关卡设计层看到玩家死亡率或存活率最高的区域,这个工具的初级版本是以点状分布图来显示死亡人数,后来玩家死亡率大幅上升时,我就改用热地图来显示玩家死亡分布(见下图)。
heatmap
游戏设计失误
我推出的提高玩家闯关级别、死亡监测热地图的工具,很快就取得了立杆见影的效果。
比如说,我可以从中发现大量玩家在某个关卡都死于第一个敌人之手,但并不是因为这个敌人太难对付,而是因为敌人的临空而降实在让他们措手不及,无法防范——玩家所在区位的天花板太低了,他们看不到敌人出现的方向。
另外我还发现,原先那个简单的动态难度调整系统本身就需要改进和调整。
经过又一轮死亡潮后,我让这个系统悄悄地提高了玩家的存活率和飞行能力,然后再观察数据发现,我其实早该这么做了。
我还对游戏关卡的几何设计进行了大幅度的改动。
我看到有不少关卡死亡率极低,仅仅是因为玩家在地图中迷路了。
于是我就对道路进行了重新设置,让它更加清晰明了;有时候甚至彻底抛弃整个关卡,设计一个全新的环节。
最大的问题在于游戏中的陷阱设置。
《小绿人历险记》中有许多需要玩家跃过的陷阱,但游戏虚拟人物的主要代步方式并非跳跃,而是飞行。
游戏主人公——绿色Android机器人的脚上有一个火箭飞行器,它原先的移动方式是:在地面上时要先酝酿动力,然后一飞冲天,再借助这种动力以及飞行器的力量,盘旋飞行。
但火箭飞行器的能量消耗得很快,所以机器人着陆时要补充能量。
我决定将它调整为,玩家飞升的时候,可以利用这种能量飞向遥远的平台,或者向敌人发动准确无误的攻击。
这种调整取得了良好的效果,但是我再看玩家测试数据时,又发现许多人扎堆死在无底洞中,甚至还有人会掉进极小的洞穴;死于陷阱的玩家人数仍然是居高不下,玩家的跳跃能力并没有提高。
获得这种信息后,我重新审视了游戏关卡设计,并发现了一些新问题。
最根本的原因是,玩家看不到自己必须跃过的陷阱。
首先,游戏界面中没有任何关于死亡陷阱的危险提示,而我设置的台阶又总是太高,玩家无法判断哪些坑会让自己跌到更低的级别,哪个坑会将引向万劫不复的深渊。
其次,也是最关键的一点,游戏中的摄像头运行效果并不理想,不能保证地面的可视性,当玩家向空中飞跃时,游戏界面就滚动到了屏幕顶端,导致他们无法看清路面状况,不知从何处着陆。
《SuperMarioBros》这款经典游戏的界面几乎从不采用垂直滚动方式,它有一整套严格复杂的标准,规定在哪些特定情况下,摄像机位可以上下移动。
因为《小绿人历险记》中有飞行功能设置,所以我不得不支持界面重直滚动方式。
为了改变这种现象,我又开发了一个更智能的摄像头,只有在玩家快要离开可视范围时,游戏界面才会垂直滚动。
经过这些变更,我又向玩家推出了又一个游戏更新版本,并和上一个版本的测试结果进行了对比。
结果非常乐观,玩家死亡率已经大幅下降,闯关所耗时长也在正常范畴之类,因陷阱而阵亡的人数大量减少了。
ReplicaIsland
正式发布游戏
在我的测试团队的帮助下,我对这款游戏进行了一轮又一轮的更新和调整,最后才决定正式向市场投放游戏,但仍然保留了原来的测试系统,因为我想看看系统从在线用户所搜集到的情况,与测试团队所反映的数据究竟有多大差别。
当然,任何一款手机应用向服务器发送数据时,最好都要让用户知情。
《小绿人历险记》刚发布时,首先会在游戏界面出现一个欢迎信息,并告知用户:为了完善这款游戏设计,他们在玩游戏过程中形成的匿名数据,将发送到一个服务器以便开发者了解情况,如果他们不想参与调查,可以直接关闭菜单中的系统记录选项。
看来这种方法才是最佳解决方案:它是开源代码,任何人都可以打开数据包查看其中内容(我保证这些数据不会锁定某一个特定的用户或手机ID),而且用户有权退出这项调查。
从AndroidMarket上的游戏安装数量来看,选择退出调查的用户还不到20%,也就是说大部分用户都愿意参与系统追踪调查。
我也因此搜集到了海量的数据,超过了1400万个数据点(游戏邦注:截止本文撰稿,该游戏的用户大约120万人)。
如此庞大的信息量很快就撑破了我的数据处理工具,之后还有许多工具都因此而瘫痪。
我只好截取前1万3000名玩家的活动资料进行分析,这些玩家的综合数据与小规模测试团队的信息非常接近,这表明测试团队的调查结果也适用于大规模的用户群体。
测试效果很理想
我对《小绿人历险记》的这个活动记录系统非常满意,因为它的开发非常省心省力,几乎不需要投入什么成本(服务器后端开销比申请一个 XboxLive帐号还便宜),而且只需要调查两项活动内容,我就能快速有效地找到游戏玩家的事故多发地带。
更重要的是,我通过搜集这些数据,还能和不同测试版本的统计结果进行对比,很容易就可以看出设计调整的效果如何。
使用PHP和MySQL作为服务器后端的编写语言也是一个很正确的选择,活动记录只是一些很零碎的程序,任何一种语言都能顺利执行这个操作,但有了PHP,整个服务器不需要30分钟就能完成所有的数据整合。
通过一个独立控制流来记录玩家的游戏活动,也是一个很积极的对策。
我不希望有任何一个UI阻挡HTTP的调查请求界面,所以将网络通信内容移到了这个独立控制流。
我一开始非常担心成本支出的问题,但事实证明,这种成本支出实在是微乎其微,我甚至懒得将它列到财务报表中。
最后,保持整个记录系统的简洁性也真是一个智举。
我之前也有想过很多种备选的活动记录内容,但对《小绿人历险记》来说,追踪玩家死亡和闯关情况就已经足够了。
越多统计资料意味着数据处理将更为复杂繁琐,甚至难以提炼出有
效的反馈信息。
我现在对控制这种自动记录系统已经有经验了,所以将来可能会增加一些调查参数,当然刚起步时还是首选比较简单的记录系统,这一点是不会有错的。
记录系统的局限性
这个活动记录系统并非无所不能,它的设计仍然有一些不足和缺陷。
用PHP来编写服务器是个很不错的选择,但如果拿它来处理数据就完全不可行了。
我原先的想法是,通过一个网页仪表板处理数据,但数据流量加大时,PHP就完全无法招架了。
另外,PHP对硬件内存和运行速度的要求很高,我常常因为这些局限性而浪费了不少时间。
当游戏用户超过2万人时,大部分基于 PHP 开发的工具全部罢工。
通过PHP编写的Bitmap处理程序尤其要命,我用PHP制作了所有的热地图,实际上我应该编写一些可以在本地运行,而不是仅限于网络服务器的程序。
在PHPGD界面中,我发现了很多漏洞,为了处理程序我又不得不缩小关卡设计层的图像。
现在我又用Python和ImageMaick重新编写了这项工具,效果非常理想。
我在《游戏开发者杂志》的官方网站上公布了实现这项操作的代码,如果各位有兴趣可以上去看看。
最后要提的是,虽然这个系统所提供的数据可以让我了解玩家死因,闯关时长等信息,但我并不能找到那些不会导致死亡,但会限制玩家游戏体验的活动死角。
因为这个系统没办捕捉到这些信息,我的一些关键性关卡设计也出现了不少问题,最严重的例子就是,玩家无故被卡在某个环节中,大家都不知道要怎么脱身,最后只好放弃闯关。
我的系统并不能反映这种现象,我也是自己听到玩家抱怨,才得知了这一情况。
所以我要说的就是,这种自动活动记录系统虽然超级好用,但并不能准确反映整个游戏的全貌。
从我自己的经历来看,这个系统在查找问题关卡的布局上很管用,但却不能明确指出游戏的具体设计失误。
总结:
至于今后要开发的游戏,我当然还会植入这种自动记录系统来观察用户体验效果。
除了死亡区域,我还会增加针对不同死法的监测,这样才能知道玩家是怎么赢掉游戏任务的;另外,从游戏的实际情况出发,我认为增加一项玩家死前的区位历史记录也很有必要,这样可以追踪该玩家的游戏路径。
不过,编写这种系统关键还是要让它尽量简化;另外搜集到充分的数据并非大功告成,只有开发出可处理数据的工具才能算是完成任务。
所以我开发下一款游戏时,有可能继续用这种记录系统和数据存储解决方案,但会集中大部分精力编写行之有效的数据分析工具。
如果服务器可以读取个人玩家的活动记录,那这个系统也一定适用于大规模的玩家群体,它可记录的数据类型应该是多种多样,只是我们暂时还没有想到。
它并不是一个完美的玩法测试系统,但至少可以长期提供有价值的反馈信息。
通过这个极其简单的系统开发过程,我对游戏的关卡设计、用户的游戏习惯有了更深入的了解,也因此极大优化了游戏。
唯一的遗憾就是,我真后悔自己早些时候的游戏没有采用这个系统,因为它适用于任何平台、任何类型的游戏。
为Android编写实时游戏
—-学习笔记
这篇文章是Chris Pruett 在Google I/O 2009的一个演讲视频的笔记。
我翻译了大部分的演讲的演示稿,里面有不少疏漏,臆断和错误都是我记录的时候造成的,与演讲作者无关。
本文的版权归演讲作者所有。
转载请保留演讲作者的信息和本文链接。
你可以从下面的链接进入该主题在Google I/O 2009 的原文里面含视频和演示稿。
/events/io/2009/sessions/WritingRealTimeGamesAndroid.html 演示稿的直接连接:
/io/2009/pres/WritingRealTimeGamesforAndroid.pdf
演讲作者所制作的Android开源(apcha 2.0)游戏Replica Island :
/
/该游戏的开发笔记!
为什么要在Android平台上面开发游戏?
*传统PC和控制台游戏市场都变得高风险,只有很少的公司能够承担。
*在非传统游戏平台上面的小游戏持续赢得了那些原来在传统游戏平台上面的玩家和新玩家的亲睐。
-新平台参照:Nintendo Wii, iPhone, Flash, XBLA,等。
-低风险=更有趣+更多样的内容。
*Android给开发游戏提供了一个面向广泛的,熟悉互联网受众的渠道。
(指的是那些需要打电话也需要在手机里面玩游戏的人)
为什么这个游戏是在Android平台上?
*我做这个游戏的三个目标:
-给Android制作一个有趣的游戏。
-制作一个可复用,开源的游戏引擎让大家为Android开发游戏。
-对Android平台进行压力测试:只使用已经公开的代码和工具来制作游戏。
*我计划做一个传统的2D卷轴类游戏。
-视差层(近景远景不同的移动速度),基于图块(tile-based),精灵动画(animated
sprites),等。
-引入所有的硬件按钮:输入系统,OpenGL ES, 声音,等。
-这个游戏可能需要一个20%的工程师(即作者,20%是说作者每个星期用一天时间来
开发这个游戏)开发6个月的时间和一个全职美工开发4个月的时间。
-游戏的工具写起来非常的简单。
作者用G1演示了Replica island的demo。
游戏引擎的架构
*有许多的实现方法,但是基础的问题都差不多。
*我的实现方法是一个可以在每一帧都被遍历的“游戏图”(Game Graph),可以获取时间和移动事件作为输入,结果记录在一个清单里面来画出画面。
(这里的Grahp在大多数情况下你也可以理解成树结构)
-所有图形的“根”(root)都是“main loop”。
-main loop 的所有子节点每帧都被调用一次。
(所有的子节点都可以拥有他自己的子节点)
-在树中更底层的节点有可能同样被每帧调用一次,这取决于他的父节点。
-“game objects”是“game manager”的一个节点,”game manager”保证只访问那些在以摄像机为中心的一个圆形心区域内的节点。
(译者:其实做了类似于场景管理的工作)
-”game objects”他们本身就是“game components”的子图,每个component 都可以实现自己特定的功能,比如自己特有的更新循环(update loop)。
*至少我是这样做的。
*关键点:时间传递给每一个在graph中的节点,这样帧率独立于物体的运动就是可能的。
(可以制作一些例如特定物体慢动作的效果!replica island里面实现了慢动作的效果)
*另一个关键点:这个系统为每一帧把各个需要被渲染的物体收集到一个渲染列表中,但是这并不是真的把所有物体都渲染到屏幕里面。
游戏引擎架构-漂亮的线程,哟
*我有三个线程:
-主线程(main thread)是由Android activity生成的。
*负责引导游戏和接收输入事件。
(引导即为负责整个游戏的生命周期)
*在大多数情况下这个线程是休眠状态。
-游戏线程(game thread)。
*负责处理所有非渲染部分,包括:物理,AI,碰撞检测,动画,等。
*这个线程还负责game graph。
(graph就是前文提到的类似于场景管理的树结构)-渲染线程(rendering thread)。
*这个线程被SurfaceHolder所控制。
*仅根据他的渲染列表来运行,他还会为每一帧触发OpenGL命令。
—对于游戏的内
容他什么都不知道。
写快速的Java代码
这里说的Java是指的是android平台下的Java。
Java给你提供了非常丰富的现成的功能。
我爱咖啡,我爱茶
*我很大程度上是一个C++工程师
-实际上,我在这个项目之前没有写过一行Java代码。
-所以对于我给你的Java上的意见,你应该持保留态度。
-在过去的六个月的时间里面我做了许多优化工作,可能在某种程度上对于Java程序是没有必要的,也许我可以提供一些有用的花絮。
*写一个实时游戏就是一个在灵活性(flexibility)和性能上面寻找最佳平衡点的练习。
*我的(非语言特性)方法是:
-从尽可能简单的实现开始,但是要为未来的重做而进行设计。
-选择灵活性作为工作的重头而不是速度,直到速度慢到影响游戏操作。
-对于游戏的整体构想的制定要尽早和保持不变。
(profile early and constantly)要保证知道自己现在在做什么。
关于JAVA的意见第一步:内存管理
*绝对不要分配和释放内存。
-呃~绝对不要在游戏被玩(gameplay)的过程中分配内存。
- GC(垃圾回收)将会让你的游戏卡住100~300 ms(毫秒)。
这对于实时游戏来说是很致命的!你不会想要GC在你的游戏进行过程中被触发。
(译注:演讲在2009年,当时htc g1还是主流手机,作者演示游戏用的也就是g1,所以这真的是个大问题,但就算现在的那些高端手机对于这个问题也要慎重。
)
*改进:尽可能多的在游戏进行之前分配好内存,不要释放任何内存,直到游戏有一个自然的暂停时间。
手动调用GC在你知道那个时候是安全的。
(比如在两个关卡交替的时候)
*使用DDMS去追踪分配。
-嘿,Java分配内存是持续不断的,呃!
-把分配隐藏到类似于enum.values(), Class.getClassName(), Iterator, HashMap, Arrays.sort 等等。
-其中的一些是内存分配是没有办法避免的,但是要尽可能的保证GC不要在游戏过程中频繁运行。
对Java内存分配的误解
*把Java当作是C++来用。
*许多标准的Java实用对象分配内存。
-Collections过时了
-把enums忘记吧(他们真的很重量级)
-Arrays.sort()也类似
-所有返回String 的地方都必须是只读的(比如Class.getXXX();)
*DDMS是你的命名和查错的工具。
*比我更好的Java工程师也许可以给你更多的关于减少使用内存分配的实现方法。
第二步:不要调用函数
*OK,这很极端。
但是函数调用的开销很大并且你不能依靠内联(inlining)函数。
*尽最大可能的使用静态函数(static functions)。
*不要通过interface(这里的interface指的是Java的interface即接口)来调用一个函数,这会比普通虚函数慢30%!
*存取器(Accessors) 递变因子(Mutators)是我在C++的最好的朋友,但是他们在你的Java中的内部循环中没有位置。
*要警惕JNI函数。
-尤其是:许多的gl.glXX() 函数。
(JNI 会花费很多时间)
第三步:其他的技巧
*使用本地变量,尤其是在内循环里面。