分享个技术贴-如何设计随机内容
-
最近看了论坛里几个大神用唤境做随机地图的帖子,自己也开始尝试做起来了。其实用唤境实现随机规则不难,难得是随机生成的规则究竟应该怎么设计……正好在gamelook上看了一篇文章,分享给大家,给大家提供点思路。以下正文
随着玩家对内容消耗速度越来越快,随机生成内容对于开发者来说可以解决相当一部分压力,不仅可以满足玩家需求,还可以提高游戏的可重复性。
那么,游戏里的随机生成该怎么做呢?海外开发者John Harris分析了三种比较经典的做法:
你在自己的游戏里对于随机生成考虑过多少?如果没有,那么我建议你花点时间想想它的本质,以及有可能出错的地方。
有些人觉得,游戏不应该加入随机性,或者说,类似摇骰子一样的玩法应该是“边缘角色”。把所有的信息展示给玩家,如果攻击生效,它就应该是明确的,把不确定性排除。在一款动作游戏里,如果你拿枪指着一名玩家并且扣动扳机,如果目标是真实的,那就一定会击中,不应该被漂移或者描述数值干涉。
还有一些人,他们非常担心人们对于90%击中率的含义有所误解,所以用混淆数学概念的方式掷骰子,所以实际上击中率应该是98%。
真正随机的电脑游戏数量很少,在我们所处的宏观现实世界里,随机性实际上很少见。当我们掷骰子的时候,决定数字的主要原因是我们用手扔出去的力道,而用随机性来解释它实际上出于无知。我们不知道骰子在空中运行时候的运动矢量结果,也不知道它撞到桌子上有什么反应、会如何翻滚和停止。
你可以在量子级别得到真正的随机性,但这通常是传统电子学无法覆盖的。这个问题却非常重要,有些Unix系统实际上通过玩家的精准实际输入等资源形成了无序状态池,作为OS级服务响应使用请求。这些请求十分重要,以至于可以用来阻塞、暂停请求过程,直到获得足够的数值,这种方式通常被用于加密。
不那么重要的请求通常由其他方式构成。大多数时候,我们在游戏里要做的只是伪随机数字生成器,它们很容易被理解、大多数编译器的标准库都有提供,如果有需要,你还可以自己做。
如果你打算在自己的游戏里加入随机数字生成器,这些都是非常值得研究的,因此,本文主要介绍3种值得注意的随机数字生成器,包括它们的特性、使用方式,以及在一系列经典游戏中的使用案例。
《最终幻想1》:从预生成数字按顺序读取
原版的《最终幻想》以及史克威尔公司一些列的Famicom游戏,都是由传奇8位素程序员Nasir Gebelli编程的,他在Apple Ⅱ电脑时代就已经非常出名。Apple Ⅱ与Famicom都使用了6502微处理器,所以Gebelli写这款游戏编程的时候,已经掌握了大量技巧。
其中的随机遭遇生成大多数是由向上或者向下走来决定,通过存储在在ROM里的256个预置数值随机决定的。玩家角色每走一步都会更新参数,每个参数对应一个阈值,如果参数低于阈值,就会触发遭遇战。
但是,这并非《最终幻想》原版游戏唯一的随机数字生成器。在战斗中,当需要掷骰子的时候,就会用到类似系统,它带有完全不同的256个数值,而且是按次序读取。与遭遇战生成器的参数不同,这个生成器存储在有电池供应的RAM里,换句话说,如果在特定区域加载存档之后遭遇战斗,重新加载游戏,然后在相同区域还可以再次遭遇,而且会是同样的敌人、同样的难度。
有趣的是,虽然战斗状态的随机生成器存储于RAM中,但它并不与玩家的存档发生直接关联。战斗开始之后,战斗引擎做了一件非常聪明的事情。该游戏每两帧都会调用数字函数,却不使用结果,以至于你很难预测。
我们可以把这种行为叫做“旋转”随机数字生成器,即生成数字并非为它们的数值,只是为了得到数字。当玩家移动光标的时候,随机数字生成器会再次转动。将战斗计算的结果与玩家操作时机关联起来,做到每次游戏都带来不重复的结果。尽管遭遇战生成器每次加载存档都会一样,但只要玩家无法复制此前的精准操作,战斗状态很快就会发生变化。
在RPG游戏里,这一点是尤为重要的,你需要确保玩家无法掌握随机数字生成规律,才能保证战斗系统不会形同虚设。如果提前知道某个区域有自己不喜欢的遭遇战斗,那么玩家就会主动到另外一个遭遇区,甚至能够利用这个漏洞区购买物品,找到对战斗最有利的道具。
唯一能够避免这种情况的,就是获取一些外部数值、外部无序资源,来通过编程产生多种运行状态。在Commodore 64上,声卡芯片和噪音振荡器上的输出虽然不够完美,但通常可以提供足够好的无序资源。有时候在NES和SNES上,一款游戏可以对一些或者所有帧调用随机数字生成器。由于对玩家输入的反馈发生在不同帧,随着玩家行为给系统提供大量无序资源,就会导致游戏运行结果出现越来越多的差别。
带有实时时钟的系统会它来初始化伪随机生成器,不过,玩家通常可以设置时钟,所以这种做法也是一个漏洞。如果始终有不错的分辨率是最好的,我们说的时间单位是以毫秒计的,如果通过这么小的单位取阈值,你可以得到让玩家很难有效操控的数值。
我们再回到《最终幻想》,大多数的休闲玩家是很难找到随机生成器漏洞的。但是,如果玩家出于某种原因想要避开或者触发一个特别困难的遭遇战该怎么办?
在游戏的一个房间里,有个叫做Warmech的伪boss,他出现在一个房间里的时候被遭遇的概率很高,但它是第8组遭遇敌人的一个,只有三个数值可以触发,也就是说,256场战斗才会遭遇三次。如果你知道战斗生成器的状态,就可以故意触发遭遇战,让它必定发生。
-
《超级马力欧64》:线性同余数生成器
一个非常受欢迎的伪随机数字生成器叫做线性同余数生成器(Linear Congruential Generator,简称LCRNG),它们在被操控的时候不会产出破坏游戏的效果。如果想要详细了解它的解释,读者们可以到维基百科查询。
好的LCRNG在于它是不计算顺序的遭遇,它的数值是跳跃式的,但同时会覆盖所有的步骤。
你从子数值开始,通过基础操作产生结果数值,后者会返回调用者并且再次生成数值,你最终可以得到每个子数值产生的一系列数值,最终形成循环。随机数字生成器需要避免这种情况,但这也恰好是LCRNG的优势:除非域内数值耗尽,否则绝不会重复。
《超级马力欧64》就使用了这样的随机生成器,在YouTube做挑战视频的pannenkoek还专门发布过相关视频。有一个问题在于,它的算法会在65114个数值之后循环,因为它的生成器只有这么多可能的结果,所以,如果玩家操作超出这个数值范围,是得不到对应随机数字的。
-
《口袋妖怪绿宝石》:不良种子行为
操控《最终幻想》的随机数字生成器可以决定敌人出现的时机与具体种类,但这需要玩家投入大量的时间尝试。《马力欧64》的单个生成器就可以影响金币复活与敌人行为,但这并不会对游戏带来巨大影响。《口袋妖怪》对随机数字生成器的使用频率更高。
当一个宝可梦产出之后,结果数值可能会存在很长时间,其中有些数字是神秘的、玩家不可见,但却有长期影响。如果掌控这些数值可以给游戏带来破坏,由于玩家之间可以相互交易,所以最终伤害的不仅仅是游戏本身。
由于生成器在《口袋妖怪》系列里十分重要,现代很多的续作都给伪随机性使用的特别强大的算法,比如Mersenne Twister算法。由于该系列的受欢迎度,玩家们探索了很多方式破解该系统。
这些作弊方式其中一个目的是得到更好看的宝可梦,虽然不能带来战斗优势,但它们却是十分稀有的。在Ruby、Diamond和Emerald系列里,随机数字生成器每帧都会变化,战斗中的变化频率提高为两倍,更不用说到处可见的随机性。不过,Smogon网站专门用了一页研究如何操控该游戏的生成器,因为它有一个非同寻常的缺陷:开机的时候,Emerald并不会把内部时钟运用到生成器上,而是把它重置为0,其他两款游戏只有在断电之后才会这么做。
由于游戏的生成器按计划处理种子数值,因此决定是否产出特殊宝可梦的有特定帧数。了解这些帧数并不能保证得到好看的宝可梦,但至少概率会大幅提升。
需要注意的是,该游戏的生成器会利用玩家ID和秘密ID,这些都藏在存储文件里,而且不易改变,因此,一个存档上很容易抓到的宝可梦,换到另一个就可能需要等很久。
-
此回复已被删除!
-
此回复已被删除!