遊戲企劃必修課:遊戲的「隨機」設計
隨機系統設計與實務經驗談
什麼是「隨機」?
所謂的隨機(Random)指的就是無法預期結果。
這個無法預期結果,不見得是因為真的無跡可尋,有時候是因為要素太多太雜,我們無法全部掌握。例如丟出一顆骰子,如果我們可以計算所有的力道和碰撞,其實是可以得知最終結果的。但無論是計算量、觀測精準度和我們對力道的控制,現階段都是不可能實現預測的。
在現實世界中,常見的隨機產生手段包括剛剛提到的骰子,此外能「打亂順序」的諸如「洗牌」等方式,也都能產生隨機效果。
而隨機也是遊戲設計中很重要的一塊,今天我們就針對這個領域來探討一下吧!
電子遊戲中產生「隨機」的方法
在電子產品中,可以利用軟體函數來實現「隨機」,但這個隨機其實並不是真的隨機。
舉例來說,如果在C語言寫一段下面的程式碼:
無論執行多少次,都會得到同樣的結果。
這是因為電腦的隨機,實際上是在事先準備好的「亂數表」中,找一個參照區間,利用這個區間來顯示隨機函式的結果。
但由於這張亂數表是固定的,因此顯示的亂數也會是固定的。
參考資料C/C++ 使用 rand 函數產生隨機亂數教學與範例程式碼
如何產生「每次都不同的結果」?
在程式開發中,為了避免每次取隨機都會取到一樣的結果,我們會利用所謂的「種子」(註一)來作為隨機計算的變因。
當這個「種子」不同時,隨機的結果也會不一樣。因此,我們只要能在每次需要亂數計算時,放入不同的種子即可。(反之亦然,使用同樣的種子就會獲得相同的結果)
最常使用的方式,是將「時間」作為亂數種子置入隨機函式中,如此一來,就能在不同時間獲得不同的結果了。
註一這裡所謂的「種子」(英文叫做 Seed),和我們在玩「用演算法生成地形」的遊戲中的「種子碼」是同一種東西。例如 Minecraft 中可以藉由輸入種子碼,生成固定的地形。所謂的「生成演算法」也是一種隨機機制的應用。除此之外,伺服器和客戶端如果有相同的演算法時,隨機結果可以只傳送種子給客戶端就好,避免需要傳一大堆隨機結果,可以節省封包容量。
延伸補充- Unity 新版本的隨機函式
筆者這邊原本想要拿 Unity 當例子,但實際嘗試後發現,大概是為了開發方便,Unity 中用產生隨機數值的函式 Random.Value 本身內建了替換種子的功能,換言之只要呼叫隨機函式,根據時間點的不同就會有不同的結果。
不過 Unity 依然保留了可以指定種子的功能,如下圖,使用Random.InitState() 函式就可以指定 Seed,之後的隨機結果會根據這個種子而定。
以前印象中沒這麼方便,大概是後來為了減少開發者的麻煩(大部分時間遊戲取隨機都想要不同的結果),所以做了這個調整。
筆者做上面這個嘗試的時候使用的是 Unity 2019.4.21 版本。
了解了電腦中隨機的生成原理後,我們來看兩個利用隨機和演算法生成遊戲場景的例子。
以 Rogue Legacy 的「地牢」生成為例
在盜賊遺產這款遊戲中,我們可以發現實際上地牢的房間是以某個尺寸為基礎單位來設計的。而且無論房間如何設計,連接上下左右其他房間的通道大小和位置始終如一。(順道一提,The Binding Of Isaac也是使用這種方式,還包含了隱藏房間等設計,更為複雜)
這種方格化的規格,能確保房間之間能夠完美相接,減少演算法的複雜度。
但像是 Enter The Gungeon,地牢房間就不是以這種方式設計,因此走道會依據房間位置來客製化生成。(即便如此,走道還是有最小單位,演算法會用這些零件拼接成最終的連接通道)
只要能確保地牢的路線不會被封死,所有房間都能到達,這樣就算是生成一個可以使用的隨機地圖了。
事先定好規則,並且置入隨機種子,就能讓系統生成不重複的地形。
以Terraria的「隨機地形」生成方式為例
筆者以前在參與沙盒類型的遊戲專案時,曾經研究過沙盒類遊戲的地形生成,像是泰拉瑞亞(Terraria)、當個創世神(Minecraft)等遊戲中,都有應用類似的技術。不過為了降低理解門檻,這邊就以二維遊戲 Terraria 當作例子。
以隨機地形生成領域來說,沙盒類遊戲可說是最複雜的了。因為可以改變地形,因此地表或山脈裡面的構成也需要一併生成。
以 Terraria 為例,地形是由方塊資源為單位組成的。生成時,大約會以「地形」->「生態」->「水和其他液體」->「據點」->「礦物」的順序來逐步生成,後面生成的東西會蓋掉前面已經生成好的物件。
根據隨機算法,每一個階段都會在地圖上生成不同的資源物件。
以「地形」的生成為例,是在一張三維的雜訊陣列(隨機陣列)上,橫向切一個橫截面,與陣列相接處的部分為「真」,空的部分為「假」,以此來形成地形中的「實體」和「空氣」區域。生成完後,再以一條二維的隨機曲線作為地表的地形線。
而「生態」的生成則是依照演算法,在合適的位置生成指定的生態中心,涵蓋的範圍內將基礎資源塊改變為與生態相符合的資源塊。例如在「沙漠」裡的基礎塊就是沙子,而「雪原」的基礎塊則會被替換為雪塊。
等生態系完成之後,「液體」、「礦物資源」、「植被」、「建築物和地牢」等等不同的結構會依序以類似的方式生成在地圖中。
沙盒遊戲就是利用這種方式,在每一個階段套用不同的隨機算法,將整張地圖「算」出來。這也是為什麼隨機地形類遊戲,在一開始生成地圖時,需要比較長的讀取時間了。
隨機能帶給玩家怎麼樣的「體驗」?
關於遊戲內的隨機設計,有過不少文章或影片介紹了,筆者這邊直接放上一部個人認為很值得一看的解釋短片:
簡單來說,在這種理論中,將隨機分為「輸入型隨機」與「輸出型隨機」。
前者是指玩家接收到的隨機「資訊」,包括地形、突然出現的敵人、怪物掉落的寶物和裝備等等。這會提供遊戲的多樣性,以及刺激感。
後者指的是玩家操作之後的隨機「結果」,例如攻擊敵人結果 Miss「落空」,打出爆擊,或是轉蛋系統的轉出結果等等。
輸入型隨機和輸出型隨機最大的差異點,就是玩家能否對接收到的資訊進行「回應」,例如攻擊時 Miss 打空就是打空了,玩家無法針對「攻擊落空」這件事情做有效的回應。但隨機的關卡生成或地形是一開始就產生的,玩家可以對這些資訊進行整理和回應。
輸入型隨機的特點
- 和輸出型相比,玩家更傾向把遊戲成敗歸咎於「技術」
- 提供多樣性,降低作業感
- 提供玩家需要「調整策略」的動機
輸出型隨機的特點
- 和輸入型相比,玩家更傾向把遊戲成敗歸咎於「運氣」
- 製造「戲劇」效果(例如派對遊戲)
- 迫使玩家進行「風險控管」
兩種隨機設計的共通點
- 隨機結果影響的比例過大,會抑制玩家對於「長遠策略」的規劃。(亦即過大的運氣比例會降低策略的價值)
- 過於數值化時,會讓玩家很難「預期」。(影片中也有提到,抽象的文字不如具體的骰子或卡牌來的容易「想像」)
- 能給予玩家「驚喜」和「記憶點」,尤其是「機率較低的結果」(例如如果爆擊機率98%,那麼那個2%沒爆擊就是記憶點)
避免踏入玩家的心理誤區
在心理學上,人類有一些特殊的傾向,會導致「體驗」與「事實」相違背。
以下這些在設計隨機機制的時候要特別留意。
- 玩家對於「例外」會特別印象深刻。如同上面提到的,「低機率」會出現的事情,如果碰巧發生了一次,往往會記得特別清楚。
- 玩家對於「損失」的印象會大於「獲取」,尤其是「獲取後的損失」更是如此,這也被稱為「損失厭惡」。但追根究底,是人們特別不喜歡「負面反饋」。例如「攻擊落空」和「攻擊爆擊」,前者的機率玩家往往會覺得「體感比帳面數字還高」,而後者則剛好相反。
- 玩家傾向記得最後一個記憶點。如果以關卡來說,玩家今天遊玩的最後一個關卡,如果是成功收尾,玩家對這款遊戲的整體印象就偏向「正面」,如果是失敗收尾,玩家往往會在整體評價上給遊戲打折扣。
延伸閱讀查理芒格的人類誤判心理學
隨機設計的檢查點
針對這些心理誤區,以及上述內容的整理,以下這些檢查點可以讓你在設計「隨機」的時候,多一層檢驗的思路。
- 這個隨機設計對玩家的策略決定影響的比例為何?在極端狀況下是否會取代「策略」的價值?(註二)
- 輸入型隨機的出現頻率為何?是否在機制中影響玩家的長線決策?
- 輸出型隨機的設計目的為何?如果是負面反饋(例如攻擊Miss),是否限制在玩家可接受的範圍內?
- 承上,負面反饋發生時,有沒有補償的機制(例如保底),或是避免全部損失的設計(例如強化失敗只消耗金幣,武器不會消失,或是閃避成功時降低一半傷害而非全部傷害)?
- 機率會顯示給玩家看嗎?是以什麼方式表現?抽象數值或是實體物件(例如骰子)?
- 介面上顯示的是真正的機率嗎?是否有隱性的其他演算機制來做補償或調整?
老話一句,「遊戲是體驗的載體」,重點在於玩家獲得的體驗,而非遊戲的機制本身。
所有的設計都是在為體驗服務
只要能提供好的遊戲體驗,假造的帳面機率也是可行的。(當然這個指的是好的面向,並非偽裝的轉蛋機率,或是強調公平的 PVP 遊戲也無法這樣設計)
筆者在之前某篇文章也提到了營運類遊戲的活動設計核心,其實也是在強調數值和機率設計都是為體驗服務的。
營運活動設計的精髓,不在於一波操作下來能賺多少錢,而是暴死的玩家有多少還願意留下來。
不過,轉蛋的議題比較大,留待下次的專題再來討論,我們接下來聊聊實務上隨機計算會碰到的問題。
註二關於遊戲策略的設計,可以參考筆者的另一篇文章:什麼叫做「遊戲深度」?
隨機算法對伺服端的負擔
關於伺服器計算與客戶端演出的基本知識,可以參考筆者之前寫的「遊戲的『連線與驗證』機制淺談」一文。
即便一個 Random.Value 函式運作的時間非常短,伺服器要處理非常大量次數的隨機依舊是一件艱鉅的任務。
因此「降低計算量」以及「把計算工作丟給客戶端」就是唯二的解決方案。考量到客戶端可能會作弊,那麼營運類遊戲就只能想辦法降低計算量了。
用「圓桌理論」判斷方法來降低計算次數
圓桌理論和逐步判斷可以參考小熊之前寫的這篇文章:「逐步判斷vs圓桌理論 淺談2種戰鬥流程的判定方式」。
簡單來說,逐步判斷就是對每一種影響隨機的要素,分開來進行計算。例如A角色攻擊B角色,「是否擊中」和「是否爆擊」以及「是否觸發技能」等等判斷都分開來運算,最後確認結果。
而圓桌判斷就是將上面這些可能性先計算好,然後用一次隨機就可以獲得原本可能需要多次判斷的結果。(如果是可以重疊發動的效果,在圓盤的區間上也會直接攤平計算,無論如何隨機只會取一次)
除此之外,圓桌理論也可以根據體驗的優先級,讓「更重要」的事情留在隨機區間內。優點是重要的觸發效果觸發的機率會是絕對正確的,缺點是優先較低的事件會被犧牲掉,同時數值對裝備屬性和效果的平衡把關要更為嚴格才行。
參考資料[职业交流] 对于圆桌理论和经典概率判断算法的分析
偽造浮動傷害
在遊戲中,攻擊打出的傷害數字通常會在一個區間內浮動,這是為了在傷害數字大的遊戲中,避免每次攻擊傷害都一樣所做的設計。也被稱為「大傷小傷」。
例如期望傷害是 100,系統可以能會上下抓 5%作為浮動區間,因此實際打出的傷害會是 95~105 之間。
浮動傷害由於需要取隨機,如果給伺服器計算的話會造成額外負擔,因此也有一種作法是浮動傷害純粹只是客戶端表現,因為長遠來看還是以期望值為最終結果。這種方式常見於 MMO 或是大型掛機遊戲,玩家不太看重單次傷害,也不需要對小數字斤斤計較的場合。
事前計算好大量數據結果
遇到那種需要萬人同屏作戰,或是大量數據計算的場合,其實很多數據都是事先算好的,中途不做多餘的計算,客戶端也只是展示結果而已。
在這種情況下,很多時候玩家也不會在意微小的數值差距,大部分還是取概數即可。
筆者之前就看過一篇文章,描述 MMO 副本的 Boss 傷害在玩家組團進副本的時候就計算好了,後面只要根據 Boss 的 AI 來進行觸發就行,把計算量壓到了最低,也是一種應用方式。
「假的」隨機(不須計算的亂數表隨機)
有些時候,隨機並不是在出現結果時才計算的。
就如同最前面寫的,對玩家而言,「隨機」意味著「不可預期」。因此只要能讓玩家不能預期,就能達到類似隨機的效果。
像是魔物獵人中有一個「護石鑑定」的系統,是將狩獵獲得的未知寶珠,丟給村莊內的NPC鑑定,會有類似抽轉蛋的感覺。
而這些「護石」鑑定後的內容,就是用一張「已經生成好的亂數表」來決定的。只要能找到玩家當前正處於亂數表的哪一個區域,就能精準刷出指定的鑑定結果。
這種方式也能避免單機玩家用不斷重讀存檔的方式來刷出想要的道具。
參考資料【心得】做一個有目的的礦工!如何有效的刷護石Clash Royale宝箱掉落顺序 皇室战争宝箱掉率有什么规律
延伸議題-常見的隨機配置表架構
無論是轉蛋還是福袋禮包,伺服端的隨機驗證都相當重要。
一般而言,業界的隨機用表單有固定的格式,會以「權重」和「分組」來進行配置。
在同一次隨機計算中,「同一組」的內容物「僅會被抽取到一次」。
而每一組內部單獨每一項的內容,被抽取到的機率為「自身的權重/同組全部權重相加」。
舉個例子,假設今天要設計一個禮盒,打開後的內容包括「固定3張掃蕩券」、「隨機顏色寶石x3顆」,以及有機率抽中「稀有裝扮兌換券x1」。
那麼配置表就會長成下面這個樣子:
其中掃蕩券固定會給,所以獨立自己一組。
各色寶石選一種顏色給,所以寶石們會分成一組,同時各顏色機率相等,所以權重都填寫為一樣即可。
最後,裝扮兌換券是「可能出現」也「可能不出現」的,因此配兩條項目,其中一條為空氣。抽中的機率為 10/(10+90) = 10%。
總結
「隨機」在現今的遊戲設計中扮演著不可或缺的角色,用的好的話,可以讓玩家的遊戲體驗更豐富,但同時也有可能造成負面效果。
這就跟成就感的營造需要難度合適的關卡一樣,隨機在遊戲內佔的比重太高或太低都有可能造成玩家的反感。如何與遊戲機制合併考量,設計出合適的隨機方案是設計師需要努力的目標。
希望這篇能提供大家一些不一樣的思路和方向。
那麼今天就先到這邊。
我是水狼,我們下次見。
也可以到臉書追蹤我喔: 粉絲專頁連結
最後,請多利用我的個人文章列表,會持續更新: