萬字長文,關於遊戲中道具設定和產出條件的相關設計,下篇

篇目1,解析鍛造系統對於玩家和開發者的作用

作者:Sande

武器/道具鍛造系統很早以前就是MMORPG中非常重要的一部分,它豐富了原本空洞而單調的遊戲世界。然而,對於這樣一種有效的娛樂手段,鍛造系統的發展史卻並非一帆風順。以前的遊戲總是充滿各種刷任務機制,無所用處的組件,並強迫玩家使用無聊的鍛造系統,甚至完全採納毫無用處的交易技能。

鍛造系統也可以是維繫着玩家與開發者關係的一個“彈簧”。如果玩家自己創造的內容與遊戲所提供的道具力量不均,那麼鍛造者和非鍛造者就會認爲鍛造系統是無用的,而不再與其他玩家進行比較,並責怪開發者糟糕的設計。

如何才能避免這種矛盾?矛盾的根源在於,鍛造對於開發者的作用與其對於玩家的作用是完全不同的。而平衡雙方需求便是化解這種矛盾的好方法,並且能夠幫助遊戲創造出一個合適的鍛造系統。

所以,鍛造系統對於玩家有何作用?

有助於緩解刷任務現象

對於玩家來說這應該說是最重要的作用吧。玩家總是喜歡變化,如果一款遊戲只是讓玩家一整天都在打怪,而沒有其它任務,他們肯定會對此感到厭煩並最終退出遊戲。而鍛造能夠在原本的殺戮-搶奪-殺戮模式中爲玩家提供替換式選擇,讓他們能夠以不同的方式控制角色的發展。

同時開發者還應該確保鍛造的易用性。這就意味着玩家能夠同時擁有戰鬥技巧和鍛造技巧,並且兩者間不會產生相互抵觸。玩家不需要非得從中做出選擇。同時鍛造還需要具有吸引力,不論是資料還是產品,都應包含有趣的選擇。肯定沒有哪個玩家希望用一種更無聊的刷任務機制取代原先的刷任務機制吧。

crafting(from massively.joystiq.com)

crafting(from massively.joystiq.com)

它是一種道具和貨幣來源

玩家可以從自己所創造的道具中獲得更多可觀的收益。甚至,如果玩家能夠使用自己鍛造的道具,他們便會萌生出一種自力更生感,即通過自己的努力而不斷增強戰鬥技巧。

而對於開發者來說,鍛造道具應該能夠有效地說服玩家願意花費他們辛苦所得的貨幣。這時候他們就需要想辦法保持鍛造產品與遊戲掉落道具之間的平衡。一大策略 便是在鍛造中包含非裝備性質的選項。如鍛造一些能夠消耗的物品,如藥劑,以確保需求的穩定,以及強化裝備威力的功能,如寶石或者能夠讓鍛造者提升道具(遊 戲邦注:可同時適用於遊戲掉落道具、玩家自己鍛造的道具)等。按照這種方法,獲得最佳裝備的角色便能夠同時地利用兩種遊戲玩法的優勢。

吸引建造和社交型玩家

有些玩家喜歡遊戲中的破壞,殺戮和掠奪;也有一些玩家更喜歡在城市中閒逛,與人交流並創造神奇的道具。他們會喜歡鍛造所推動的相互依賴和相互交流,願意與合作伙伴和好友分享並共同創造資源。

這些玩家便是這類遊戲最重要的玩家基礎,遊戲應該想辦法留住這些玩家。開發者應該努力創造一個具有吸引力且有趣的鍛造系統,但是卻不應該強求所有玩家不得不關注鍛造系統。一些系統採用即時戰鬥類行動而取代無聊的進度條。但是這麼做卻適得其反,因爲這會強迫玩家不得不在鍛造道具時停止社交行爲。相反地,鍛造應該更加靈活,讓玩家能夠按照自己的節奏進行。而這些有趣的行動應該在玩家點擊“創造”之前就表現出來,例如在選擇特定資源,資料或使用方法的時候。

創造有效的自定義機制

鍛造功能能夠按照不同方式吸引不同類型玩家的注意。對於那些喜歡角色創造的玩家來說,交易技能能夠讓角色更加與衆不同。對於社交遊戲玩家來說,他們能夠鍛造裝飾性道具去自定義角色和環境的外觀。對於戰鬥策略型玩家來說,定製屬於自己的裝備能夠增強角色的實力並提高戰鬥效率。

開發者總是會忽視自定義機制,因爲這需要花費他們更多的額外成本。但是如此做法所造成的損失卻是我們不容小覷的。如果鍛造者能夠定製角色或道具的外觀,這可以進一步增強玩家的沉浸感。遊戲掉落的道具只有原來的固定屬性,而如果鍛造道具的配方也只有一種固定屬性,那麼對玩家來說,鍛造道具與遊戲掉落道具之間並無多大區別,其吸引力也將大打折扣。

Vanguard-Crafting(from mmorpg.com)

Vanguard-Crafting(from mmorpg.com)

那麼,鍛造對於開發者來說有何作用?

強化遊戲的合理性

讓人悲哀的是,很多開發者只是因爲外部需求而在遊戲中添加鍛造機制。如此心態最終只能夠創造出糟糕的設計系統,並破壞了整款遊戲的合理性。

在設計一款強調用戶留存的遊戲,開發者在設計鍛造系統時更是應該仔細考慮玩家的想法。如果遊戲的目標是吸引特定玩家類型,如休閒玩家或戰鬥型玩家,遊戲可以適當放鬆鍛造系統的作用,但是同時應該添加能夠創造出同等利益的功能。如果鍛造系統是遊戲所必須的內容,開發者就應該關注預算分配等問題,而如果玩家不喜歡你的鍛造系統,那就只是徒勞無功的做法。

它能讓玩家投入更多遊戲時間

MMO中的任何系統都必須對玩傢俱有吸引力,並讓他們願意長時間玩遊戲。鍛造系統其實也是玩家角色發展的體現,結合戰鬥進程更能夠調動玩家的積極性,在遊戲中投入更多時間。

但是如果使用不合理,這種理念將會導致玩家不得不在鍛造系統中耗費更多時間。不必要的刷任務機制,較長的進度條以及對失敗的嚴厲懲罰都會導致玩家在鍛造中投入更多時間,但是同時卻會導致玩家在遊戲中產生更多挫敗感。帶有過多挫敗感的玩家很可能隨時停止玩遊戲。爲了避免這種情況,遊戲應該確保玩家始終能夠感受到某種意義上的進步。或許可以讓他們按照配方上的材料或其他交易技能中的組件來鍛造道具,或者通過經驗值而非隨機性的技能增長,讓他們獲得這種進步感。

創造玩家間的相互依賴感

作爲一種多人遊戲,MMO自然應該包含推動玩家交流與協作的機制。而鍛造系統便具有這種功效。它讓玩家能夠爲好友創造及增強道具能量,同時還能夠與他們分享所得的資源和材料。

創造玩家間相互協作的一大方法便是引入一種包括稀有掉落道具(或由其他交易技能鍛造材料)的配方,但這種配方必須具有特殊性,能夠製造出更多有益的道具。它不需要特別要求玩家爲了獲得一些基本道具進行協作,更不能對玩家做出升級技能的要求,否則只會讓玩家因更多時間和金錢投入而備受挫折。

創造強有力的經濟系統

強大的經濟系統能夠提高遊戲的用戶粘性,而如果開發者允許遊戲內部的貨幣交易,他們便有可能從中獲得更多實在的利益。鍛造系統是玩家間一種重要的交易方式。除此之外,它讓毛皮,尖牙,寶石等能夠用於商業交易的材料更凸顯其價值,並有效緩解遊戲經濟系統中的通貨鼓脹現象。

使用鍛造推動經濟發展的一大方法便是,引進可以讓讓所有玩家都受益的道具配方。其次就是提供多種材料的來源,例如交易商品,掉落的道具(稀有和普遍的),資源節點以及其它配方。設計適用於多種配方的材料以提升它們的需求量,同時增加僅適用於一種配方但卻極有用處的掉落道具數量。

總結

上述內容並非創建優秀鍛造系統的完整列表,其中要點也未必適用於同一款遊戲。開發者應該在衡量玩家的遊戲目標前優先考慮自己的目標,以便創造一種能夠讓大家各取所需的鍛造系統,並最終制作出一款強大的遊戲。

篇目2,分享爲怪物掉落道具編寫程序的經驗

作者:Kyatric

動作遊戲中的一個普遍機制就是讓敵人在臨死前掉落一些道具或者獎勵。角色就可以拾取這些戰利品從而增加自己的優勢。這是包括RPG在內的許多遊戲都有的一個機制,它給予玩家一個除掉敵人的動機——以及看到即時獎勵時的一點興奮感。

在本篇教程中,我們將查看這些機制的內在運行機制,以及如果用你所使用的編碼工具/語言將其植入遊戲中。

我使用Construct 2這種HTML5遊戲開發工具來展示這方面的例子,但其使用工具並不侷限於此。無論你使用哪種編程語言或工具,應該都能夠植入同樣的機制。

這些例子是由r167.2所製作,你可以在其軟件免費版本中打開和進行編輯。你還可以下載Construct最新版本來操作這些例子。

基本機制

ScreenShot1(from gamedevelopment)

ScreenShot1(from gamedevelopment)

在敵人死時的那一刻(它的HP已經極大減少,或者接近於0)會調用一個函數。該函數的作用就是確定敵人是否存在掉落物品,如果有,又該掉落哪種道具。

該函數還可以處理掉落物品的可視化表現形式, 令其協同敵人在前方屏幕中生成。

看看以下的例子。

0_ Owl is slain, and drops Lollipop.
1_ Goblin is slain, and drops Gold.
2_ Mastodon is slain.
3_ Mastodon is slain, and drops Gold.
4_ Squire is slain, and drops Lollipop.
5_ Owl is slain.
6_ ZogZog is slain, and drops Lollipop.
7_ Owl is slain.
8_ Mastodon is slain.
9_ Owl is slain.
10_ Goblin is slain, and drops Lollipop.
11_ ZogZog is slain.
12_ ZogZog is slain, and drops Lollipop.
13_ Squire is slain.
14_ Mastodon is slain.
15_ Boar is slain, and drops Lollipop.
16_ Mastodon is slain.
17_ Boar is slain, and drops Lollipop.
18_ Boar is slain, and drops Lollipop.
19_ Boar is slain, and drops Lollipop.
20_ Boar is slain, and drops Lollipop.
21_ Boar is slain, and drops Lollipop.
22_ Mastodon is slain, and drops Rocks.
23_ Boar is slain, and drops Lollipop.
24_ ZogZog is slain, and drops Lollipop.
25_ Squire is slain, and drops Lollipop.
26_ Boar is slain, and drops Lollipop.
27_ Squire is slain, and drops Gold.
28_ Owl is slain.
29_ Squire is slain.
30_ Squire is slain.
31_ ZogZog is slain, and drops Lollipop.
32_ Owl is slain, and drops Jewel.
33_ Squire is slain.
34_ Mastodon is slain, and drops Rocks.
35_ Owl is slain.
36_ Owl is slain.
37_ Owl is slain.
38_ ZogZog is slain.
39_ Goblin is slain.
40_ Mastodon is slain.
41_ Boar is slain, and drops Lollipop.
42_ Boar is slain, and drops Lollipop.
43_ ZogZog is slain, and drops Lollipop.
44_ Owl is slain.
45_ Owl is slain.
46_ Mastodon is slain, and drops Rocks.
47_ Squire is slain, and drops Gold.
48_ ZogZog is slain, and drops Lollipop.
49_ Squire is slain, and drops Gold.
50_ Goblin is slain, and drops Lollipop.
51_ Owl is slain.
52_ Mastodon is slain.
53_ Mastodon is slain, and drops Lollipop.
54_ Squire is slain, and drops Gold.
55_ Goblin is slain, and drops Lollipop.
56_ Mastodon is slain.
57_ ZogZog is slain, and drops Lollipop.
58_ Goblin is slain, and drops Lollipop.
59_ ZogZog is slain.
60_ ZogZog is slain.
61_ ZogZog is slain, and drops Lollipop.
62_ Boar is slain, and drops Lollipop.
63_ Goblin is slain, and drops Lollipop.
64_ Squire is slain, and drops Lollipop.
65_ Goblin is slain.
66_ ZogZog is slain, and drops Lollipop.
67_ Owl is slain, and drops Equipment.
68_ Boar is slain, and drops Lollipop.
69_ Boar is slain, and drops Lollipop.
70_ Squire is slain, and drops Gold.
71_ Owl is slain.
72_ Owl is slain.
73_ Goblin is slain, and drops Lollipop.
74_ ZogZog is slain, and drops Lollipop.
75_ ZogZog is slain, and drops Lollipop.
76_ Owl is slain, and drops Equipment.
77_ Goblin is slain, and drops Lollipop.
78_ Boar is slain, and drops Lollipop.
79_ Owl is slain.
80_ ZogZog is slain, and drops Lollipop.
81_ ZogZog is slain.
82_ ZogZog is slain, and drops Lollipop.
83_ Mastodon is slain.
84_ Owl is slain, and drops Equipment.
85_ Mastodon is slain.
86_ Squire is slain.
87_ Mastodon is slain.
88_ Boar is slain, and drops Lollipop.
89_ ZogZog is slain.
90_ ZogZog is slain, and drops Lollipop.
91_ ZogZog is slain.
92_ Mastodon is slain.
93_ Boar is slain, and drops Lollipop.
94_ Goblin is slain.
95_ Owl is slain, and drops Rocks.
96_ Mastodon is slain.
97_ ZogZog is slain, and drops Lollipop.
98_ Mastodon is slain.
99_ Squire is slain, and drops Lollipop.

這將執行一個創造100個隨機怪物,並殺死它們,然後展示每個怪物是否掉落道具這一結果的批量過程。屏幕底部將展示有多少怪物掉落道具,以及掉落了多少種類型的道具。

這個例子用文本來解釋是爲了呈現了該函數背後的邏輯,以及展示該機制適用於任何類型的遊戲,無論是踩踏敵人的平臺遊戲,還是上下視角的射擊遊戲,或是RPG。

讓我們看看這個樣本的運行方式。首先,怪物和掉落道具都有各自的陣列。以下是怪物陣列:

beast array(from gamedevelopment)

beast array(from gamedevelopment)

這是掉落道具陣列:

drops array(from gamedevelopment)

drops array(from gamedevelopment)

Index列中的X值是怪物或道具類型的獨特標識符。例如,指數爲0的怪物就是一隻野豬。而指數爲3的道具則是一個寶石。

這些陣列便於我們查找表格,它們包括每個怪物或道具的名稱和類型,以及將允許我們確定稀有性或掉落率的其他值。在怪物陣列中,其名稱後還有另外兩個欄目:

掉落率是怪物被殺死時掉落一項道具的機率。例如,野豬被殺死時有100%的道具掉落率,而貓頭鷹的這一機率僅爲15%。

稀有性決定了這隻怪物掉落某項道具的低概率。例如,野豬可能掉落某項稀有值爲100的道具。現在,讓我們看看drops陣列。我們可以看到岩石是擁有最大稀有值(95)的道具(遊戲邦注:雖然這裏的稀有值很高,但作者編寫這一函數時,爲更普遍的道具設置了更大的稀有值。也就是說,怪物掉落岩石的機率高於稀有值較低的道具。)

從遊戲設計角度來看,這對於我們來說非常有趣。爲了遊戲獲得平衡,我們並不希望讓玩家過早接觸太多裝備或過多高端道具——否則,角色可能會過早變得太強大,遊戲也就不再那麼有趣了。

這些表格和數值只是一些例子,你可以根據自己的遊戲系統和環境來進行調整,一切取決於你的系統平衡性。

讓我們看看樣本的僞代碼:

CONSTANT BEAST_NAME = 0
CONSTANT BEAST_DROPRATE = 1
CONSTANT BEAST_RARITY = 2
CONSTANT DROP_NAME = 0
CONSTANT DROP_RATE = 1
//Those constants are used for a better readability of the arrays

On start of the project, fill the arrays with the correct values
array aBeast(6,3) //The array that contains the values for each beast
array aDrop(6,2) //The array that contains the values for each item
array aTemp(0) //A temporary array that will allow us what item type to drop
array aStats(6) //The array that will contain the amount of each item dropped

On button clicked
Call function “SlainBeast(100)”

Function SlainBest (Repetitions)
int BeastDrops = 0 //The variable that will keep the count of how many beasts did drop item
Text.text = “”
aStats().clear //Resets all the values contained in this array to make new statistics for the current batch
Repeat Repetitions times
int BeastType
int DropChance
int Rarity
BeastType = Random(6) //Since we have 6 beasts in our array
Rarity = aBeast(BeastType, BEAST_RARITY) //Get the rarity of items the beast should drop from the aBeast array
DropChance = ceil(random(100)) //Picks a number between 0 and 100)
Text.text = Text.text & loopindex & ” _ ” & aBeast(BeastType,BEAST_NAME) & “is slain”

If DropChance > aBeast(BeastType,BEAST_DROPRATE)
//The DropChance is bigger than the droprate for this beast
Text.text = Text.text & “.” & newline
//We stop here, this beast is considered to not have dropped an item.

If DropChance <= aBeast(BeastType,BEAST_DROPRATE)
Text.text = Text.Text & ” dropping ” //We will put some text to display what item was dropped
//On the other hand, DropChance is less or equal the droprate for this beast
aTemp(0) //We clear/clean the aTemp array in which we will push entries to determine what item type to drop
For a = 0 to aDrop.Width //We will loop through every elements of the aDrop array
aDrop(a,DROP_RATE) >= Rarity //When the item drop rate is greater or equal the expected Rarity
Push aTemp,a //We put the current a index in the temp array. We know that this index is a possible item type to drop
int DropType
DropType = random(aTemp.width) //The DropType is one of the indexes contained in the temporary array
Text.text = Text.text & aDrop(DropType, DROP_NAME) & “.” & newline //We display the item name that was dropped
//We do some statistics
aStats(DropType) = aStats(DropType) + 1
BeastDrops = BeastDrops + 1
TextStats.Text = BeastDrops & ” beasts dropped items.” & newline
For a = 0 to aStats.width //Display each item amount that was dropped
and aStats(a) > 0
TextStats.Text = TextStats.Text & aStats(a) & ” ” & aDrop(a,DROP_NAME) & ” “

首先,是用戶行爲:點其Slay 100 Beasts可以調用一個參數爲100的函數,當然在真正的遊戲中,你可能一次只會殺死一隻怪物。

由此開始,調用SlainBeast函數。其目的展示一些文本,給予用戶反饋讓他們知道發生了什麼情況。首先,它會清除BeastDrops變量以及aStats陣列。在真正的遊戲中,你不可能會需要這些陣列。它也會清除Text,這樣你就可以看到這個批量數據的結果。函數本身會創造三個數值變量:BeastType, DropChance和Rarity。

BeastType將成爲我們涉及aBeast陣列的特定行,它實際上是玩家必須面對和殺戮的怪物類型。Rarity也同樣取自aBeast陣列,它是該怪物應該掉落的道具稀有性,道具稀有值位於aBeast陣列中。

最後,DropChance則是我們隨機從0到100挑選出來的一個數值(遊戲邦注:多數編程語言都有一個從某個範圍隨機獲取一個數值的函數,或者至少是從0到1獲得一個隨機數值,之後你可以將其簡單地乘以100)。

在這種情況下,我們可以展示位於Text對象中的一點信息:我們已經知道會生成和殺死哪種怪物。所以,我們要將從aBeast陣列中隨機挑選的當前BeastType的BEAST_NAME與當前的Text.text值連接起來。

接下來,我們必須確定某項道具是否應該掉落。我們可以通過對比來自aBeast陣列的DropChance值與BEAST_DROPRATE值來實現這一點。如果DropChance少於或者等同於這個值,我們就要掉落一個道具。

(注:你可以選擇“多於或等同於這個值”的方法來編寫這個函數,這只是一個數值和邏輯上的問題。但是,要保持算法的一貫性,不要半途更改邏輯——否則,你可能就會在調試或維護的時候產生問題。)

要用兩行代碼來確定某項道具是否掉落,首先:

DropChance > aBeast(BeastType,BEAST_DROPRATE)

這裏的DropChance在少於或等同於當前BeastType中的DropRate,所以我們可以認爲這意味着一項道具會掉落。爲此,我們將運行當前BeastType“允許”掉落道具的Rarity對比,以及我們已經在aDrop表格中設置好的一些稀有值。

我們查看aDrop表格,查找每個索引以便找到其DROP_RATE是否大於或等同於Rarity。(記住,Rarity值越高,該道
具就越普遍)針對匹配該對比的每個索引,我們會將該索引推向一個臨時陣列aTemp。

這DropChance遠比DropRate更大,我們認爲這意味着沒有道具會掉落。由此開始,唯一展現的東西就是句子末尾的一個全角句號“.”在移向我們批次的下一個敵人之前,“[BeastType]被殺掉”。

另一方面:

DropChance <= aBeast(BeastType,BEAST_DROPRATE)

在循環的最後,我們應該至少在aTemp陣列中設置一個索引。(否則,我們就必須重新設計aDrop和aBeast表格了!)我們之後可以製作一個新的數值變量DropType,從aTemp陣列中隨機挑選一個索引。這就是我們將會掉落的道具。

我們要在文本對象中添加道具名稱,形成類似“BeastType被殺死,掉落一個DROP_NAME”的句子。之後,爲了便於解釋,我們要在多個變量統計表中添加一些數值(添加到aStats陣列和BeastDrop中)。

最後,在重複100次後,我們展示這些統計數據,怪物掉落道具的數量,以及每種道具掉落的數量。

另一個例子:形象化地掉落道具

讓我們考慮另一個例子:

screenshot2(from gamedevelopment)

screenshot2(from gamedevelopment)

你可以從中看到,畫面中產生了一個隨機敵人。位於左側的玩家角色可以創造一次發射攻擊。當發射攻擊命中敵人時,敵人就會死。

在這裏,我們在之前的例子中所使用的相似函數可以決定敵人是否掉落了一些道具,並確定其掉落的道具類型。此時,它還會創造道具掉落的視覺形象,並更新屏幕底部的數值。

以下就是僞代碼的部署:

CONSTANT ENEMY_NAME = 0
CONSTANT ENEMY_DROPRATE = 1
CONSTANT ENEMY_RARITY = 2
CONSTANT ENEMY_ANIM = 3
CONSTANT DROP_NAME = 0
CONSTANT DROP_RATE = 1
//Constants for the readability of the arrays

int EnemiesSpawned = 0
int EnemiesDrops = 0

array aEnemy(11,4)
array aDrop(17,2)
array aStats(17)
array aTemp(0)

On start of the project, we roll the data in aEnemy and aDrop
Start Timer “Spawn” for 0.2 second

Function “SpawnEnemy”
int EnemyType = 0
EnemyType = random(11) //We roll an enemy type out of the 11 available
Create object Enemy //We create the visual object Enemy on screen
Enemy.Animation = aEnemy(EnemyType, ENEMY_ANIM)
EnemiesSpawned = EnemiesSpawned + 1
txtEnemy.text = aEnemy(EnemyType, ENEMY_NAME) & ” appeared”
Enemy.Name = aEnemy(EnemyType, ENEMY_NAME)
Enemy.Type = EnemyType

Keyboard Key “Space” pressed
Create object Projectile from Char.Position

Projectile collides with Enemy
Destroy Projectile
Enemy start Fade
txtEnemy.text = Enemy.Name & ” has been vanquished.”

Enemy Fade finished
Start Timer “Spawn” for 2.5 seconds //Once the fade out is finished, we wait 2.5 seconds before spawning a new enemy at a random position on the screen
Function “Drop” (Enemy.Type, Enemy.X, Enemy.Y, Enemy.Name)

Function Drop (EnemyType, EnemyX, EnemyY, EnemyName)
int DropChance = 0
int Rarity = 0
DropChance = ceil(random(100))
Rarity = aEnemy(EnemyType, ENEMY_RARITY)
txtEnemy.text = EnemyName & ” dropped ”

If DropChance > aEnemy(EnemyType, ENEMY_DROPRATE)
txtEnemy.text = txtEnemy.text & ” nothing.”
//Nothing was dropped
If DropChance <= aEnemy(EnemyType, ENEMY_DROPRATE)
aTemp.clear/set size to 0
For a = 0 to aDrop.Width
and aDrop(a, DROP_RATE) >= Rarity
aTemp.Push(a) //We push the current index into the aTemp array as possible drop index

int DropType = 0
DropType = Random(aTemp.Width) //We pick what is the drop index amongst the indexes stored in aTemp
aStats(DropType) = aStats(DropType) + 1
EnemiesDrops = EnemiesDrops + 1
Create Object Drop at EnemyX, EnemyY
Drop.AnimationFrame = DropType
txtEnemy.Text = txtEnemy.Text & aDrop.(DropType, DROP_NAME) & “.” //We display the name of the drop
txtStats.text = EnemiesDrops & ” enemies on ” & EnemiesSpawned & ” dropped items.” & newline
For a = 0 to aStats.width
and aStats(a) > 0
txtStats.text = txtStats.Text & aStats(a) & ” ” & aDrop(a, DROP_NAME) & ” ”

Timer “Spawn”
Call Function “SpawnEnemy”

先分別來看看aEnemy和aDrop表格的內容:

aEnemy(from gamedevelopment)

aEnemy(from gamedevelopment)

aDrop table(from gamedevelopment)

aDrop table(from gamedevelopment)

與之前的例子不同,包含敵人的陣列命名爲aEnemy,它還包括另一行數據ENEMY_ANIM,後者擁有敵人動畫的名稱。這樣,當畫面生成敵人時,我們就可以查看並自動化圖像播放。

同樣,aDrop現在包含16個而非6個元素,每個索引都涉及對象的動畫幀——但我也可能擁有多個動畫,就像針對敵人設置一樣,需要確定其掉落道具是否也需要動畫。

此時我們所需要的敵人和道具數量遠超過之前的例子。但你可以看到,與掉落率和稀有值相關的數據仍然存在。有一個顯著的區別就是,我們將計算是否存在掉落道具的函數所生成的敵人區別開了。這是因爲,在真正的遊戲中,敵人不會無動於衷地等着被玩家殺掉。

所以現在,我們有一個函數SpawnEnemy和另一函數Drop。Drop類似於我們在之前例子中處理道具掉落隨機性的方式,但這次要用到一些參數:其中兩個是屏幕上敵人的X和Y座標,因爲這正是我們想讓道具生成掉落的地方,另一個參數就是EnemyType,這樣我們就可以在aEnemy表格中查找敵人的名稱,以及一系列角色名稱,以便更快速地編寫爲玩家呈現的反饋。

Drop函數的邏輯與之前例子相似,變化最多的是我們呈現反饋的方式。這次我們不僅僅是呈現文本,我們還要在屏幕上生成一個對象,給予玩家一個視覺形象。

(注:爲了在屏幕多個位置生成敵人,我使用了一個隱形對象Spawn作爲參照,它可以持續左右移動。無論何時調用SpawnEnemy函數,它都會在Spawn對象當前座標創造敵人,這樣敵人就會出現在一系列水平位置上。)

最後要討論的是何時調用Drop函數。我並不會直接在敵人死亡的時候觸發它,而是在敵人淡出屏幕(這是敵人的死亡動畫)時才執行這一操作。你當然可以在敵人仍在屏幕上可見的情況下調用掉落函數,這取決於你的遊戲設計需求。

ScreenShot3(from gamedevelopment)

ScreenShot3(from gamedevelopment)

總結

在設計層面上看,讓敵人掉落一些戰利品可以爲玩家提供對抗和摧毀敵人的動力。掉落的道具可以爲玩家提供能量升級、狀態或目標,可以是直接或間接的方式。

從執行層面上看,掉落道具可以通過一個由程序員來決定何時調用的函數來管理。該函數要根據殺死敵人類型來執行檢查掉落道具稀有性的工作,也可以確定在屏幕何處生成道具。道具和敵人數據可以在類似陣列等數據結構中託管,並通過函數進行查找。

函數使用隨機數字來確定掉落道具的頻率和類型,由程序員來控制這些隨機性,其查找的數據,並調這些掉落道具在遊戲中的感覺。

希望本文能夠讓你更加理解如何在自己的遊戲中設置怪物道具掉落的情況。

篇目3,如何在遊戲設計中利用戰利品掉落表

作者:Daniel Cook

許多遊戲都帶有戰利品。通常情況下這些戰利品的分配都是隨機的。戰利品掉落是特別常見的主題,但卻也是每個設計師經常會覺得頭疼的內容。以下是我在過去幾年所遇到的最佳實踐。

你的基本戰利品表

這裏的目標是爲了基於特定機率掉落一組道具。假設當你打敗一個敵人,你便有機會獲得盾牌,稀有的劍,或者什麼都沒有。

例子

戰利品表

道具:

名字:劍

重量:10

道具:

名字:盾

重量:40

道具:

名字:空

重量:50

設置

道具:你想要提供給玩家的一種道具。

戰利品表:將一組道具放進戰利品表中。這只是一部分道具。例如一個戰利品表將包括:劍,盾,空。

重量:每個道具都帶有掉落重量:從1到10000。例如一把劍的掉落率可能是10。

空道具:戰利品表中會有一個道具是“空”,這意味着如果滾動到它,便不會掉落任何戰利品。

loop drop(from 3dmgame)

loop drop(from 3dmgame)

滾動戰利品

總概率:首先,計算戰利品表中的所有重量。在上述例子中便是10+40+50=100。因爲這些數值並不是百分比,所以它們並不需要加到100。

接下來分配每個道具的範圍。劍=1至10,盾=11至50,空=51至100。

從1至100生成一個隨機數。

將該數值與範圍進行比較。這便能夠決定到底會掉落哪種道具。

再次滾動:生成多個隨機數值去模擬多次滾動。

所以玩家會如何看待它們?我們設置劍的掉落機率爲10%,盾的掉落機率爲40%,而什麼都不會掉落的機率爲50%。

作爲設計師,我可以將空的重量改爲100,而現在我將劍的掉落機率設爲6.6%(10/150),盾的掉落機率爲26%(40/150),什麼都不會掉落的機率爲66%(100/150)。

映射到其它常見的隨機系統

這一系統只是在重申許多其它相似的隨機性方法。這是訓練你的設計師大腦在基於戰利品表,紙牌或篩子上理解任何隨機性問題間轉換的有趣方法。

紙牌

想象你能夠洗牌並獲取的橋牌。

橋牌上的每種紙牌類型都是一種道具。

特定類型的紙牌數量便是道具的重量。

洗牌等同於爲每種道具分配範圍並生成隨機數。

抽取紙牌等同於選擇掉落的道具。

現在常見的橋牌都擁有52張牌,但如果是基於戰利品表,你便可以不受約束地進行操作。你的橋牌擁有1000張各種類型的紙牌。或者它們可以提供與典型的撲克手所擁有的較小的橋牌。

篩子

篩子同樣也能夠映射到戰利品表上。

每一個獨立的篩子都是一張戰利品表。

篩子的每一面(1至N)便等同於道具。

篩子的每一面都擁有重量“1”(除非你是在使用超重的篩子!)。

多次滾動篩子代表多次滾動同一個戰利品表。所以2D6便等同於抽取一個帶有6種道具的戰利品表2次。

變量

既然我們定義了一個基本的戰利品表,我們還可以做些什麼?

變量:道具組合

你同樣也可以掉落戰利品組合。道具並不需要一定是單一的內容。例如我可以擴展它從而讓玩家同時獲得一個盾牌和一個生命藥劑。

例子

戰利品表

道具:

名字:劍

重量:10

道具:

名字:盾

名字:生命藥劑 數值:2

重量:40

道具:

名字:空

重量:50

變量:總是掉落

常見的需求是標記一個道具從而提升它的掉落頻率。這裏存在一種慣例,即帶有“-1”重量的道具將會更常掉落。

變量:可重複的隨機性

有時候你會希望能夠重複一個隨機滾動。例如當一名玩家保存了遊戲,並能在之後重新加載以避免糟糕的戰利品掉落結果,這將導致非常折騰的玩家行爲。而如果存在一種方法能夠避免這種情況,所有玩家都會很高興吧。

大多數臨時的僞隨機數生成程序都是使用一個種子值。只要你能夠保存該種子值,你便能夠再次運行隨機數生成程序並獲得同意的結果。

變量:無需改變而滾動

上述系統的問題在於玩家可能會一直滾到“空”。這也是玩家常常抱怨的結果。就像“我玩了3000多次卻從未獲得MegaGoldenLootGun!”。

在統計學中存在兩種基本的抽樣類型:

放回抽樣:你將從列表中抽取數值然後在記錄你所獲得的數值後,你會將它們放回去。如此你便有可能在下次抽取時擁有同樣的機率。

不放回抽樣:你將從列表中抽取數值,並且在你記錄之後便將其置於一邊。如此你在下次抽取時抽到該道具的機率便會下降,而抽到剩下道具的機率便會增加。

《俄羅斯方塊》便使用了不放回抽樣。每種俄羅斯方塊都有自己的戰利品表。每次你獲得一個特殊組塊時,它便會被移出列表。這種方法能夠保證你在長時間等待長方形組塊時將能獲得它。

以下是關於你在戰利品表中如何執行不放回滾動。

當你滾動一個道具時,將其的重量減少1。這也等同於將它的範圍和最大範圍減去1。

確保在玩家下次滾動時他們的戰利品表已經進行了修改。

變量:保證特殊的掉落道具

有時候不放回滾動不夠快,而你卻希望保證戰利品的掉落。暴雪便保證了特定稀有道具的掉落從而讓玩家無需長時間地刷道具。

你可以只是提升重量,但是隨着玩家多次玩遊戲,他們會感受到獲得某些有保證的道具的低頻率與獲得一種道具慢慢提升的機率之間的明確區別。

以下是關於如何執行有保證的掉落戰利品。

當你滾動任何無保證的道具時,減少X%無保證的道具重量。

X=100/在有保證的道具掉落前滾動的最大數量。

確保在玩家下次滾動時他們的戰利品表已經進行了修改。

例子

假設你想要在5個回合後劍能夠頻繁掉落,儘管它只擁有10%的掉落機率。

如此X=100/5或20%

所以每次當你滾到劍時,盾的重量便會下降8(40*0.2),而空的重量會下降10(50*0.2)。

在5個回合後,所有其它道具的重量將變成0,劍便會擁有100%的掉落機率。

變量:分等級的戰利品表

戰利品表通常都是新資源的來源。然而你很容易進入一種情境,即你掉落了太多或太少特殊資源。這時候一些限制將很有幫助。

一種解決方法便是使用不放回的分等級的戰利品表。當一種特殊資源用盡時,玩家將不再獲得該資源。我們在每日貨幣獎勵中便使用了這一方法。我們想要每天派發100個貨幣,並且不會超過這一數值。但是我們也想將其作爲戰利品系統的一部分。

創造兩個表:獎勵和每日貨幣。

讓主要的戰利品表參照每日貨幣表。

當選擇每日貨幣時,滾動列表並明確你獲得了多少貨幣。

例子

戰力品表:獎勵

道具:

名字:劍

重量:10

道具:

名字:每日貨幣

重量:40

道具:

名字:空

重量:50

戰利品表:每日貨幣

類型:不放回

更新率:每日

道具:

名字:貨幣,數值:1

重量:10

道具:

名字:貨幣,數值:10

重量:4

道具:

名字:貨幣,數值:50

重量:1

在上述例子中,玩家有40%的機會獲得貨幣。然後我們將滾動每日貨幣表並看看它們是否能夠基於10次獎勵每次1個貨幣,4次獎勵每次10個貨幣以及1次獎勵每次50個貨幣而在一天中獲得最多的100個貨幣。

當每日貨幣戰利品表空了時,它們只有在隔天更新時纔會再次被填滿。

變量:有條件的掉落

有時候你會想要測試是否應該基於一些外部變量去掉落道具。在《 Realm of the Mad God》中,我們便想要避免未創造任何傷害而殺死boss的“搭便車者”獲得戰利品。所以在戰利品表中,我們添加了檢查。如果滾動到戰利品表中的一種有價值的道具,我們便會檢查玩家對敵人所造成的傷害是否超過X%。

你可以基於玩家的級別或敵人的級別改變戰利品的有效性。就像我更傾向於使用多個較小的戰利品表,並且系統非常靈活,足以讓你能夠輕鬆地使用一些較大的列表和條件去創造數據。

變量:編輯器

你可以基於以下外部邏輯修改掉落物的數量或重量。例如擅長收集的玩家能夠獲得比不擅長收集的玩家2倍多的特殊掉落道具。或者你可以修改重量。較高級別的角色的所有道具可能擁有-50%的重量,這遠低於他們的級別。

其它使用

掉落物列表通常是用於掉落戰利品,但我們也可以在其它地方發現它們。

程序生成:使用列表去創造武器或角色。

AI:使用列表去選擇行爲,如攻擊或移動。

這可能有點愚蠢,但的確存在一些更好的方式去創造AI!一種方式便是將隨機性當成任何系統的一階模型。人類大腦是如何創造系統模型?我們爲系統創造了觀察報告。並注意到這些觀察值重複出現的頻率和趨勢。在之後我們開始理解“爲什麼”會發生某些情況以及每個部分之間的臨時關係。

在物理學中,我們經常會開玩笑地說,爲了創造一隻奶牛模型,即一個複雜的有機體,我們需要做的第一步便是“想象一隻球形的奶牛。”通過創造一個簡單的模型,我們便能夠以最低成本生成有用的見解。

很多時候,掉落表其實就是一個複雜系統的以人類爲中心的近似值。對於許多系統,大多數玩家的移動都不會超過一個基本的概率理解,所以創造更復雜的模型只會浪費時間。有效的遊戲設計是創造模型去最小化必要級別以創造出理想的遊戲體驗。

考慮:《龍與地下城》便基於必要的戰利品掉落表創造了完整的宇宙。這就是專注於最小化系統。

戰利品掉落表並不是你需要的唯一工具,但在很多情況下,它卻是一種很有效的工具。

程序生成思維實驗

以下是使用掉落表的簡單程序生成系統。存在許多其它方式能夠做到這點,但這卻是最需要你進行思考的方法。讓我們假設你想要創造一個程序生成敵人。

一開始先創造獨特的敵人列表。也許你的敵人是由移動類型,攻擊類型,防禦類型以及財寶類型所組成。

爲每種類型創造戰利品表。

基於強度提供給戰利品表中的每種道具能量值。例如,刀的攻擊可能較弱,那麼它的能量值便是5。而較大的鐵錘的能量值爲15。

創造另一個戰利品表。這是各種屬性的修改內容。例如,“強大”將爲攻擊增加20%的數值。你也可以將攻擊設爲“弱”,這將減少50%的數值。

現在讓我們生成一個敵人

設定一個目標:爲你的生成敵人設定一個目標能量。假設你想要一個擁有40能量值的敵人。

滾動:滾動每個部分並將其添加到列表上。

分數:添加所有的能量值去獲得一個分數。

調整:如果這些部分的總和超過目標值,那就爲較低的能量部分添加一個攻擊或滾動。如果總和低於目標值,那就爲較高的能量部分添加一個攻擊或滾動。

重複:重複這一過程直到你到達一個預期的錯誤門檻(遠離能量40)或者你耗盡了你想要消耗的迭代數。

現在你便擁有一個程序生成敵人。對於這一基本系統你可以進行多次調整,但它大多數情況下都是有用的。作爲練習,你可以想想:

排除列表:如果選擇了列表中的兩個部分,那就丟掉敵人再次滾動。

多重限制:基於多個標準進行評判的部分。需要注意的是,當你添加更多限制時,你便更加不可能聚集多重結果。

結論

任何時候都會出現關於隨機性的討論,並且也有許多次要問題會發揮作用。我建議你們能夠閱讀以下內容:

http://www.lostgarden.com/2012/12/understanding-randomness-in-terms-of.html

http://www.lostgarden.com/2012/12/understanding-randomness-in-terms-of.html

抵抗教條式的隨機性。作爲一個受過良好教育的設計師,你的美學選擇應該是基於親手實踐。這裏存在的一個經驗法則便是,在你成功使用一種設計工具創造出一些成功遊戲之前,你不能輕易批評這種設計工具。

篇目4,促進角色創造&資源管理的遊戲道具類型

作者:Koobazaur

什麼是“工具”道具?

在本文中,我將把工具定義爲一種可獲得的道具,即提供給玩家一種全新且非戰鬥能力去通過障礙。例如撬鎖工具將幫助玩家打開門,爪鉤將幫助他們攀升到一個全新高度,或者氧氣罩將讓他們能夠長時間待在水裏。

工具=能力[-]障礙

deus-ex-multitool(from gamingpoint.org)

deus-ex-multitool(from gamingpoint.org)

需要注意的是我特別排除了戰鬥工具,如武器或盾牌,因爲我想專注於那些用於打開新的前進方向或避免障礙(如守衛,所以就包含了潛行工具)的工具。我同樣也排除了在傳統RPG風格遊戲中通過升級而獲得的能力。然而,《生化奇兵》的補養藥卻包含在內,因爲它們的功能與道具很像。

典例:《殺出重圍》,《神偷》,《羞辱》,《塞爾達傳說》,《銀河戰士》,《生化奇兵》

工具的類型

着眼於各種遊戲,我總結出了工具的以下特徵:

獲取——玩家是如何獲取工具

給予——在某些點上工具是自動給予玩家(如《神偷》中的lockpics)

可發現的——可以在遊戲世界中的各種地方發現它們(如在《銀河戰士》,《塞爾達傳說》和《殺出重圍》中)

獨有的選擇——可以排除其它內容而選擇它(如《殺出重圍》中的AUG升級道具)

可購買的——可以通過使用某些貨幣進行購買(如在《生化奇兵》,《羞辱》中那樣)

永久性——玩家可以使用工具多長時間

無限的——能夠無限期地使用(如《神偷》的lockpicks,《銀河戰士》)

一次性——使用數量有限,如果想再次使用就需要再次獲取(如《殺出重圍》中的多功能工具)

基於燃料——能夠無限次地使用,但要求某些燃料或彈藥的補給(如《生化奇兵》的補養藥,《殺出重圍》的AUG)

可升級性——可改變或完善?

靜態的——始終保持一樣(如在《塞爾達傳說》和《銀河戰士》那樣)

可升級的(通過貨幣)——通過使用一些貨幣而獲得省級(如在《羞辱》中)

以下是一些例子:

super-metroid-items(from gamingpoint.org)

super-metroid-items(from gamingpoint.org)

《殺出重圍》中的多功能工具=可發現的+一次性+靜態的

《殺出重圍》中的AUG=可發現的+基於燃料+可升級的(通過貨幣)

《羞辱》中的能量=可購買的(通過貨幣)+基於燃料+可升級的

《神偷》中的繩索或青苔箭=可發現的/可購買的+一次性+靜態

《銀河戰士》的能量=可發現的+無限的+靜態的

當然,遊戲也可以基於單一規格混合多種道具特徵——就像《生化奇兵》中的某些補養藥便是給予的(如前面幾個)而有些則是可發現的(非必要的)。

我能想到的最複雜的例子便是《殺出重圍》的AUG——它們不只是要求燃料的可發現且一次性的選擇資源,同時也可以通過完全不同的資源獲得升級!

通過工具進行角色定製

工具能夠提供最基本的角色創造方法。工具的實用性,永久性,和可升級性定義了玩家選擇的靈活性和意義,以及他們的角色將具有多大的差別。

