概覽
Steam 統計和成就為您的遊戲提供了一種簡便的方式,持續並動態追蹤使用者的成就與統計資料。 使用者的資料將與 Steam 帳戶連結,而每項成就與統計資料皆可依固定的格式顯示於使用者的 Steam 社群個人檔案之中。
有些什麼益處
除了向您的遊戲玩家提供高價值的獎勵之外,成就也很適合用於鼓勵和獎勵團隊合作或玩家互動、加深遊戲目標的層次,並可獎勵玩家在遊戲上花更多時間。
統計資料則記錄了許多細膩的資訊,像是遊戲時間、使用過的強化道具數量等等。 您可只使用它們來記錄遊戲內部的資料,如此一來,您便可從多台機器收集多重工作階段的遊戲統計資料,並給予使用者成就。
實作概覽
定義遊戲的統計與成就
成就是專屬於各個應用程式的,必須使用 Steamworks 夥伴網站的應用程式管理員進行設定。
可儲存的統計型別有三種:
- INT - 32 位元(帶正負號的)整數(例如遊戲次數)
- FLOAT - 32 位元的浮點值(例如駕駛的里程數)
- AVGRATE - 移動平均。 詳見:AVGRATE 統計型別
Steamworks 合作夥伴網站的介面可供您定義和更新遊戲統計和成就, 您可以用它來:
- 定義初始的統計與成就
- 新增統計與成就
- 更新成就名稱、說明,和圖示
- 更新統計的參數與限制(最大 / 最小值、移動平均區間大小等等)
統計有下列屬性:
- ID - 每項統計自動產生的數值 ID
- 類型 - 這項統計的型別——INT、FLOAT,或 AVGRATE
- API 名稱 - 用來存取這項統計的 API 字串
- 設定方 - 設定誰能更改這項統計, 預設是用戶端。 更多資訊請見遊戲伺服器統計段落
- 僅限增長? - 勾選後,此統計數值便只能隨著時間增加
- 最大變更 - 設置每次呼叫 SetStat 時,此項統計的數值能改變多少
- 最小值 - 設置此項統計能接受的最小數值, 預設為數值型別的基本最小值(INT_MIN 或 -FLT_MAX)
- 最大值 - 設置此項統計能接受的最大數值, 預設為數值型別的基本最大值(INT_MAX 或 FLT_MAX)
- 預設值 - 設置後,將當作這項統計的新使用者預設值。 如果沒有設置,預設值則為零
- 合計 - 勾選後,Steam 將記錄此項統計的全球統計。 更多資訊,請見下方的全球統計段落
- 顯示名稱 - 顯示在您應用程式中的統計名稱
AVGRATE 統計有下列的額外屬性:
- 區間 - 用來計算平均值的「滑動區間(Sliding Window)」的大小
AVGRATE 的統計是由 Steam 自動平均得出的。 更多資訊,請見下方的
AVGRATE 段落。
成就有下列屬性:
- ID - 每項成就自動產生的數值 ID
- API 名稱 - 用來存取這項成就的 API 字串
- 進度數據 - 指定一項統計資料,做為這項成就展示於社群中的進度數值。 當統計數值抵達解鎖值時,成就將自動解鎖
- 顯示名稱 - 出現於用戶端彈跳式通知和社群的顯示名稱。 可以在地化
- 說明 - 一段顯示於社群中,關於這項成就的說明。 可以在地化
- 設定方 - 設定誰能解鎖這項成就。 預設是用戶端。 更多資訊請見遊戲伺服器統計段落
- 將其隱藏? - 如勾選,「隱藏」成就在達成前將不會顯示於使用者的社群頁面中
- 已達成圖示 - 達成成就後顯示的圖示
- 尚未達成圖示 - 尚未達成成就前顯示的圖示
以下是
Steamworks API Example Application (SpaceWar) 的成就列表:

特殊考量
- 成就名稱和圖示應適合所有年齡層
- 預設狀況下,遊戲一開始最多可以擁有 100 項成就。 當您的應用程式達到個人檔案功能臨界值時,便能新增更多成就。
使用方式
在遊戲中存取統計和成就:
AVGRATE 統計型別
此統計型別提供一些獨特且極為實用的功能,但需要詳加解釋。
假設您想追蹤一項計算平均的統計資料,例如「每小時獲得分數」。 其中一個方式是使用兩個統計,一個 INT "TotalPoints"(總分)和一個 FLOAT "TotalPlayTimeHours"(總遊玩時數),接著以分數除以時間,以計算出「每小時獲得分數」。
這種做法的缺點是,當玩家累積相當的遊玩時間後,計算出的平均值將變化得極為緩慢。 事實上,使用者玩得越多,平均值的變動就越小。 如果使用者花費了 100 小時遊玩遊戲,計算出的平均值將會「延遲」約 50 小時。 即使玩家的技巧進步了,「每小時獲得分數」也不會應期望而增加。
AVGRATE 統計型別可讓您對平均值實施「滑動區間(Sliding Window)」效果。 舉例來說,您可以只採用最近幾個小時的遊玩時間,讓統計更能正確反映玩家目前的技巧程度。
讓我們來設定一項 AVGRATE 統計,讓「每小時獲得分數」僅採用最近 20 小時的遊玩時間來計算數值。 設定方法如下:
- 請注意,因為平均值為「每小時」之值,因此所有與此統計相關的時間參數單位均為「小時」。 這適用於統計本身的區間屬性,以及傳送到下方
UpdateAvgRateStat
(更新平均評分統計)的 "dSessionLength" 參數
- 建立名為 "AvgPointsPerHour"(每小時平均分數)的 AVGRATE 統計並將區間屬性設為 20.0(請記住,單位為「小時」)
- 在遊戲中適當的時間點呼叫 ISteamUserStats::UpdateAvgRateStat,傳入下列參數:
- pchName - "AvgPointsPerHour"(每小時平均分數)
- flCountThisSession - 自上一次呼叫 UpdateAvgRateStat(更新平均評分統計)後,玩家所獲得的分數
- dSessionLength - 自上一次呼叫 UpdateAvgRateStat(更新平均評分統計)後的遊戲時間。 數值單位應與統計的區間屬性單位相同。 在此情況下,單位為「小時」
- 比方說,若玩家在上一回合中獲得了 77 分,而上一回合持續時間為 0.225 小時(13.5 分鐘),則
SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
在上方範例中,Steam 會將目前回合的平均值「342.2 分 / 小時」(77 除以 0.225)與之前的值一起計算, 得到的結果即為玩家最近 20 小時遊玩時間的總平均值。 如果這是當前使用者首次更新統計,則目前值為 342.2。
這個範例採用「小時」為單位,但您可以自行決定要使用的單位。 只要記得,您必須為 "dSessionLength" 和視窗屬性使用相同的基礎單位。
取得其他使用者的統計資料
您可以使用
ISteamUserStats::RequestUserStats 取得另一位使用者的統計。 接著可以使用
ISteamUserStats::GetUserStat、
ISteamUserStats::GetUserAchievement 和
ISteamUserStats::GetUserAchievementAndUnlockTime 取得該使用者的資料。 這項資料不會隨著該使用者上傳新統計而自動更新,因此若要更新資料,只要再呼叫一次
ISteamUserStats::RequestUserStats 即可。
為了避免佔用過多記憶體,系統會維持一個「近來最少使用(LRU)」快取,偶爾也會解除載入其他使用者的統計。 當此情形發生時,將自動傳送
ISteamUserStats::UserStatsUnloaded_t 回呼。 傳送回呼後,指定使用者的統計將無法使用,直到再次呼叫
ISteamUserStats::RequestUserStats 為止。
離線模式
Steam 會將統計與成就資料儲存於本機快取之中,好在離線模式時也能正常使用 API。 而任何無法上傳的統計也將被儲存起來,等到下次使用者上線再處理。 如果在多台電腦上都有過變更,Steam 會自動合併成就,並選擇進度較多的一組統計資料。 因為 Steam 會保留統計資料的本機快取,遊戲無須在磁碟上同時保留資料的本機快取。 這兩種快取通常會相互衝突,而發生衝突時,從使用者的角度來看就像進度消失了一樣,這會令人十分沮喪。
遊戲伺服器統計
作用類似於
ISteamUserStats 的是用於遊戲伺服器的
ISteamGameServerStats。 這些 API 取得使用者統計的方式跟用戶端一樣(如上方所述), 但僅有在「設定方」欄位為 GS(遊戲伺服器)或 Official GS(官方遊戲伺服器)的情況下,才能設定統計和獎勵成就。 遊戲伺服器和官方遊戲伺服器的差異在於,官方遊戲伺服器是由您託管和控制的伺服器。 使用官方遊戲伺服器來設定統計,能夠提升防作弊的安全性,因為使用者可能會修改他們自己的遊戲伺服器,或是冒充遊戲伺服器。 如要定義官方遊戲伺服器,於
此處輸入伺服器的 IP 範圍。
遊戲伺服器可設定的統計與成就無法以用戶端設定。 遊戲伺服器僅可為目前在伺服器上遊玩的使用者設定統計與成就。 玩家離開伺服器時,有一小段緩衝時間可以設定最終統計,但之後所有上傳都會被拒絕。 這是為了確保一致性,也讓惡意遊戲伺服器無法隨時設定任何人的統計。 在此限制下,最好不要等到回合結束時再設定統計。 要持續地設定統計,好在使用者退出時進行儲存。
當遊戲伺服器變更統計時,用戶端會自動獲得更新。 然而,與用戶端相同的是,伺服器為其他使用者載入的統計不會自動更新,也有可能過期。
重設統計
在開發的測試階段,常常需要完全清除一個或所有帳戶上的統計與成就。 若要清除帳戶上的統計,呼叫
ISteamUserStats::ResetAllStats,並將
bAchievementsToo
設為
true 以同時清除成就。 呼叫後,請記得再次逐一查看您的統計與成就,並重設記憶體內的遊戲統計。 但您無法全域性清除所有使用者的統計與成就。 其中一個原因是,即使能夠全域性清除資料,進行中的遊戲可能會忽略這次清除,而再次寫入記憶體內的值。 幸好,有個簡單的方式能在遊戲內建置全域性清除系統。 方法如下:
這樣一來,當您想進行全域性清除時,只需變更硬式編碼統計版本編號即可。 接著會在使用者獲得新組建時進行全域性清除。
統計一致性
最佳作法是考量相關統計之間可能會出現的不一致情形。 比方說,您可能擁有這三個統計:"GamesWon"(勝場次數)、"GamesLost"(敗場次數)和 "GamesPlayed"(總遊玩次數)。 即使盡力維護,統計之間也有可能會變得不同步。 在這種情況下,可能會導致勝場次數和敗場次數的總和與總遊玩次數有所差異。 如果要靠移除 "GamesLost" (敗場次數)統計並以計算 "GamesPlayed"(勝場次數)- "GamesWon"(總遊玩次數)代替敗場次數來解決問題,其中差異可能會導致 "GamesLost" (敗場次數)變成負數。 在此情況下,最佳作法是移除 "GamesWon"(總遊玩次數)統計,並以計算 "GamesPlayed"(勝場次數)- "GamesLost" (敗場次數)代替。
全球統計資料
可在管理員頁面上將統計標示為「合計」,以告知 Steam 為該項統計記錄所有使用者的全球總值。 這可用於取得經濟中的金錢總數、擊殺總數、最愛的武器、最愛的地圖以及哪一支隊伍通常表現較好等資料。 另一方面,此項無法用於 "MostKills"(最多擊殺數)之類的統計,因為將多個使用者在這類統計的值相加起來並沒有意義。 也因為統計由使用者決定,此項資料很有可能被濫用。 因此,在使用合計統計時,設定最低值、最高值、僅限增長(如適用)和最大變更等適當限制相當重要。 最大變更對合計統計來說有特別的意義。 在上傳新值時,全球值的變更將無法超過最大變更值。 這可限制作弊玩家影響全球統計的速度。
如欲存取全球統計,為每項全球統計呼叫
ISteamUserStats::RequestGlobalStats,接著再呼叫
ISteamUserStats::GetGlobalStat。 您也可以向
ISteamUserStats::RequestGlobalStats 要求特定天數的歷史記錄。 這筆歷史記錄是統計每日變更的數值。 您能以
ISteamUserStats::GetGlobalStatHistory 存取該筆歷史記錄。
您也可以從用戶端要求全球成就的完成比例。 若要取得資料,首先呼叫
ISteamUserStats::RequestGlobalAchievementPercentages。 接著,呼叫
ISteamUserStats::GetMostAchievedAchievementInfo 和
ISteamUserStats::GetNextMostAchievedAchievementInfo,依照完成度高低的順序逐一查看成就。 您也可以呼叫
ISteamUserStats::GetAchievementAchievedPercent 獲取特定成就的完成比例。
測試
在發行應用程式前,您無法在 Steam 社群或收藏庫中查看已獲得的成就。 您的應用程式需要一個方式來輸出使用者已獲得的成就。
您可透過 Steam 用戶端主控台來清除成就或清除統計,而無須另外在遊戲中添加程式碼。 執行 steam.exe -console,接著:
- achievement_clear <appid> <achievement name>
- reset_all_stats <appid>
Steam 社群
推出您的遊戲後,個人及全球成就進度的資訊將在 Steam 社群中顯示。 每個玩家可透過社群個人檔案中的連結,前往已達成和待解鎖成就的展示頁面。
備註:在您的應用程式有任何社群可見度以前,都不會顯示出成就。
每項成就會與相應的圖示及 Steamworks 控制台中設定的名稱與說明一併列出。 如果成就名稱和說明已在地化為使用者選用的語言,則會以該語言顯示。
此頁面和您的遊戲在 Steam 上的主頁面也會提供連結,連至遊戲的全球成就統計資料集, 這裡顯示遊戲的 Steam 玩家在每項成就上的達成比例,依照最常見到最稀有成就的順序排列。 不僅玩家看了覺得有趣,對開發者來說也是很好的資訊:您的特殊挑戰是否夠困難? 還是太難了? (這項資訊也可在「銷售與啟用報告」網站中查看。)
其它問題?
請至
統計與成就討論區提問。