Re: [问题] 单机游戏用seed生成的假乱数表好处是?

楼主: extemjin   2018-03-07 23:03:26
※ 引述《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 (推荐)
作者: bnn (前途无亮回头是暗)   2018-03-07 23:05:00
广告文(X
作者: emptie ([ ])   2018-03-07 23:06:00
原来是书商(误
作者: prismwu   2018-03-07 23:07:00
妳要用先讲结论当作第一句
作者: ayubabbit (ウォロックが倒せな)   2018-03-07 23:08:00
原来是业配(X
作者: kungfutofu (功夫豆腐)   2018-03-07 23:09:00
好喔 来买书
作者: SilentRain24 (SilentRain24)   2018-03-07 23:13:00
身为写扣人士这篇我推
作者: seaEPC (没看见,我没看见 >_<)   2018-03-07 23:14:00
Design Patterns跟Data structure确实很重要不过最可怕的是接他人的code然后发现里面满满return A+B;
作者: LiNcUtT (典)   2018-03-07 23:22:00
感谢解惑~
作者: SPDY (Alex)   2018-03-07 23:25:00
推专业清晰的讲解
作者: zseineo (Zany)   2018-03-07 23:26:00
猝不及防的叶配XDDDD
作者: guogu   2018-03-07 23:27:00
可是合成那种就不需要大量重复的运算,那边用rand就没差?
作者: zseineo (Zany)   2018-03-07 23:27:00
防玩家SL也不一定是替玩家着想啦,有时候玩家会选择不好玩但简单无脑的玩法(某些SL),不过这又跟其他设计方面又关就是了
作者: arrenwu (键盘的战鬼)   2018-03-07 23:29:00
你说的情况 只要运算都在服务器就可以不用乱数表了吧?
作者: zseineo (Zany)   2018-03-07 23:29:00
*有关
作者: aaaaajack (丁丁是个人才)   2018-03-07 23:30:00
有点疑惑,照理说这些东西都以server算的为主吧没事,大概懂了
作者: sdd5426 (★黑白小羊☆)   2018-03-07 23:45:00
简单来说写的程式码要有sense 不能像学生那样什么都用最简单的想法
作者: aaaaajack (丁丁是个人才)   2018-03-07 23:49:00
不过这篇讲的是同步的问题,但原po问单机游戏...
作者: sdd5426 (★黑白小羊☆)   2018-03-07 23:53:00
他有提到啊 使用函数不好实作replay等
作者: linzero (【林】)   2018-03-08 00:00:00
replay直接把所有得到的乱数存起来不就好了?
作者: aaaaajack (丁丁是个人才)   2018-03-08 00:02:00
那段我觉得他在乱讲,rand没这问题...
作者: know12345 (你和我)   2018-03-08 00:03:00
猝不及防卖书XDDD
作者: LiNcUtT (典)   2018-03-08 00:04:00
实作上绝大部分都是基于乱数表的乱数产生器 < 这不对吧
作者: holymars   2018-03-08 00:05:00
实作上都是deterministic的PRNG算法..然后让generator同步....
作者: aaaaajack (丁丁是个人才)   2018-03-08 00:05:00
或者说rand跟乱数表根本是一样的吧
作者: LiNcUtT (典)   2018-03-08 00:05:00
绝大部分的乱数产生器都是算出来的,不是查表啦
作者: holymars   2018-03-08 00:06:00
会写成先骰好一张表再整张sync,应该是对PRNG有所误解平白浪费流量在传无用资讯 同样的算法下你传10000个值
作者: seaEPC (没看见,我没看见 >_<)   2018-03-08 00:06:00
会出现不同结果我觉得比较像撞到multi-thread执行顺序问题
作者: LiNcUtT (典)   2018-03-08 00:07:00
h大说的比较有道理
作者: holymars   2018-03-08 00:07:00
你“以为”算法一样,实际上要保证不同平台不同硬件的PRNG算法跑出一模一样的结果,通常踩到雷都是这个至于保证rand()呼叫的顺序和次数是相同的,这是另一个问
作者: seaEPC (没看见,我没看见 >_<)   2018-03-08 00:09:00
看reply指的是哪种囉,我指的是像在同个条件/输入下重跑
作者: holymars   2018-03-08 00:09:00
题,不管你有没有随机因素,event发生的次数和顺序本来就要保证是同步且正确的..
作者: seaEPC (没看见,我没看见 >_<)   2018-03-08 00:11:00
所以没写好的情况下就会出包啊 工作上还真遇过...
作者: holymars   2018-03-08 00:13:00
同步没写好,应该不止有随机的部份会出包,是全部都会出包才对...
作者: seaEPC (没看见,我没看见 >_<)   2018-03-08 00:25:00
我们那边是收前端资料解码后丢去DB更新,基本上多个threads分别处理自己所属资料,是不用管谁必须先做的
作者: Logan2934 (Loagn)   2018-03-08 03:16:00
神奇宝贝 MHW 本来都是卡匣游戏,可能整个游戏就只要骰0~9,为了省空间以及加速,就自制了个很简化的rand(),结果就一路继承到现在
作者: Neil000 (\ぱんぱかぱーん♪/)   2018-03-08 07:58:00
书商推
作者: yshinri (ISML实习分析师)   2018-03-08 08:45:00
同样是表, 写程式时先建好表跟实际执行时先求一万个乱数cache 成表还是有差, 你在讲的表多半是后者这种那后者这种表其实除了你提的优点之外, 其他方面都比前者来的好, 但我想不只这里推文, 原 PO 多少也以为建表是前者那种建表, 这才是这一串开头在问的问题然后我提的神魔的例子则是真的少数用前者这种方法建表的奇葩例子replay 这种事情就算使用先 cache 的表, 只要把开头的种子给纪录下来, 之后 replay 回放时重新产生就行了至于区网连线游戏的随机伤害这种东西, 你该传的不是“我打了你, 你帮我算个伤害”而该是“我打了你多少点”那这个随机伤害怎么产生就跟什么同步的无关了当然这种状况的 replay 就必须把每次的伤害都纪录下来
作者: hanmas   2018-03-08 09:35:00
推专业 不过物件导向学校也是有教的吧
作者: stfang925 (司马铃薯)   2018-03-08 10:17:00
推推~~
作者: j456789a (nightforce)   2018-03-08 11:15:00
感谢伟大的物件导向让我们减少更多爆肝时间
作者: gn00063172   2018-03-08 12:20:00
推推
作者: GKki2012 (chichi)   2018-03-08 14:33:00
专业推推推

Links booklink

Contact Us: admin [ a t ] ucptt.com