karas38_tempering_with_gears(from gamingport.org)

karas38_tempering_with_gears(from gamingport.org)

舉個例子來說,因爲工具的規格,《銀河戰士》具有非定製的線性角色創造—-你將在每次遊戲的幾乎同一個點上獲得工具,並且不能在之後升級它們。基於所有目的,武器例外,“角色創造”總是會基於同樣的方式發展。相反地,《殺出重圍》的AUG更加定製化且兩級化—-它們會要求你在兩個會對之後遊戲發展造成重要影響的內容中做出選擇。

《神偷》的箭就是個有趣的例子——你可以在每個階段購買它們,並且將看到各種不同的數量,在每個任務結束前你都可以自由地進行購買。《生化奇兵》允許玩家交換補養藥,但限制了升級它們的資源。

試驗

此外,工具的規格也影響了玩家能夠做試驗的次數。在此他們會提出一個問題“在致力於某一工具前我是否能夠給予基本形式去測試每種工具?”

在《殺出重圍》中,一旦玩家做出一個增強選擇,他便喪失了一個機會——他將永遠不會知道自己錯過了什麼。所以你並不能真正進行“試驗”。

另一方面,《神偷》在某些點上提供給你至少每種類型的箭中的一個,如此你便能夠在花錢辛苦獲得道具前對它們進行試驗。

我們還可以看到《生化奇兵》採取了一種中立的方法,即基於基本形式提供給你幾乎每一種補養藥,讓你決定升級哪一個。《羞辱》也是如此——玩家並不是基於每種能力開始遊戲,但是他們卻可以通過遊戲賺到足夠的貨幣去獲取基於基本形式的每種工具。

bioshock-loot-glint(from gamingpoint.org)

bioshock-loot-glint(from gamingpoint.org)

作爲資源的工具

在我看來,資源也是一種你能夠發現,獲得或購買的工具或貨幣/燃料,它們是有限供應或者是一次性的。包括一般彈藥,《殺出重圍》中的電池或《生化奇兵》中的藥劑。

當工具變成資源時情況會變得更有趣,它將引進一種管理和探索元素。例如《殺出重圍》中的多功能工具或《神偷》中的繩索/青苔箭便是如此。

相反地,《塞爾達傳說》中的大多數工具(遊戲邦注:如爪鉤或盾牌)便不屬於資源—-它們在遊戲世界中只有一個,並且不要求管理。炸彈則是例外,它們在遊戲世界中是一次性的且可發現的。

thief-dark-project-rope-arrows(from gamingpoint.org)

thief-dark-project-rope-arrows(from gamingpoint.org)

資源管理和探索

當工具作爲或依賴於資源時,它們將能提升遊戲玩法的深度——基於你的遊戲表現以及做出何種選擇,你將不斷“獲得”並“失去”能力。

再一次地,《殺出重圍》的多功能工具和lockpick,《神偷》的箭或《塞爾達傳說》的炸彈都是很棒的例子——它們都是探索的一種獎勵。

相反地,《銀河戰士》的工具或《塞爾達傳說》的爪鉤雖然能夠推動探索但卻不能基於自身去“鼓勵”它——你必須找到它們去推動股市的發展,所以你不能從技術上進行“探索”,只能走在預先設定好的設計之路。

平衡道具的難度

適當地設計並平衡工具很難。解釋並驗證每一個選擇也很難。《殺出重圍》中的游泳升級或水中呼吸器便是很好的例子,很少用例是在否定它們。襄樊地,你也會無法忍受某種過度設計的工具—-《羞辱》中一種閃光能夠讓你非常有效地完成每一個任務,從而導致其它工具變得無用。

此外,當工具是資源或依賴於資源時,我們將很難去平衡它們的數量,特別是考慮到玩家技能的不同以及隨機探索的能力時。一位資深的《神偷》玩家將能夠基於過多的箭而完成一個任務。但新手卻只能勉強維持下來。不同的難度級別能夠緩解這種情況,但每個設置中仍然存在着設計問題。

篇目1篇目2篇目3篇目4(本文由遊戲邦編譯,轉載請註明來源,或諮詢微信zhengjintiao)

篇目1,The Role of Crafting (Part I)

Sande

In this article, game designer Brendon Trombley looks at the various ways crafting adds to player experience in MMOs and how developers can use an understanding of these roles to build better crafting systems.

Since early on, crafting has been a major staple in the design of MMORPGs. Without some sort of crafting system, most online worlds would seem empty, nothing more than hack’n’slash mechanics wrapped around a leveling curve. Yet, for such a peaceful pastime, crafting has a sordid history. Past games have been fraught with resource grinds, wasted components, forced participation in crafting systems, useless recipes, and sadly, sometimes even useless tradeskills entirely.

Crafting can even be a source of strain between player and developer. If the balance of power between player-created and dropped items isn’t carefully calibrated, crafters and non-crafters can feel useless and neglected compared to the other and will blame the developer.

How can all this strife be avoided? A source of conflict is that crafting’s role for developers can differ greatly from its role for players. Reducing this conflict by addressing the needs of both parties is a good step towards a designing a successful crafting system.

So what’s the role of crafting for players?

It breaks up the grind

This is probably the single most important aspect for players. They crave variety, and if they get bored with fighting monsters all day and don’t have anything else to do, they might as well just log out. Crafting offers a satisfying alternate activity to the regular pattern of kill-loot-kill by giving them a separate form of character advancement.

Keeping this in mind, developers should keep crafting accessible to all players. That means allowing players to take both combat and crafting skills without negatively impacting each other. Players shouldn’t have to choose between the two. Crafting should also be kept engaging and include interesting choices, whether in the selection of materials, or the choice of product to make. No one wants to replace a grind with an even more tedious grind.

It’s a source of items and cash

Players derive a great source of satisfaction earning a tidy profit from the items they personally created. Even better, if they can personally use the items, they get to feel self-reliant seeing their own efforts augment their combat skills.

For developers, this means of course that crafted items must be useful to convince players to spend their hard-earned cash on them. This is where the tricky balance must be struck between crafting and dropped items. A great strategy is to include non-equipment niches in crafting. For instance, crafted consumables like potions ensure a steady demand, and equipment augments such as slot gems or enchantments allow crafters to increase the power of items, dropped or crafted. In this way, the best-equipped character is one who has taken advantage of both styles of play.

It appeals to constructive and social play styles

Some players don’t find rampaging around the world, destroying, killing, and pillaging everything they encounter terribly fun. Some would much rather hang out in cities, socialize, and create cool items. They enjoy the interdependency and community that crafting promotes, sharing or creating materials with their guildmates and friends.

These players are an important part of the player base, and retaining them should be prioritized properly. Developers should keep them in mind by creating a crafting system that is engaging and fun, but not demanding of all the player’s focus. Some systems have included real-time combat-like actions to replace boring progress bars. This could be a mistake, because it forces the player to stop socializing while they craft. Instead, crafting should be more cerebral, taken at one’s own pace. The interesting action should happen before the player clicks ‘create’, such as in the choosing and collecting of specific resources, materials, or recipes to use.

It creates greater customization

This is a feature of crafting that can appeal to different player types in different ways. For those interested in character-building, taking a tradeskill is a way to further differentiate their characters. For social players, making decorative items allows them to tailor the appearance of their characters and environments. For the combat strategists, the ability to customize their equipment allows them to maximize their stats and effectiveness in battle.

Fostering customization is a facet that is often neglected by developers, being as it tends to come with extra overhead cost. However, the loss of the potential benefits should not be taken lightly. When crafters can tailor the stats or appearance of their items, it greatly increases their engagement in the activity. Dropped items, by their nature, come as they are. When recipes also have locked-in stats, it seems to be a missed opportunity to differentiate those items from drops.(source:gamedesignaspect)

So what’s the role of crafting for developers?

It adds legitimacy to the game

It’s a sad fact that many developers include crafting in their game simply because they are expected to by the outside world. This leads to poorly designed systems that are added seemingly as an afterthought and can end up dragging the game down.

When designing in a genre where player retention is vitally important, developers should think carefully about their audience while considering crafting systems. If the game is meant to appeal to a specific player type, for instance casual or combat-oriented players, it may be possible to leave out crafting but include features that create similar benefits. Otherwise, if it’s decided that including crafting is indeed required, it should have the proper attention and budget allocated to it or players won’t use it, making it a wasted effort.

It gets players to spend more time playing

The goal of any system in an MMO should be to engage players and keep them willing to play the game over a long period of time. Crafting offers a form of character advancement that, when combined with combat advancement, creates plenty of motivation to spend time in the game.

When taken too far, this concept may lead to the addition of artificial time-sinks to crafting systems. Unnecessary grinding, long progress bars, and harsh penalties for failure may require the player to spend more time crafting, but at the cost of increased player frustration. Too much frustration, and there’s a chance they will stop the activity entirely. Avoid this by ensuring there’s always a sense of progress for the player. Perhaps the items they grind are ingredients for recipes down the line or components for other tradeskills. Perhaps advancement is based on experience rather than random skill-point increases.

It creates interdependency between players

MMOs, being multiplayer games, should of course include mechanics that foster player interaction and cooperation. Crafting systems are an effective way to do this. They allow players to create and enhance items for others, and promote the sharing of resources and materials.

A great way to create more cooperation between players is to include recipes with rare dropped components or ingredients crafted from other tradeskills. However, these recipes should be special exceptions that produce extra-useful items. Don’t require too much collaboration for basic items and especially not for regular advancement in the skill, or players will become frustrated at the extra time and money costs.

It promotes a strong economy

A strong economy increases player engagement and, if the developer so desires, can be a source of income if real-money trading of in-game currency is allowed. Crafting is a major source of trade between players. Additionally, it creates value in all those skins, fangs, gems, and other drops that would otherwise be merchant fodder. Merchant-bought components can help remove currency from a mostly positive-sum money system, reducing inflation.

Use crafting to promote the economy by first and foremost making the results of recipes worthwhile for all kinds of players. Then, create a variety of sources for ingredients: merchants, drops (rare and common), resource nodes, and other recipes. Create demand by designing ingredients to be useful in multiple recipes, and maximize the number of drops that are useful in at least one recipe.

Final thoughts

This is by no means a comprehensive list of all the ways to create a successful crafting system. Nor should all the tips here be included in the same game. Developers should instead prioritize their goals while thinking carefully about the goals of their audience. That way, they can craft a system that satisfies the needs of everyone as best they can, creating a stronger game in the end.

篇目2,How to Code Monster Loot Drops

by Kyatric25

A common mechanic in action games is for enemies to drop some kind of item or reward upon dying. The character can then collect this loot to gain some advantage. It is a mechanic that is expected in a lot of games, like RPGs, since it gives the player an incentive to get rid of the enemies—as well as a small blast of endorphins when discovering what the immediate reward is for doing so.

In this tutorial, we’ll review the inner workings of such a mechanic and see how to implement it, whatever the type of game and the coding tool/language you might be using.

The examples I use to demonstrate this were made using Construct 2, a HTML5 game making tool, but are in no way specific to it. You should be able to implement the same mechanic whatever your coding language or tool is.

