เอกสาร Steamworks
คำแนะนำทีละขั้นตอน: กระดานผู้นำ

บทนำ

หัวข้อดังต่อไปนี้เป็นคู่มือคำแนะนำขั้นตอนการดำเนินงานสั้น ๆ เพื่อผสานระบบกระดานผู้นำ Steam ขั้นพื้นฐานเข้าไปสู่แอปพลิเคชันของคุณ โดยใช้เวลาไม่ถึง 10 นาที Steamworks SDK มาพร้อมกับแอปพลิเคชันตัวอย่างชั้นเยี่ยม ที่เรียกว่า Spacewar เพื่อนำเสนอคุณสมบัติของ Steam อย่างเต็มรูปแบบ ซึ่งคุณควรจะลองใช้งานเพื่อเรียนรู้การทำงานของคุณสมบัติต่าง ๆ ทั้งหมดของ Steam การฝึกสอนนี้จะกลั่นกรองข้อมูลที่อยู่ใน Spacewar และ API กระดานผู้นำที่อยู่ใน ISteamUserStats ลงมาให้เหลือเฉพาะข้อมูลที่จำเป็นจะต้องใช้ในกระดานผู้นำ Steam เพื่อให้ตัวอย่างนี้ตรงประเด็นที่สุดเท่าที่จะเป็นไปได้

ขั้นตอนที่ 1 - นิยามกระดานผู้นำของเกมของคุณ

Leaderboards are application specific and are setup on the Leaderboard Configuration page in the Steamworks Partner Site.

ในการกำหนดค่ากระดานผู้นำ ช่องข้อมูลดังต่อไปนี้จะต้องมีข้อมูลครบถ้วน:
  • Name - ให้ตั้งค่าเป็นชื่อที่อ่านออกเข้าใจได้ที่ถือเป็นส่วนหนึ่งของการพัฒนาภายใน
  • Community Name - หากจะแสดงกระดานผู้นำเอาไว้ในศูนย์กลางชุมชน ให้ตั้งชื่อที่จะแสดงต่อสาธารณะได้ที่นี่ หากไม่ใส่ชื่อเอาไว้ กระดานผู้นำจะไม่ปรากฏขึ้นมา
  • Sort Method - มีไว้เพื่อตั้งค่าการอันดับวิธีเรียงก่อนหลังของกระดานผู้นำ สำหรับกระดานผู้นำประเภทไล่ตำแหน่งอันดับ ให้ใช้การเรียงจากน้อยไปมาก สำหรับกระดานผู้นำประเภทคะแนนสูงสุด ให้ใช้การเรียงจากมากไปน้อย
  • Display Type - มีไว้เพื่อใช้กำหนดประเภทของข้อมูลที่จะแสดงบนกระดานผู้นำ ให้เลือกว่าเป็นตัวเลข วินาที หรือ มิลลิวินาที
  • Writes - หากตั้งค่านี้ให้เป็นเชื่อถือได้ ไคลเอนต์จะไม่สามารถตั้งค่าคะแนนของกระดานผู้นำได้ และจะต้องตั้งค่าผ่านทางการใช้ SetLeaderboardScore WebAPI เท่านั้น ค่าเริ่มต้นคือ false
  • Reads - หากตั้งค่านี้เป็นเพื่อน เกมจะสามารถอ่านได้แต่คะแนนกระดานผู้นำของเพื่อนของผู้ใช้ ส่วน WebAPI จะสามารถอ่านคะแนนทั้งหมดได้เสมอ ค่าเริ่มต้นคือ false

spacewar_leaderboards

ขั้นตอนที่ 2 - การเอ็นแค็ปซูเลตกระดานผู้นำ

The following code is game independent and can be added to your game as you see fit. The class is fully functional as is but can be easily extended to meet any further needs. All of this code was taken directly from the Spacewar example files Leaderboards.cpp/h.

ไฟล์ส่วนหัว

