無所屬單位

首頁 文獻與幫助
Steamworks 文獻庫
統計與成就

英文原文已更新

本頁原文在翻譯完成後已再次更新。\r
點擊這裡檢視最新的英文版本。

總覽

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 將記錄此項統計的全球統計。更多資訊,請見下方的全球統計段落
  • 顯示名字 - 顯示於 Steam 社群的統計名稱。可以在地化
AVGRATE 有以下額外的屬性:
  • 視窗 - 用來計算平均值的「滑動視窗」的大小
AVGRATE 的統計是由 Steam 自動平均得出的。更多資訊,請見下方的 AVGRATE 段落。

成就有下列屬性:
  • ID - 每項統計自動產生的數值 ID
  • API 名稱 - 用來存取這項成就的 API 字串
  • 進度數據 - 指定一項統計資料,做為這項成就展示於社群中的進度數值。當統計數值抵達解鎖值時,成就將自動解鎖
  • 顯示名字 - 出現於用戶端彈跳式通知和社群的顯示名稱。可以在地化
  • 說明 - 一段顯示於社群中,關於這項成就的說明。可以在地化
  • 設定由 - 設定誰能解鎖這項成就。預設是用戶端。更多資訊請見遊戲伺服器統計資料一文。
  • 將其隱藏 - 如勾選,在達成此成就前完全不會顯示於使用者的社群頁面中
  • 已達成圖示 - 達成成就後顯示的圖示
  • 尚未達成圖示 - 尚未達成成就前顯示的圖示

以下是 Steamworks API 範例應用程式(SpaceWar)的成就列表:
achievements_spacewar.png

使用方式

在遊戲中存取統計和成就:

AVGRATE 統計型別

此型別提供了獨特且非常有用的功能,但需要一些詳細說明。

假如說您想追蹤紀錄某項平均數據,像是「每小時平均得分」。一種辦法是設置兩項統計資料,一個 INT 的「總分數」,和 FLOAT 的「總遊玩時數」,然後將分數除以遊玩時數,得到每小時平均得分。

這個方法這的缺點是,一但玩家的遊戲時數達到某個程度,計算出的平均值將變動得非常緩慢。實際上,玩家玩得越多,平均的改變就越少。如果玩家花了 100 個小時在遊戲上,得出的平均將會「延遲」大概 50 個小時。就算技術程度提高,也不會如期看到每小時平均得分一起上升。

AVGRATE 統計型別則能讓您設置一個可影響平均值的「滑動視窗」。舉例來說,您可以只計算先前幾個小時的遊戲時間,讓統計數值更精確地反應玩家目前的技術程度。

現在來設置一個 AVGRATE 統計來實作「每小時平均得分」,並只有過去 20 個小時能影響數值。方法是:
  • 由於這項平均是以小時計算,以下有關時間的單位都是「小時」,例如統計本身的視窗屬性,和傳給 UpdateAvgRateStat 的「dSessionLength」參數
  • 建立一個名為「AvgPointsPerHour」的 AVGRATE 統計,並將視窗設置為 20.0(以小時為單位)
  • 在遊戲中適當的時候,呼叫 ISteamUserStats::UpdateAvgRateStat 並傳入下列參數:
    • pchName - 「AvgPointsPerHour」
    • flCountThisSession - 自從上次呼叫 UpdateAvgRateStat 後,玩家所獲得的分數
    • dSessionLength - 自從上次呼叫 UpdateAvgRateStat 後,玩家的遊玩時數必須使用與視窗屬性相同的單位,以這個例子來說便是以小時為單位。
  • 例如說,玩家在過去 0.225 小時(13.5 分鐘)獲得了 77 分,就會變成 SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
以上面的例子來說,Steam 會將這回合的每小時 342.2 分(77 除以 0.225)與先前的數值一起計算,結果便是玩家過去 20 個小時遊戲時間的平均得分。如果這是第一次替此玩家更新數據,那麼目前的值就是 342.2。

這個範例用了「小時」作為單位,但您也可使用任何其他的時間單位。只要在「dSessionLength」和視窗屬性使用同樣的單位就行了。

取得其他玩家的統計資料

您可使用 ISteamUserStats::RequestUserStats 取得其他玩家的統計資料,然後呼叫 ISteamUserStats::GetUserStatISteamUserStats::GetUserAchievement,和 ISteamUserStats::GetUserAchievementAndUnlockTime 取得使用者的其他資料。由於其他玩家會不斷上傳新的統計數據,您取得的資料並不會自動更新。再呼叫一次 ISteamUserStats::RequestUserStats 即可更新資料。

為避免使用過多的記憶體,系統會維持一個近來最少使用(LRU)快取,而有時會載入不到其他使用者的統計。這種狀況發生時將自動傳送一個 ISteamUserStats::UserStatsUnloaded_t 回呼。發出回呼後,再次呼叫 ISteamUserStats::RequestUserStats 之前,都無法使用該使用者的統計資料。

離線模式

Steam 會將統計與成就資料保存於本機快取之中,所以在離線模式中也能正常使用 API。這段時間無法上傳的統計皆會被保存至下次連線至網路。如在多台機器上都有過變更,Steam 會自動合併成就,並選擇進度最多的統計。由於 Steam 已經在本機快取上保存了統計資料,遊戲便沒有必要再將資料快取儲存於磁碟上。這兩種快取常常互相衝突,從使用者的角度看來即是失去了進度,是個令人挫折的經驗。

遊戲伺服器統計資料