The examples were made in r167.2 and can be opened and edited in the free version of the software. You can download the latest version of Construct 2 here (since I started writing this article, at least two newer versions have been released) and mess around with the examples to your liking. The example CAPX source files are attached to this tutorial in the zip file.

The Basic Mechanic

Upon an enemy’s death (so, when its HP is less than or equal to zero) a function is called. The role of this function is to determine whether there is a drop or not, and, if so, the kind of drop it should be.

The function can also handle the creation of the visual representation of the drop, spawning it at the former screen coordinates of the enemy.

Consider the following example :

Click the Slay 100 Beasts button. This will execute a batch process that creates 100 random beasts, slays them, and displays the result for each beast (that is, whether the beast drops an item, and, if so, what kind of item). Statistics at the bottom of the screen display how many beasts dropped items, and the how many of each type of item was dropped.

This example is strictly text to show the logic behind the function, and to show that this mechanic can be applied to any type of game, whether it is a platformer on which you stomp on the enemies, or a top-down view shooter, or an RPG.

Let’s look at how this demo works. First, the beasts and drops are each contained in arrays. Here’s the beast array:

Index (X)
Name (Y-0)
Drop rate (Y-1)
Item rarity (Y-2)
0 Boar 100 100
1 Goblin 75 75
2 Squire 65 55
3 ZogZog 45 100
4 Owl 15 15
5 Mastodon 35 50

And here’s the drops array:
Index (X)
Name (Y-0)
Item rarity (Y-1)
0 Lollipop 75
1 Gold 50
2 Rocks 95
3 Jewel 25
4 Incense 35
5 Equipment 15

The X value (the Index column) for the array acts as a unique identifier for the beast or item type. For example, the beast of index 0 is a Boar. The item of index 3 is a Jewel.

These arrays act as lookup tables for us, containing the name or type of each beast or item, as well as other values that will allow us to determine the rarity or the drop rate. In the beast array, there are two more columns after the name:

Drop rate is how likely the beast is to drop an item when slain. For example, the boar will have a 100% chance to drop an item when killed, whereas the owl will have a 15% chance to do the same.

Rarity defines how uncommon the items that can be dropped by this beast are. For example, a boar will be likely to drop items of a rarity value of 100. Now, if we check the drops array, we can see that the rocks is the item with the biggest rarity (95). (Despite the rarity value being high, due to the way I programmed the function, the bigger the rarity number is, the more common the item is. It has more chances to drop the rocks than an item with a lower rarity value.)

And that’s interesting to us from a game design perspective. For the balance of the game, we don’t want the player to get access to too much equipment or too many high-end items too soon—otherwise, the character might get overpowered too early, and the game will be less interesting to play.

These tables and values are just examples, and you can and should play with and adapt them to your own game system and universe. It all depends on the balancing of your system. If you want to learn more on the subject of balancing, I recommend checking out this series of tutorials: Balancing Turn-Based RPGs.

Let’s now look over the (pseudo)code for the demo:

CONSTANT BEAST_NAME = 0
CONSTANT BEAST_DROPRATE = 1
CONSTANT BEAST_RARITY = 2
CONSTANT DROP_NAME = 0
CONSTANT DROP_RATE = 1
//Those constants are used for a better readability of the arrays

On start of the project, fill the arrays with the correct values
array aBeast(6,3) //The array that contains the values for each beast
array aDrop(6,2) //The array that contains the values for each item
array aTemp(0) //A temporary array that will allow us what item type to drop
array aStats(6) //The array that will contain the amount of each item dropped

On button clicked
Call function “SlainBeast(100)”

Function SlainBest (Repetitions)
int BeastDrops = 0 //The variable that will keep the count of how many beasts did drop item
Text.text = “”
aStats().clear //Resets all the values contained in this array to make new statistics for the current batch
Repeat Repetitions times
int BeastType
int DropChance
int Rarity
BeastType = Random(6) //Since we have 6 beasts in our array
Rarity = aBeast(BeastType, BEAST_RARITY) //Get the rarity of items the beast should drop from the aBeast array
DropChance = ceil(random(100)) //Picks a number between 0 and 100)
Text.text = Text.text & loopindex & ” _ ” & aBeast(BeastType,BEAST_NAME) & “is slain”

If DropChance > aBeast(BeastType,BEAST_DROPRATE)
//The DropChance is bigger than the droprate for this beast
Text.text = Text.text & “.” & newline
//We stop here, this beast is considered to not have dropped an item.

If DropChance <= aBeast(BeastType,BEAST_DROPRATE)
Text.text = Text.Text & ” dropping ” //We will put some text to display what item was dropped
//On the other hand, DropChance is less or equal the droprate for this beast
aTemp(0) //We clear/clean the aTemp array in which we will push entries to determine what item type to drop
For a = 0 to aDrop.Width //We will loop through every elements of the aDrop array
aDrop(a,DROP_RATE) >= Rarity //When the item drop rate is greater or equal the expected Rarity
Push aTemp,a //We put the current a index in the temp array. We know that this index is a possible item type to drop
int DropType
DropType = random(aTemp.width) //The DropType is one of the indexes contained in the temporary array
Text.text = Text.text & aDrop(DropType, DROP_NAME) & “.” & newline //We display the item name that was dropped
//We do some statistics
aStats(DropType) = aStats(DropType) + 1
BeastDrops = BeastDrops + 1
TextStats.Text = BeastDrops & ” beasts dropped items.” & newline
For a = 0 to aStats.width //Display each item amount that was dropped
and aStats(a) > 0
TextStats.Text = TextStats.Text & aStats(a) & ” ” & aDrop(a,DROP_NAME) & ” ”

First, the user action: clicking on the Slay 100 Beasts button. This button calls a function with a parameter of 100, just because 100 feels like a good number of enemies to slay. In a real game, it’s more likely that you will slay beasts one by one, of course.

From this, the function SlainBeast is called. Its purpose is to display some text to give the user feedback on what happened. First, it cleans up the BeastDrops variable and aStats array ,which are used for the statistics. In a real game, it’s unlikely you will need those. It cleans the Text as well, so that a new 100 lines will be displayed to see the results of this batch. In the function itself, three numeric variables are created: BeastType, DropChance, and Rarity.

BeastType will be the index we use to refer to a specific row in the aBeast array; it’s basically the kind of beast that the player had to face and kill. Rarity is taken from the aBeast array as well; it’s the rarity of the item this beast should drop, the value of the Item rarity field in the aBeast array.

Finally, DropChance is a number we randomly pick between 0 and 100. (Most coding languages will have a function to get a random number from a range, or at least to get a random number between 0 and 1, which you could then simply multiply by 100.)

At this point, we can display our first bit of information in the Text object: we already know what kind of beast spawned and was slain. So, we concatenate to the current value of Text.text the BEAST_NAME of the current BeastType we’ve randomly picked, out of the aBeast array.

Next, we have to determine whether an item shall be dropped. We do so by comparing the DropChance value to the BEAST_DROPRATE value from the aBeast array. If DropChance is less than or equal to this value, we drop an item.

(I decided to go for the “less than or equal to” approach, having been influenced by these live role players using the D&D King Arthur: Pendragon set of rules regarding dice rolls, but you could very well code the function the other way around, deciding that drops will only occur when “greater or equal”. It’s just a matter of numeric values and logic. However, do stay consistent all through your algorithm, and don’t change the logic halfway—otherwise, you could end up with issues when trying to debug or maintain it.)

So, two lines determine whether an item is dropped or not. First:
1

DropChance > aBeast(BeastType,BEAST_DROPRATE)

Here, DropChance is greater than the DropRate, and we consider this to mean that no item is dropped. From there on, the only thing displayed is a closing “.” (full stop) that ends the sentence, “[BeastType] was slain.”, before moving on to the next enemy in our batch.

On the other hand:
1

DropChance <= aBeast(BeastType,BEAST_DROPRATE)

Here, DropChance is less than or equal to the DropRate for the current BeastType, and so we consider this to mean that an item is dropped. To do so, we will run a comparison between the Rarity of item that the current BeastType is “allowed” to drop, and the several rarity values we have set up in the aDrop table.

We loop through the aDrop table, checking each index to see whether its DROP_RATE is greater than or equal to Rarity. (Remember, counter-intuitively, the higher the Rarity value is, the more common the item is) For each index that matches the comparison, we push that index into a temporary array, aTemp.

At the end of the loop, we should have at least one index in the aTemp array. (If not, we need to redesign our aDrop and aBeast tables!). We then make a new numeric variable DropType that randomly picks one of the indices from the aTemp array.; this will be the item we drop.

We add the name of the item to our Text object, making the sentence to something like “BeastType was slain, dropping a DROP_NAME.”. Then, for the sake of this example, we add some numbers to our various statistics (in the aStats array and in BeastDrops).

Finally, after the 100 repetitions, we display those statistics, the number of beasts (out of 100) that dropped items, and the number of each item that was dropped.
Another Example: Dropping Items Visually

Let’s consider another example:

Press Space to create a fireball that will kill the enemy.

As you can see, a random enemy (from a bestiary of 11) is created. The player character (on the left) can create a projectile attack. When the projectile hit the enemy, the enemy dies.

From there, a similar function to what we’ve seen in the previous example determines whether the enemy is dropping some item or not, and determine what the item is. This time, it also creates the visual representation of the item dropped, and updates the statistics at the bottom of the screen.

Here is an implementation in pseudocode :

CONSTANT ENEMY_NAME = 0
CONSTANT ENEMY_DROPRATE = 1
CONSTANT ENEMY_RARITY = 2
CONSTANT ENEMY_ANIM = 3
CONSTANT DROP_NAME = 0
CONSTANT DROP_RATE = 1
//Constants for the readability of the arrays

int EnemiesSpawned = 0
int EnemiesDrops = 0

array aEnemy(11,4)
array aDrop(17,2)
array aStats(17)
array aTemp(0)

On start of the project, we roll the data in aEnemy and aDrop
Start Timer “Spawn” for 0.2 second

Function “SpawnEnemy”
int EnemyType = 0
EnemyType = random(11) //We roll an enemy type out of the 11 available
Create object Enemy //We create the visual object Enemy on screen
Enemy.Animation = aEnemy(EnemyType, ENEMY_ANIM)
EnemiesSpawned = EnemiesSpawned + 1
txtEnemy.text = aEnemy(EnemyType, ENEMY_NAME) & ” appeared”
Enemy.Name = aEnemy(EnemyType, ENEMY_NAME)
Enemy.Type = EnemyType

Keyboard Key “Space” pressed
Create object Projectile from Char.Position

Projectile collides with Enemy
Destroy Projectile
Enemy start Fade
txtEnemy.text = Enemy.Name & ” has been vanquished.”

Enemy Fade finished
Start Timer “Spawn” for 2.5 seconds //Once the fade out is finished, we wait 2.5 seconds before spawning a new enemy at a random position on the screen
Function “Drop” (Enemy.Type, Enemy.X, Enemy.Y, Enemy.Name)

