作者cowbaying (是在靠北喔)
看板GameDesign
标题[程式] 乱数、线性同余、perlin noise
时间Wed Oct 8 13:44:34 2014
标题打这麽多是因为去年的某篇文章导致的...
除了骗还是骗
这个世界充满了欺骗...
目前还在研究乱数这东西
http://rosettacode.org/wiki/Linear_congruential_generator
有兴趣可以先阅读上面的文章
目前基本的乱数产生都是用线性同余法来达成
觉得不够乱的话就是要自己写了
方法似乎百百种
接着再阅读这篇
http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
应该许多人研究过这东西
许多沙盒游戏也都是使用perlin noise来达到理论上无限大的地图
使用种子码来减少资料储存量
产生看似随机生成的世界
不过理论跟实际要使用差距蛮大的
网路上能找的资料都是很基本的东西
要实际使用还需要琢磨一番
如果照着网路上的文献来实作会发现一个范围的perlin noise的产生
跟即时产生差异还颇大的
因为还牵扯到图块接合等等问题(map tile)
需要做内插法平顺等等处理
说到这里
可以参考minecraft spigot-api里头的perlin noise
github.com/SpigotMC/Spigot-API/tree/master/src/main/java/org/bukkit/util/noise
(太长了把http截掉)
=======吃完饭之後突然忘了自己要说什麽========
说点比较不容易看懂的地方
如果照着第二篇的公式来看
很快就会发现过了一定数值後结果会一直是1.0
我想这应该是同余法的极限吧
如果SEED一直不变
完全无法产生够大范围的乱数
(1.0-((x*(x*x*15731+789221)+1376312589)
&7fffffff)/1073741824.0);
来分析一下上面的算式
基本上的目的就是要让1.0後面那串结果在0.0与2.0之间
这样相减才能产生正负
注意绿色的符号
那是位元运算子後面的7fffffff应该是0x7fffffff
也就是整数最大值2,147,483,647
位元运算子的用处就是确保计算後的直为正数且在该范围内
位元运算子算相当好用
接下来可以参考C或者C++的RAND与SRAND之header
在stdlib.h里
利用第一个种子码计算出下一个数值後(可能为长整数时期)
将其当成下次的种子码如此反覆执行到我们指定的次数
不过这种作法我们发现每次乱数的顺序都是一样的
所以现在改善的做法都是用系统时间来当种子码(准度到秒)
不过还是有不够随机的情况产生
所以第一个种子码很重要
接下来就是我们想控制的部分了
由於PERLIN NOISE是有规律的
因此需要使用不同的频率与放大的倍率将数个阶(octave)合成起来
这边可以另外参考SIVI的作品
https://github.com/philfrei/SiVi
我目前的想法是
如果之後要带入计算的座标极大时
是否会降低运算的效能
目前还在测试
所以猜测把座标加入seed的产生
或许是个效率较高的作法
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.27.44.146
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/GameDesign/M.1412747077.A.1B2.html
1F:推 LayerZ: 先推,不过超过我理解范围了XDD 对我而言,用时间,顶多把 10/08 14:25
2F:→ LayerZ: 时间摊开来到整个活动期间都不一样就好了,根据测不准原理 10/08 14:26
3F:→ LayerZ: 再去过度追求随机的随机性,因为永远无法确定玩家此时此刻 10/08 14:28
4F:→ LayerZ: 抽福袋是否会合乎设计的理论.. 10/08 14:28
5F:→ LayerZ: 第三行前面少个不用,不用再去.. 10/08 14:29
6F:→ LayerZ: 唔...我发现我又再说废话了(死),可以帮我把推文删掉吗, 10/08 14:29
7F:→ LayerZ: 我找时间看完再来回好了.这麽方便的推文真是个糟糕的发明 10/08 14:30
9F:推 LayerZ: 楼上害我上班大笑XDDD 如果一个玩家只能骰一次,并且不能 10/08 15:25
10F:→ LayerZ: 跟别人比较的话...他是成立的XDD 10/08 15:26
11F:推 LayerZ: ...PS3 ESCDA Code!? 10/08 16:29