※ 引述《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 (推薦)