Function Drop (EnemyType, EnemyX, EnemyY, EnemyName)
int DropChance = 0
int Rarity = 0
DropChance = ceil(random(100))
Rarity = aEnemy(EnemyType, ENEMY_RARITY)
txtEnemy.text = EnemyName & ” dropped ”

If DropChance > aEnemy(EnemyType, ENEMY_DROPRATE)
txtEnemy.text = txtEnemy.text & ” nothing.”
//Nothing was dropped
If DropChance <= aEnemy(EnemyType, ENEMY_DROPRATE)
aTemp.clear/set size to 0
For a = 0 to aDrop.Width
and aDrop(a, DROP_RATE) >= Rarity
aTemp.Push(a) //We push the current index into the aTemp array as possible drop index

int DropType = 0
DropType = Random(aTemp.Width) //We pick what is the drop index amongst the indexes stored in aTemp
aStats(DropType) = aStats(DropType) + 1
EnemiesDrops = EnemiesDrops + 1
Create Object Drop at EnemyX, EnemyY
Drop.AnimationFrame = DropType
txtEnemy.Text = txtEnemy.Text & aDrop.(DropType, DROP_NAME) & “.” //We display the name of the drop
txtStats.text = EnemiesDrops & ” enemies on ” & EnemiesSpawned & ” dropped items.” & newline
For a = 0 to aStats.width
and aStats(a) > 0
txtStats.text = txtStats.Text & aStats(a) & ” ” & aDrop(a, DROP_NAME) & ” ”

Timer “Spawn”
Call Function “SpawnEnemy”

Take a look at the contents of the aEnemy and aDrop tables, respectively:

Index (X)
Name (Y-0)
Drop rate (Y-1)
Item rarity (Y-2)
Animation name (Y-3)
0 Healer Female 100 100 Healer_F
1 Healer Male 75 75 Healer_M
2 Mage Female 65 55 Mage_F
3 Mage Male 45 100 Mage_M
4 Ninja Female 15 15 Ninja_F
5 Ninja Male 35 50 Ninja_M
6 Ranger Male 75 80 Ranger_M
7 Townfolk Female 75 15 Townfolk_F
8 Townfolk Male 95 95 Townfolk_M
9 Warrior Female 70 70 Warrior_F
10 Warrior Male 45 55 Warrior_M
Index (X)
Name (Y-0)
Item rarity (Y-1)
0 Apple 75
1 Banana 50
2 Carrot 95
3 Grape 85
4 Empty potion 80
5 Blue potion 75
6 Red potion 70
7 Green potion 60
8 Pink Heart 65
9 Blue pearl 15
10 Rock 100
11 Glove 25
12 Armor 30
13 Jewel 35
14 Mage Hat 65
15 Wood shield 85
16 Iron axe 65

Unlike the previous example, the array that contains the enemy data is named aEnemy and contains one more row of data, ENEMY_ANIM, which has the name of the enemy’s animation. This way, when spawning the enemy, we can look this up and automate the graphical display.

In the same vein, aDrop now contains 16 elements, instead of six, and each index refers to the animation frame of the object—but I could have had several animation as well, as for the enemies, if the dropped items were to be animated.

This time, there are far more enemies and items than in the previous example. You can see, though, that the data regarding drop rates and rarity values is still there. One notable difference is that we have separated the spawning of the enemies from the function that calculates if there is a drop or not. This is because, in a real game, enemies would likely do more than just wait on screen to be slain!

So now we have a function SpawnEnemy and another function Drop. Drop is pretty similar to how we handled the “dice roll” of our item drops in the previous example, but takes several parameters this time: two of these are the X and Y coordinates of the enemy on screen, since that’s the place where we will want to spawn the item when there is a drop; the other parameters are the EnemyType, so we can look up the name of the enemy in the aEnemy table, and the name of the character as a string, to make it quicker to write the feedback we want to give to the player.

The logic of the Drop function is otherwise similar to the previous example; what mostly changes is the way we display feedback. This time, instead of just displaying text, we also spawn an object on screen to give a visual representation to the player.

(Note: To spawn the enemies on several position on screen, I used an invisible object, Spawn, as reference, which continually moves left and right. Whenever the SpawnEnemy function is called, it creates the enemy at the current coordinates of the Spawn object, so that the enemies appear and a variety of horizontal locations.)

One last thing to discuss is when exactly the Drop function is called. I don’t trigger it directly upon an enemy’s death, but after the enemy has faded away (the enemy’s death animation). You can of course call for the drop when the enemy is still visible on screen, if you prefer; once again, that is really down to your game design.

Conclusion

On a design level, having enemies drop some loot gives an incentive to the player to confront and destroy them. The items dropped allow you to give power-ups, stats, or even goals to the player, whether in a direct or indirect way.

On an implementation level, dropping items is managed through a function that the coder decides when to call. The function does the job of checking the rarity of the items that should be dropped according to the type of enemy killed, and can also determine where to spawn it on screen if and when needed. The data for the items and enemies can be held in data structures like arrays, and looked up by the function.

The function uses random numbers to determine the frequency and type of the drops, and the coder has control over those random rolls, and the data it looks up, to adapt the feel of those drops in the game.

I hope you enjoyed this article and have a better understanding of how to make your monsters drop loots in your game. I’m looking forward to seeing your own games using that mechanic.

篇目3,Loot drop best practices

by Daniel Cook

Many games have loot. Usually this drops randomly. Loot drops are a pretty mundane topic, but one that almost every designer runs into at some point. Here are some best practices I’ve encountered over the years. Many thanks to everyone who contributed to these tips and tricks.

Your basic loot table

The goal is to drop some set of items at a given probability. Let’s say when you defeat an enemy, you have a chance of getting shield, a rare sword or nothing at all.

Example

lootTable
item:
name: sword
weight: 10
item:
name: shield
weight: 40
item:
name: null
weight: 50

Setup

Item: An item is something you want give the player.

Loot Table: A set of items is put into a loot table. This is just a bucket of items. For example a loot table might include: Sword, Shield, Null.

Weight: An item has a drop weight: 1 to 10,000. For example a sword might have a drop rate of 10.

Null items: One of the items in the loot bucket is ‘null’ which means if that is rolled, no loot is given

Rolling for loot

Total probability: First, sum all the weights in the bucket. In the example above, that’s 10+40+50 = 100. They don’t need to add up to 100 since these aren’t percentages.

Next assign each item a range. Sword = 1-10, Shield = 11 to 50, Null = 51 to 100

Generate a random number from 1 to 100.

Compare that number to the ranges. That’s the item that drops.

Reroll: Generate multiple random numbers to simulate multiple rolls.

So what does this look like to the player? We’ve got a 10% chance of dropping a sword, a 40% chance of dropping a shield and a 50% chance of getting nothing.

As the designer, I could go in and change Null’s weight to 100 and now I’ve got a 6.6% (10/150) chance of dropping a sword, a 26% (40/150) chance off dropping a shield and a 66% (100/150) chance of dropping nothing.

Mapping onto other common random systems

This system is a simple restating of many other familiar methods of randomness. It is a fun superpower to train your designer brain to be able to switch between understanding any randomness issue in terms of loot tables, cards or dice.

Cards

Imagine deck of cards that you can shuffle and draw from.

Each type of card in the deck is an item.

The number of cards of a given type is that item’s weight

Shuffling the deck is equivalent to assigning each item to a range and generating a random number.

Drawing a card is the equivalent of selecting the item that drops.

Now a normal deck of cards has 52 cards, but with loot tables, you don’t need to operate with that constraint. Your decks could have 1000′s of cards and a vast array of types. Or they could have tiny decks that are the equivalent of a typical poker hand.

Dice

Dice also map onto loot tables.

Each individual dice is a loot table.

The sides (1-N) are items (labeled 1 through N)

Each side gets a weight of ‘1’. (Unless you are using weighted dice!)

Multiple dice can be represented as rolling the same loot table multiple times. So 2D6 is the equivalent of sampling a 6 item loot table twice.

Variations

Now that we’ve defined a basic loot table, what else can we do with it?

Variation: Items sets

You can also drops sets of loot. An item doesn’t need to be a single thing. For example, I could extend it so that the players gets a shield and a health potion if that option is selected.

Example

lootTable

item:
name: sword
weight: 10
item:
name: shield
name: healthPotion number: 2
weight: 40
item:
name: null
weight: 50

Variation: Always drop

A common need is to flag an item so it always drops. One convention is that items with weight ‘-1′ always drop.

Variation: Repeatable randomness

Sometimes you want to be able to repeat a random roll. For example, when a player saves a game and then is able to reload to avoid a bad loot drop, it can lead to very grindy player behavior. If there is an exploit that ruins the game for them, most will happily go for it.

Most contemporary pseudo random number generators use a seed value. As long as you can save that seed value, you can run the random number generator again and get the same result.

Variation: Rolling without replacement

The problem with the system above is that players may, through chance alone, always roll ‘null’. This is a common complaint by players. “I played that encounter 3000 times and never got the MegaGoldenLootGun!” This can happen.

In statistics, there are two fundamental types of sampling:

Sampling with replacement: You pull the numbers out of the bucket and then after you’ve recorded what you got, you put them back in. So you have the same chance of getting the same thing again in the next draw.

Sampling without replacement: You pull the item out of the bucket and once you’ve recorded it, you set it aside. You have a lower chance of getting that item again and thus a higher chance of getting the remaining items.

Tetris uses sampling without replacement. Each set of Tetris pieces is in a loot table. Every time you get a specific piece, it is removed from the bucket. That way they guarantee that you’ll always get a long piece if you wait long enough.

Here’s how you implement rolling without replacement in a loot table.

When you roll an item, reduce its weight by 1. This shorten its range by 1 and shortens the max range by 1 as well.

Keep the player’s modified loot table around for the next time you roll.

Variation: Guaranteeing specific drops

Sometimes even rolling without replacement isn’t fast enough and you want to guarantee a loot drop. Blizzard does this for certain rare drops so that players don’t grind for very long times.

You could just increase the weight, but a low chance of getting something with a guarantee can feel very different over multiple plays than a slowly increasing chance of getting an item.

Here’s how you implement guaranteed loot drops.

When you roll any non-guaranteed item, reduce all non-guaranteed items weight by X%

X = 100 / Max number of rolls you before the guaranteed items drop.

Keep the player’s modified loot table around for the next time you roll.

Example

Suppose you want the sword to always drop after 5 turns even though it it only has a 10% chance of dropping.

So X = 100 / 5 or 20%.

So every time you don’t roll the Sword, the weight for the Shield drops 8 (40*0.2) and the weight for null drops 10 (50*0.2)

After 5 turns, the weight for all the other items will be 0 and the sword will have a 100% chance of dropping.

Variation: Hierarchical loot tables

Loot tables are generally source for new resources. However, you can easily run into situations where you are dropping too much or too little of a particular resource. Some sort of constraints would be helpful.

One solution is to use hierarchical loot tables without replacement. When a particular resource runs out, the player doesn’t get any more. We’ve used this for our daily coin awards. We want to give out 100 coins a day, but no more. But we want to do it as part of the loot system.

