※ 引述《ZMTL (夜风/潇湘 VR板已经开板!)》之铭言:
: 嗯,虽然我是APP工程师,但大学不是唸本科毕业后才半路出家的,
: 对这点真乱数、假乱数以前耳闻过讨论却没什么概念,刚好跟游戏有关想到就问一下。
: 首先举例使用假乱数表的游戏,以下有稍微简化过程:
: 1.魔物猎人:世界
: “炼金”功能是拿X个珠子生成三颗新的珠子,存盘读档结果不会变。
: 后来被发现有一张表,像这样
: A B C
: D E A
: A A C
: 如果你是这次炼金出来是ABC,下次炼金出来是DEA,下下次炼金出来是AAC
: 那你可以先不练金,去打两场任务出来就会变成AAC。
: (实际上打任务推进的序列是1、1、2轮回,按下不提)
: 细节:https://forum.gamer.com.tw/C.php?bsn=5786&snA=137873
: 2.神奇宝贝
: “生蛋”功能是公母方配种生出子代,特定变因固定下存盘读档结果遗传项不会变。
: 父母都有 A B C D E F六项能力,分别遗传父母的哪几项在变因固定下是不会变的,
: 但变因不包括父母是谁,所以可以确认会遗传哪一项后再更换父母取得特定遗传的子代,
: 进阶一点用法就是找到第XXXX次会生出色违后,
: 用低步数就生出来的神奇宝贝跳过中间不需要的部分,
: 在指定的位子再更会为要的神奇宝贝快速取得色违。
: 细节:https://home.gamer.com.tw/creationDetail.php?sn=3427102
: 那问题来了,
: 如果说是避免玩家用SL大法来硬洗出想要的成果,却反而造成未来成果会被预测,
: 难道单机游戏做不到真正在产出结果当下进行乱数,或者乱数表假乱数表有什么优点吗?
: 其实对这问题有疑问好久了w
: 很多人说MHW洗珠子无聊会消耗热情,但经过PM的洗礼我真的觉得还好XD
: 顺带一提,很多线上游戏/网络游戏的都市传说有时候我不会完全不信的原因也是这个。
整串下看下来好像没多少人点到重点
在业界,游戏除了博奕类例外,八成都会使用乱数表,不使用乱数表的是少数,
(有些博奕类开发还要乱数产生器还要特别用买的..,确保几乎不可回朔)
几个重点:
1. 效能
2. 可回朔性
3. 可验证性
4. 多人游戏
你如果是一个简单的大富翁游戏,只需要前进时丢丢骰子就好,
那就跟效能问题无关,你随便写、随便CALL任何随机函数都OK。
但问题是现在的游戏是需要很大量的乱数运算,越精致的游戏越是如此,
那一枪一刀打出去都还要算浮动伤害的、还有一大堆的物理计算,
很显然的不能单纯的使用各语言内建的rand()。
rand()你去爬看看 Library,展开来行数其实都不少,大部分都是以时间做种的
椭圆算算法。
而你使用乱数表的话,只需要在LOADING的时候建立一张表,之后需要乱数的时候,
直接用查询的方式即可,计算跟查询,两者效能天差地远。
而且使用计算的方式还有一个问题,那就是需要多执行绪的场合容易有问题
例如丢骰子A先生与B先生看谁比较大
如果是A先丢完,B再丢,那就双方有输有赢没什么问题,
但如果是A跟B同时丢的话,依照各种乱数产生器的原理不同,
是极有可能出现A跟B同时丢都永远会是一样数字的情况。
再来是游戏的乱数为什么会需要可回朔性跟可验证性?
因为你如果使用原生乱数产生器的方式,你很难实现REPLAY跟存盘,
这是一个很大的设计重点,不管你的游戏是否实装这功能,你都
必须要有这部分的耦合性设计,也就是确保未来可以扩充这些功能。
你如果每次都用即时运算的方式产生乱数,你很难确保每次S/L或是REPLAY
都能完美的重现每个乱数的产生,即便你种子明明喂的都一样,
但有时候跑出来的东西就是他X的鬼打墙,想必每个程式人都有这经验。
想想看,游戏终于呕心沥血的完成了,终于可以让你的肝休息,
结果老板突然要你改成使用乱数表并且支援以上功能,
那是何其大的手术工程!? 你不就..
◢···· 崩╰(〒皿〒)╯溃····◣
还有牵扯到网络连线的问题,如果不使用乱数表,使用原生乱数,
光是让要多位玩家的同个时间误差内的乱数确保一至,那就已经是个严重问题。
例如假设我砍一刀,我本机端计算伤害是 48763 ,等到你接收到封包了,
你才开始重新计算一次,然后又只用时间来做种,可是刚好这封包撞到鸽子,
结果你的本机端算出来是 5566520,请问该怎么办?
或是我也可以不用计算,直接接收你计算好的数值就好,但我也不能验证,
要是你开挂丢过来的数值变成 4876399999 我不就得被秒?
或要是你的封包丢过来要100MS,
那我是不是每次做完一个动作都要暂停画面再等100MS才能继续?
否则我没办法确保需要的乱数一至,因为是即时运算的乱数,
所以我只能等跑等跑等跑等跑...我是在玩游戏还是在看他X的幻灯片?
难道我不能在某些地方事先预测或计算出你会产生出什么数值吗?
例如一把机枪,鼠标点一次下去,一秒自动射击5枪,产生5个浮动伤害
你开一枪,我这边难道都得等你5个伤害的数值封包全到后才能计算人物伤害吗?
有了乱数表不就可以简化成,你开枪->我接收到你开枪了,
然后我这边用同样的条件查询跟演算,预先计算出未来一秒的5个伤害,
这样是不是省下整整一秒的时间? 对网络游戏有绝对的效能提升。
且因为在LOADING产生的乱数表大家都确保拿到同样的一张,
所以我还可以验证这5个伤害是正确的。
还有很多细节讲不完,其实当初我也是刚你差不多,
进了公司之后被电过,
发现自己不能在用以前在学时那种作业式的方式跟逻辑写程式,
很多地方实务上写的方法都跟课堂上的完全不一样。
例如A先生有5元 B先生有7元,两人共有多少钱?
当然我们可能会:
int A=5,B=7;
return A+B; 就完事了。
但是实务上人家会要求你例如
先设计一个物件person,然后把A跟B变成物件
person A = new person();
person B = new person();
A.money = 5;
A.money = 7;
return A.getMoney()+B.getMoney();
你可能问说干嘛要这么麻烦? 例如哪天公司要你修改成
A先生有5美金、10台币、7日圆
B先生有7美金、 9台币、6日圆 ,并且增加CDEFG先生小姐...
那我不是只要修改person这个物件就好? 我同时只要重载getMoney( String );就好
因为A跟B继承了person,不用针对A跟B再个别修改
只要getMoney( 美金 ),我就能取得多少美金...
对于程式的维护跟扩充绝对有帮助,
那个好的实务设计体现在现实面就是可以大幅减少你未来的爆肝时间
等等以上只是举个例。
总之实务上,游戏设计使用乱数表好处绝对大于你即时运算,
况且你真的需要即时运算的场合并不多。
玩家S/L大法刷东西那是玩家的事情,那并不是你站在公司开发者要替玩家着想的事情。
所以说最后有两本书建议写程式的人必买! 必买! 必买!
很重要要说三次 !
特别是你有实务需求的更是要买!
这两本根本就该列为必读的教科书,
因为这两本是真正从实务面上教你如何写程式。
就是 大话设计模式 ISBN:9789866761799 (必读)
大话资料结构 ISBN:9866072118 (推荐)