We define a helper class that will wrap all of the Steam Leaderboard API calls as well as creating all of the Steam call result handlers.
class CSteamLeaderboards { private: SteamLeaderboard_t m_CurrentLeaderboard; // Handle to leaderboard public: int m_nLeaderboardEntries; // How many entries do we have? LeaderboardEntry_t m_leaderboardEntries[10]; // The entries CSteamLeaderboards(); ~CSteamLeaderboards(){}; void FindLeaderboard( const char *pchLeaderboardName ); bool UploadScore( int score ); bool DownloadScores(); void OnFindLeaderboard( LeaderboardFindResult_t *pResult, bool bIOFailure); CCallResult m_callResultFindLeaderboard; void OnUploadScore( LeaderboardScoreUploaded_t *pResult, bool bIOFailure); CCallResult m_callResultUploadScore; void OnDownloadScore( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure); CCallResult m_callResultDownloadScore; };

ไฟล์โค้ด

คอนสตรัคเตอร์

พารามิเตอร์ - None
คืนค่า - N/A
สิ่งที่ทำ - This constructor just initializes the member variables.
CSteamLeaderboards::CSteamLeaderboards() : m_CurrentLeaderboard( NULL ), m_nLeaderboardEntries( 0 ) { }

FindLeaderboard()

พารามิเตอร์ - The string identifier of the leaderboard that you want to find (ie. "Feet Traveled")
คืนค่า - Nothing
สิ่งที่ทำ - This method wraps a call to ISteamUserStats::FindLeaderboard which is an asynchronous call to steam requesting a handle to the given leaderboard. This call needs to be made before you can retrieve or set leaderboard entries. This method also sets up the call return method to use.
void CSteamLeaderboards::FindLeaderboard( const char *pchLeaderboardName ) { m_CurrentLeaderboard = NULL; SteamAPICall_t hSteamAPICall = SteamUserStats()->FindLeaderboard(pchLeaderboardName); m_callResultFindLeaderboard.Set(hSteamAPICall, this, &CSteamLeaderboards::OnFindLeaderboard); }

OnFindLeaderboard()

พารามิเตอร์ - N/A
คืนค่า - Nothing
สิ่งที่ทำ - This method is a callback that is called anytime we attempt to find a leaderboard on Steam. If the requested leaderboard was found then we set that leaderboard handle as our current leaderboard.
void CSteamLeaderboards::OnFindLeaderboard( LeaderboardFindResult_t *pCallback, bool bIOFailure ) { // see if we encountered an error during the call if ( !pCallback->m_bLeaderboardFound || bIOFailure ) { OutputDebugString( "Leaderboard could not be found\n" ); return; } m_CurrentLeaderboard = pCallback->m_hSteamLeaderboard; }

UploadScore()

พารามิเตอร์ - an int32 representing the value to store in the current leaderboard.
คืนค่า - false if a leaderboard has not been selected yet, otherwise it returns true.
สิ่งที่ทำ - This method wraps a call to ISteamUserStats::UploadLeaderboardScore which is an asynchronous call to steam that uploads the score of the current user to the currently selected leaderboard. This method also sets up the call return method to use. This call needs to be made after you have selected a leaderboard using FindLeaderboard().
bool CSteamLeaderboards::UploadScore( int score ) { if (!m_CurrentLeaderboard) return false; SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore( m_CurrentLeaderboard, k_ELeaderboardUploadScoreMethodKeepBest, score, NULL, 0 ); m_callResultUploadScore.Set(hSteamAPICall, this, &CSteamLeaderboards::OnUploadScore); return true; }

OnUploadScore()

พารามิเตอร์ - N/A
คืนค่า - Nothing
สิ่งที่ทำ - This method is a callback that is called anytime we attempt to upload a score to a leaderboard on Steam.
void CSteamLeaderboards::OnUploadScore(LeaderboardScoreUploaded_t *pCallback, bool bIOFailure) { if ( !pCallback->m_bSuccess || bIOFailure ) { OutputDebugString( "Score could not be uploaded to Steam\n" ); } }

DownloadScores()

พารามิเตอร์ - N/A
คืนค่า - false if a leaderboard has not been selected yet, otherwise it returns true.
สิ่งที่ทำ - This method wraps a call to ISteamUserStats::DownloadLeaderboardEntries that is an asynchronous call to steam downloading a set of entries from the currently selected leaderboard. In this case we are downloading ten entries; four before the current user, the current user and five after the current user. This call can be altered to return any number of entries from any place in the leaderboard. This method also sets up the call return method to use. This call needs to be made after you have selected a leaderboard using FindLeaderboard().
bool CSteamLeaderboards::DownloadScores() { if (!m_CurrentLeaderboard) return false; // load the specified leaderboard data around the current user SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries( m_CurrentLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -4, 5); m_callResultDownloadScore.Set(hSteamAPICall, this, &CSteamLeaderboards::OnDownloadScore); return true; }

OnDownloadScore()

พารามิเตอร์ - N/A
คืนค่า - Nothing
สิ่งที่ทำ - This method is a callback that is called anytime we attempt to download entries from a leaderboard on Steam. If the data was successfully downloaded then we copy the data into our array of entries. The number of entries downloaded is stored in m_nLeaderboardEntries.
void CSteamLeaderboards::OnDownloadScore(LeaderboardScoresDownloaded_t *pCallback, bool bIOFailure) { if (!bIOFailure) { m_nLeaderboardEntries = min(pCallback->m_cEntryCount, 10); for (int index = 0; index < m_nLeaderboardEntries; index++) { SteamUserStats()->GetDownloadedLeaderboardEntry( pCallback->m_hSteamLeaderboardEntries,index,&m_leaderboardEntries[index],NULL,0); } } }

ขั้นตอนที่ 3 - การผสานเข้ากับเกมของคุณ

The following is a complete listing of code snippets that you would need to integrate into your game in the appropriate locations.

ค่านิยามและค่าโดยรวม

The following is the list of includes that are needed to build with Leaderboards and a global pointer to our helper object.
... #include "steam_api.h" #include "SteamLeaderboards.h" // Global access to Leaderboards Object CSteamLeaderboards* g_SteamLeaderboards = NULL; ...

การเริ่มต้น

The call to SteamAPI_Init initializes all of Steam and must be called before anything else. If that call succeeds then we create the helper object.
... // Initialize Steam bool bRet = SteamAPI_Init(); // Create the SteamLeaderboards object if Steam was successfully initialized if (bRet) { g_SteamLeaderboards = new CSteamLeaderboards(); } ...

การประมวลผลการคอลแบ็ก

To ensure that we process all Steam callbacks we need to regularly pump for new messages. This is achieved by adding this call to the game loop.
... SteamAPI_RunCallbacks(); ...

Shutdown

The call to SteamAPI_Shutdown is probably something you already have in your code. It shuts down steam and must be called before you application exits. Finally we delete the helper object we created.
... // Shutdown Steam SteamAPI_Shutdown(); // Delete the SteamLeaderboards object if (g_SteamLeaderboards) delete g_SteamLeaderboards; ...

ขั้นตอนที่ 4 - การทดสอบและการแก้ไขปัญหา

This sample code outputs debug information to the debug console that can help you understand what calls are succeeding or failing. The following are some typical failure messages and fixes:

ไม่สามารถเริ่มแอปพลิเคชันได้เพราะหา steam_api.dll ไม่พบ การติดตั้งตัวแอปพลิเคชันซ้ำอีกครั้งอาจช่วยแก้ปัญหานี้ได้
Make sure steam_api.dll is in the same directory as the executable.

[S_API FAIL] SteamAPI_Init() ล้มเหลว หาอินสแตนซ์ของ Steam ที่ทำงานอยู่ หรือ steamclient.dll ภายในเครื่องไม่พบ
You most likely don't have a Steam client running. Start Steam and log in.

[S_API FAIL] SteamAPI_Init() ล้มเหลว หาไอดีแอปไม่พบ
You most likely don't have the steam_appid.txt file in place. Place it in your source folder and ensure that it has your appID number in it.