Create two tables: Rewards and DailyCoins.

Have the main loot table reference the Daily Coins bucket.

When Daily Coins get picked, roll that table and see how many coins you get.

Example

lootTable: Rewards
item:
name: sword
weight: 10
item:
name: dailyCoins
weight: 40
item:
name: null
weight: 50
lootTable: dailyCoins
type: noReplacement
refreshRate: Daily
item:
name: coin, number: 1
weight: 10
item:
name: coin, number 10
weight: 4
item:
name: coin, number: 50
weight: 1

In the example above, a player has a 40% chance of getting coins. Then we roll the dailyCoins table and see that they can win a maximum of 100 coins a day with 10 awards of 1 coins, 4 awards of 10 coins and 1 award of 50 coins.

When the dailyCoins loot table is emptied, they’ll get nothing until it refreshes after a day.

Variation: Conditional drops

Sometimes you want to test if you should drop the items base off some external variable. In Realm of the Mad God, we wanted to avoid free riders getting loot for a boss kill without doing at least some damage. So in the loot table, we added a check. If a valuable item in the loot table was rolled, then we’d check to see if the player had done more than X% of damage to the enemy.

You could also build in switches for which loot is valid based off player level or even enemy level. I tend to instead use multiple smaller loot tables, but the system is flexible enough that you can easily architect your data with a few large tables and use of conditionals.

Variation: Modifiers

You can also modify the quantity or weight of a drop based off some external logic. For example, a player with a skill in harvesting could yield 2x as many of a particular item drop compared to a player without that skill. Or you could modify the weight. A high level character might have a -50% weight for all items marked lower than their level.

Other uses

Drop tables are commonly used for dropping loot. But I also find them useful in other areas.

Procedural generation: Use a table to build weapons or characters from components

AI: Use a table to select behaviors such as attacks or moves.

This may seem a little silly..surely there are better ways to model AI! However, one way to think about randomness is that it is a very rough first order model of any system. How does the human brain model a system? We make an observation about a system. We note the frequencies and tendencies for those observations to reoccur. It is only much, much later that we start to understand ‘why’ something happens or the causal relationship between parts.

In physics, we often joke that in order to model a cow, a complex biological organism, the first step is to ‘imagine a spherical cow’. By creating a simplistic, easy to work with model, we can often generate useful insights at a very low cost.

Many times, a drop table is a ‘good enough’ human-centric approximation of a complex system. For many systems, most players will never move beyond a basic probabilistic understanding so modeling more complexity is a waste of time. Efficient game design is an exercise in modeling elements only to the minimum level necessary to create the desired experience.

Consider: D&D modeled entire universes with what were essentially loot drop tables. That was a deliberate focus on minimizing systems that were in many ways just secondary flavoring to the core roleplaying.

A loot drop table isn’t the only tool you need, but in many scenarios, it is good enough.

Procedural generation thought experiment

Here’s a simple procedural generation system using drop tables. There are lots of other ways to do this, but this is more to get your brain thinking. Let’s say you want to build a procedurally generated enemy

Start by making a list of unique enemy parts. Maybe your enemy is made up of a type of movement, a type of attack, a defensive buff and a type of treasure.

Make loot tables for each one of those parts.

For each item in the loot table, give it a power value based off how powerful you think it might be. for example, a knife attack might be weak so it only has a power of 5. But a large hammer attack might have a power of 15.

Create another loot table of buffs. These are modifiers to various attributes. For example, ‘Strong’ boost a value on an attack by 20%. You can have debuffs as well ‘Weak’ might diminish a value by -50%. These have reduce the power value of a part.

Now let’s generate an enemy

Set a target: Set a target power for your generated enemy. Say you want an enemy of power 40

Roll: Roll each of the parts once and add them into a list.

Score: Add up all the power values to get a score.

Adjust: If the sum of the parts is over the target, add a debuff or roll for a lower power part. If it is under, add a buff or roll for a higher power part.

Repeat: Repeat this process until you hit a desired error threshold (distance from power 40) or you’ve exhausted the number of iterations you are willing to spend.

You now have a procedurally generated enemy. There are tons of tweaks you can do to this basic system, but it works most of the time. As an exercise, think about:

Exclusion lists: If two parts are picked that are on the list, throw the enemy away and reroll.

Multiple constraints: Parts are scored on multiple criteria. Note, the more constraints you add, the less likely you are to converge on a viable result.

Conclusion

Any time there’s a discussion of randomness, there’s a huge number of secondary issues that come into play. I recommend the following for further reading:

Understanding randomness in terms of mastery: http://www.lostgarden.com/2012/12/understanding-randomness-in-terms-of.html

Richard Garfield on Luck: https://www.youtube.com/watch?v=av5Hf7uOu-o

Resist being dogmatic about randomness. Be a broadly educated designer whose aesthetic choices are based on hands on experimentation. A good rule of thumb is that you can’t intelligently critique a design tool until you’ve made a couple games that use it successfully.

Anyway, this is just how I’ve done loot tables; a mundane part of any working designer’s life. I’m curious if other folks have other ways of managing loot (and randomness) that they love and live by.

篇目4,Game Items as Character Building and Resource Management

by Koobazaur

What is a “Tool” Item?

In this article, I am defining a tool as an acquirable item that provides the player with a new, non-combat ability to get past obstacles. For example a picklock might allow the player to open doors, a grappling hook may let them climb to new heights, or an oxygen mask stay longer underwater.

Tool = Ability [-] Obstacle

Note I am specifically excluding combat tools, such as weapons or shields, as I want to focus on tools that open up new paths or avoid obstacles (including guards, so Stealth tools are in). I am also not counting abilities acquired purely via upgrading stats in a traditional RPG fashion. However, I am still including tonics in Bioshock, as they function more like items.

Role Models: Deus Ex, Thief, Dishonored, Zelda, Metroid, Bioshock

Dimensions of Tools

Looking at a variety of games, I propose the following characteristics of a tool:

Acquisition – how the tool is acquired by the player

Given – the tool is automatically given to the player at some point (i.e. Thief’s lockpics)

Findable – it can be found somewhere in the world (i.e. Metroid, Zelda, Deus Ex)

Exclusive Choice – it can be chosen at the exclusion of others (i.e. Deus Ex AUG upgrades)

Purchasable – it can be purchased via some currency (i.e. Bioshock, Dishonored)

Permanence – how long does the tool stay with the player

Unlimited – can be used indefinitely (i.e. Thief’s lockpicks, Metroid)

Disposable – can only be used a finite amount of times and needs to be re-acquired (i.e. Deus Ex Multitools)

Fuel-based – can be used indefinitely but requires some fuel or ammo to use (i.e. Bioshock’s tonics, Deus Ex AUGs)

Upgradability – can the tool be changed or improved?

Static – always stays the same (i.e. Zelda, Metroid)

Upgradable (by finding) – can be upgraded by finding a newer version, or some other resources (i.e. Bioshock tonics, Deus Ex AUGs)

Upgradable (by currency) – can be upgraded by spending some currency (i.e. Dishonored)

Here’s a few examples:

Deus Ex multitools = Findable + Disposable + Static

Deus Ex AUGs = Findable + Fueled + Upgradable (by currency)

Dishonored Powers = Purchasable by currency + Fueled + Upgradable

Thief Rope or Moss arrows = Findable/Purchasable + Disposable + static

Metroid powers = Findable + Unlimited + Static

Of course, games can mix multiple characteristics in a single dimensions – some of Bioshock’s tonics are Given (like the first few forced on the player) while others Findable (non-essential).

The most complex case I can think of are Deus Ex AUGs – not only are they Findable, Exclusive Choice Resource that requires Fuel, but they can also be upgraded via a whole different resource. Crazy!

Character Customization via Tools

Tools provide the most basic method of character building. Tool availability, permanence and upgradability defines how flexible and meaningful player choices are, and how polarized their character becomes.

For instance, Metroid has linear character building with no customization due to the dimensions of its tools – you get the tools at almost exact points in each playthrough and cannot upgrade them after. With exception of weapons, for all intents and purposes, the “character building” always progresses the same way. Conversely, Deus Ex AUGs are far more customizable and polarized – they force you to choose between two options which have critical implications for the rest of the game.

An interesting case is Thief arrows – you can purchase them on each stage, in varying amounts, giving you a lot of freedom and a blank slate before each mission. Bioshock allows for similar hot-swappability of the tonics, but limits the resources for upgrading them.

Experimentation

Furthermore, tool dimensions also influence how much experimentation the player is allowed. The question posed is “do I get to test each tool in some basic form before committing to one?”

In Deus Ex, once an augmentation choice is made, an opportunity is lost – you will never know what you missed out on. Ergo, you can’t really “experiment.”

On the other hand, Thief gives you at least one of each type of arrow at some point so you get to play around and experiment with them before deciding which ones you want to fork your hard-earned (well, stolen) cash on.

We can see a middle-ground approach in Bioshock, giving you almost every tonic in its basic form and letting you decide which to upgrade. Another way of achieving that is seen in Dishonored, – player doesn’t start with every ability, but they can earn enough currency throughout the game to acquire each one in its basic form.

Tools as Resources

In my definition, a resource is an item or currency/fuel you find, receive, or purchase, which has a limited supply, and is disposable. So anything from generic ammo, to batteries in Deus Ex, or Bioshock’s potions.

Now things get interesting when a tool becomes a resource – it introduces an element of management and exploration discussed below. Such was the case for multitools in Deus Ex or rope/moss arrows in Thief.

Conversely, most Zelda tools (like a grappling hook or a shield) are not a resource – there is exactly one of each in the world and they don’t require management. Bombs are one exception, however, as they are disposable and findable throughout the world.

Resource Management and Exploration

When tools act as, or rely on, resources, they increases the depth of gameplay – abilities are constantly “obtained” and “lost” back and forth depending on how you play and what choices you make.

Again, Deus Ex multitools and lockpicks, Thief’s arrows, or Zelda’s Bombs are a great example – they both enable and are a reward for exploration.

Conversely, Metroid’s tools or Zelda’s grappling hook enable exploration but do not “encourage” it by themselves – you must find them to advance the story, so you aren’t technically “exploring”, just playing the predefined design path.

Difficulties in Balancing Items

It is tricky to design and balance tools properly. It’s hard to account and validate each choice. Such was the case of the swimming upgrades or aqualungs in Deus Ex, which had so few use cases they were a waste. Conversely, you can also overpower a tool by over-designing – a maxed out blink in Dishonored will let you accomplish every single objective extremely efficiently, making the other tools seem useless, if not downright too risky.

Further, when tools are or depend on resources, it becomes difficult to balance their amount as well, especially considering varying player skills and aptitude for random exploration. An experienced Thief player will end a mission with over-abundance of arrows. A novice may be barely scraping by. Different difficulty levels help alleviate this somewhat, but the desing problem still exists for each setting.

My Work

Curious about my own indie game that spawned this feature? Check out my DevBlog, currently working on a Slavic-Steampunk game of sneaking and investigation onboard a damaged Zeppelin, uncovering the secrets of its passengers.