ISteamUserStats 性值相近的便是遊戲伺服器的 ISteamGameServerStats 了,能用與用戶端相同的方式取得使用者的統計資料。也可以用它來設置統計和成就,但只有在「設定由」是 GS(遊戲伺服器)或 Official GS (官方遊戲伺服器)的情況下。遊戲伺服器和官方遊戲伺服器的差別在於,官方伺服器是您自己架設和控制的。使用官方伺服器設定統計資料較能杜絕作弊行為,因為如此一來玩家便無法變更自己的遊戲伺服器,或假扮遊戲伺服器。如要設置官方伺服器,可從這裡輸入伺服器的 IP 範圍。

遊戲伺服器可設定的統計與成就不能由用戶端更改。遊戲伺服器只能為正在伺服器上遊玩的玩家設定統計與成就。當使用者離開了伺服器,會有一小段寬限期可設置最終的統計,之後所有上傳都會被拒絕。這是為了保持資料的一致性,和避免惡意的伺服器隨時隨意更改任何人的統計。鑒於這項限制,盡量不要等到回合結束時才設置統計。要持續地設定統計,當使用者退出遊戲時便能順利儲存。

遊戲伺服器變更統計時,用戶端便會自動獲得更新。但是,像用戶端一樣,載入其他使用者的資料後不會自動更新,有可能不正確。

重設統計資料

開發過程中,常常會有為了測試希望清除某個帳戶所有統計與成就的狀況。要清除帳戶所有統計,呼叫 ISteamUserStats::ResetAllStats,而將 bAchievementsToo 設置為 true 即可一同清除成就。呼叫後,記得要重新逐一查看統計與成就,並重設記憶體內部的遊戲狀態。並沒有方法統一清除所有使用者的統計與成就。這是因為就算統一清除了資料,運作中的遊戲可能也不會注意到這次的清除,而寫入記憶體中的值。幸好是有一個簡單的辦法可以在您的遊戲中建立一個統一清除系統。方法是:
  • 設置一項成就,名稱可以用「Versoin」
  • 在遊戲中硬式編入一個統計版本編號
  • 載入統計後,對比「Version」和硬式編入的版本編號
  • 如不相符,呼叫 ISteamUserStats::ResetAllStats 然後將「Version」設為硬式編入的編號
這樣一來,需要統一清除的時候,只要改變硬式編入的統計版本編號就可以了。其他人拿到新組建時,便會清除資料。只要確定統一清除的程式碼別與最終組建一起釋出就好了。

統計一致性

最好的做法便是思考哪些有關聯的統計會不一致。假如您有三項統計「GamesWon」、「GamesLost」,和「GamesPlayed」。儘管乍看之下沒有問題,但統計彼此之間確實有無法同步的時候。以上面的例子來說,勝場和敗場數加起來有可能不到總遊戲場數。假如您將「GamesLost」去掉,而使用「GamesPlayed」-「GamesWon」來計算敗場的話,資料不一致時便會導致「GamesLost」變成負數。這種狀況下,最好的辦法是不要使用「GamesPlays」而使用「GamesWon」+「GamesLost」。

全球統計資料

可在管理員頁面中勾選統計的合計,Steam 便會記錄所有使用者的總值。這可以用來記錄經濟系統中所有的金錢、總擊殺數、最受歡迎的武器或地圖,或哪個隊伍的表現較佳。另一方面,這就不能用在像是「MostKills」的統計,因為將多個使用者的最高擊殺數加起來沒有任何意義。由於統計是掌握在玩家手上,這些數據便有遭到操縱的可能。因此,使用合計時,設置最小值、最大值、限增長部分(如有需要),與最大變更便是個關鍵。最大改變對合計統計來說用途比較特別。每當上傳了新的值,合計的改變不會超過最大改變的值。這限制了作弊的人可以在多短時間內影響全球總計。

要存取全球統計,先呼叫 ISteamUserStats::RequestGlobalStats 然後再呼叫 ISteamUserStats::GetGlobalStat 取得每項統計。也可向 ISteamUserStats::RequestGlobalStats 要求過去多少天的歷史,這些歷史記錄了這項統計每天改變的量。使用 ISteamUserStats::GetGlobalStatHistory 便可存取歷史紀錄。

您也可從用戶端要求全球成就完成百分比。首先呼叫 ISteamUserStats::RequestGlobalAchievementPercentages。然後呼叫 ISteamUserStats::GetMostAchievedAchievementInfoISteamUserStats::GetNextMostAchievedAchievementInfo 以最多完成到最少完成的順序逐一查看每項成就。您也可呼叫 ISteamUserStats::GetAchievementAchievedPercent 取得某項成就的完成百分比。

Steam 社群

遊戲發行之後,有關個人與全球的成就進度便會顯示於 Steam 社群中。每位玩家都會有一個連結,通往社群個人檔案中展示已達成和未達成成就的頁面。
備註:在您的應用程式有任何社群可見度以前,都不會顯示出成就。

每項成就都會與在 Steamworks 控制台中設置的圖示、名稱,和說明一起列出。如果成就有被在地化成使用者所選的語言,便會以該語言顯示。

這個頁面和遊戲的 Steam 主頁面皆會有一個連結連至全球成就統計資料的頁面,顯示每一項成就的 Steam 玩家全球達成率,依最常見到最少見的順序排列。這對玩家來說很有趣,對開發者來說也是項很有用的資源;特別挑戰夠不夠難?或是難度太高了?(這些資訊也可在 Steamworks 夥伴網站上找到)。

其他問題?

前往統計與成就討論區發表問題。