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

ขั้นตอนที่ 2 - การเอ็นแค็ปซูเลตสถิติ
โค้ดดังต่อไปนี้เป็นโค้ดที่ไม่ขึ้นอยู่กับเกมใดเกมหนึ่ง และสามารถเพิ่มเข้าในเกมของคุณได้ตามต้องการ คลาสดังกล่าวเป็นคลาสที่ทำงานได้ครบถ้วนอยู่แล้ว แต่ก็สามารถขยายให้ตรงกับความต้องการได้อย่างง่ายดาย โค้ดทั้งหมดนี้นำมาจากไฟล์ตัวอย่างของ Spacewar โดยตรงคือ
StatsAndAchievements.cpp/h
ไฟล์ส่วนหัว
เริ่มแรกเราได้นิยามโครงสร้างสำหรับบรรจุข้อมูลสถิติของเราที่ได้รับจาก Steam, นิยามประเภทของค่าสถิติใน Enum ที่ใช้งานสะดวก และเตรียมมาโครสำหรับสร้างออบเจ็กต์ประเภทนั้น ข้อมูลนี้จะแมปกับสิ่งที่พบในหน้า
การกำหนดค่าสถิติ โดยตรง
#define _STAT_ID( id,type,name ) { id, type, name, 0, 0, 0, 0 }
enum EStatTypes
{
STAT_INT = 0,
STAT_FLOAT = 1,
STAT_AVGRATE = 2,
};
struct Stat_t
{
int m_ID;
EStatTypes m_eStatType;
const char *m_pchStatName;
int m_iValue;
float m_flValue;
float m_flAvgNumerator;
float m_flAvgDenominator;
};
จากนั้นเราจะสร้างคลาสช่วยเหลือที่จะมาแรปการเรียก AP สถิติของ Steam ทั้งหมดพร้อมกับสร้าง
คอลแบ็ก Steam ทั้งหมด
class CSteamStats
{
private:
int64 m_iAppID; // Our current AppID
Stat_t *m_pStats; // Stats data
int m_iNumStats; // The number of Stats
bool m_bInitialized; // Have we called Request stats and received the callback?
public:
CSteamStats(Stat_t *Stats, int NumStats);
~CSteamStats();
bool RequestStats();
bool StoreStats();
STEAM_CALLBACK( CSteamStats, OnUserStatsReceived, UserStatsReceived_t,
m_CallbackUserStatsReceived );
STEAM_CALLBACK( CSteamStats, OnUserStatsStored, UserStatsStored_t,
m_CallbackUserStatsStored );
};
ไฟล์โค้ด
คอนสตรัคเตอร์
พารามิเตอร์ - คอนสตรัคเตอร์จะรับพอยน์เตอร์ที่ชี้ไปยังอาร์เรย์ของสถิติพร้อมกับความยาวของอาร์เรย์ จะมีการอธิบายเรื่องการจัดรูปแบบอาร์เรย์ในส่วนโค้ดเกมหลักต่อไปในภายหลัง
คืนค่า - N/A
สิ่งที่ทำ - คอนสตรัคเตอร์จะเริ่มต้นสมาชิกจำนวนหนึ่งไปพร้อมกับจับไอดีแอปของโปรแกรมที่เรากำลังใช้งาน นอกจากนั้นก็ยังจะฮุคกับเมธอดคอลแบ็กเพื่อจัดการการเรียกแบบอะซิงโครนัสที่ทำไปยัง Steam และสุดท้ายก็จะเรียกไปยัง
RequestStats()
ครั้งแรก เพื่อรับสถิติและรางวัลความสำเร็จของผู้ใช้ปัจจุบัน
CSteamStats::CSteamStats(Stat_t *Stats, int NumStats) :
m_iAppID( 0 ),
m_bInitialized( false ),
m_CallbackUserStatsReceived( this, &CSteamStats::OnUserStatsReceived ),
m_CallbackUserStatsStored( this, &CSteamStats::OnUserStatsStored )
{
m_iAppID = SteamUtils()->GetAppID();
m_pStats = Stats;
m_iNumStats = NumStats;
RequestStats();
}
RequestStats()
พารามิเตอร์ - ไม่มี
คืนค่า - bool ที่จะแสดงว่าการเรียกนั้นประสบความสำเร็จหรือไม่ หากการเรียกล้มเหลว ก็เป็นไปได้สูงว่ายังไม่ได้เริ่มใช้งาน Steam กรุณาตรวจสอบให้มั่นใจว่า ไคลเอนต์ Steam เปิดอยู่ในเวลาที่คุณพยายามจะเรียกและมีการเรียก
SteamAPI_Init ก่อนหน้านี้แล้ว
สิ่งที่ทำ - เมธอดนี้จะแรปการเรียกไปยัง
ISteamUserStats::RequestCurrentStats ซึ่งก็คือการเรียกแบบอะซิงโครนัสไปยัง Steam เพื่อร้องขอสถิติของผู้ใช้ปัจจุบัน จะต้องเรียกก่อนจึงจะสามารถตั้งค่าสถิติหรือรางวัลความสำเร็จได้ การเรียกเมธอดนี้ครั้งแรกจะเกิดขึ้นในคอนสตรัคเตอร์ คุณสามารถเรียกได้อีกครั้งในเวลาใดก็ได้หลังจากนั้น หากคุณต้องการที่จะตรวจสอบสถิติหรือรางวัลความสำเร็จที่ได้รับการอัปเดต
bool CSteamStats::RequestStats()
{
// Is Steam loaded? If not we can't get stats.
if ( NULL == SteamUserStats() || NULL == SteamUser() )
{
return false;
}
// Is the user logged on? If not we can't get stats.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Request user stats.
return SteamUserStats()->RequestCurrentStats();
}
StoreStats()
พารามิเตอร์ - ไม่มี
คืนค่า - bool ที่จะแสดงว่าการเรียกนั้นประสบความสำเร็จหรือไม่ หากการเรียกล้มเหลว ก็เป็นไปได้สูงว่ายังไม่ได้เริ่มใช้งาน Steam กรุณาตรวจสอบให้มั่นใจว่า ไคลเอนต์ Steam เปิดอยู่ในเวลาที่คุณพยายามจะเรียกและมีการเรียก
SteamAPI_Init ก่อนหน้านี้แล้ว
สิ่งที่ทำ - เมธอดนี้จะแรปการเรียกไปยัง
ISteamUserStats::RequestCurrentStats ซึ่งก็คือการเรียกแบบอะซิงโครนัสไปยัง Steam เพื่อร้องขอสถิติของผู้ใช้ปัจจุบัน จะต้องเรียกในทุกครั้งที่คุณต้องการอัปเดตค่าสถิติของผู้ใช้
bool CSteamStats::StoreStats()
{
if ( m_bInitialized )
{
// load stats
for ( int iStat = 0; iStat < m_NumStats; ++iStat )
{
Stat_t &stat = m_pStats[iStat];
switch (stat.m_eStatType)
{
case STAT_INT:
SteamUserStats()->SetStat( stat.m_pchStatName, stat.m_iValue );
break;
case STAT_FLOAT:
SteamUserStats()->SetStat( stat.m_pchStatName, stat.m_flValue );
break;
case STAT_AVGRATE:
SteamUserStats()->UpdateAvgRateStat(stat.m_pchStatName, stat.m_flAvgNumerator, stat.m_flAvgDenominator );
// The averaged result is calculated for us
SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue );
break;
default:
break;
}
}
return SteamUserStats()->StoreStats();
}
}
OnUserStatsReceived()
พารามิเตอร์ - N/A
คืนค่า - ไม่คืนค่าใด ๆ
สิ่งที่ทำ - เมธอดนี้คือคอลแบ็กที่จะถูกเรียกในทุกครั้งที่คุณพยายามจะร้องขอค่าสถิติ สามารถร้องขอค่าสถิติได้ด้วยการใช้
RequestStats()
เมธอดดังกล่าวจะอัปเดตตัวแปรสมาชิก m_Stats เพื่อสะท้อนถึงข้อมูลค่าสถิติล่าสุดที่ได้คืนค่ามาจาก Steam
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback )
{
// we may get callbacks for other games' stats arriving, ignore them
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "Received stats and achievements from Steam\n" );
// load stats
for ( int iStat = 0; iStat < m_iNumStats; ++iStat )
{
Stat_t &stat = m_Stats[iStat];
switch (stat.m_eStatType)
{
case STAT_INT:
SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_iValue);
break;
case STAT_FLOAT:
case STAT_AVGRATE:
SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue);
break;
default:
break;
}
}
m_bInitialized = true;
}
else
{
char buffer[128];
_snprintf( buffer, 128, "RequestStats - failed, %d\n", pCallback->m_eResult );
OutputDebugString( buffer );
}
}
}
OnUserStatsStored()
พารามิเตอร์ - N/A
คืนค่า - ไม่คืนค่าใด ๆ
สิ่งที่ทำ - เมธอดนี้คือคอลแบ็กที่จะถูกเรียกในทุกครั้งที่คุณพยายามจะจัดเก็บค่าสถิติบน Steam หากค่าสถิติใดค่าสถิติหนึ่งที่เราพยายามจะตั้งค่านั้นไม่เป็นไปตามข้อจำกัด ค่าสถิตินั้นก็จะถูกปรับกลับคืนให้เป็นค่าเก่า เพื่อให้เราสามารถโหลดค่าของสถิติตัวนั้นอีกครั้งได้
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback )
{
// we may get callbacks for other games' stats arriving, ignore them
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "StoreStats - success\n" );
}
else if ( k_EResultInvalidParam == pCallback->m_eResult )
{
// One or more stats we set broke a constraint. They've been reverted,
// and we should re-iterate the values now to keep in sync.
OutputDebugString( "StoreStats - some failed to validate\n" );
// Fake up a callback here so that we re-load the values.
UserStatsReceived_t callback;
callback.m_eResult = k_EResultOK;
callback.m_nGameID = m_iAppID;
OnUserStatsReceived( &callback );
}
else
{
char buffer[128];
_snprintf( buffer, 128, "StoreStats - failed, %d\n", pCallback->m_eResult );
OutputDebugString( buffer );
}
}
}
ขั้นตอนที่ 3 - การผสานเข้ากับเกมของคุณ
รายละเอียดดังต่อไปนี้คือรายการของ Code Snippet ที่คุณจะต้องผสานเข้าไปในเกมของคุณในตำแหน่งที่เหมาะสม
ค่านิยามและค่าโดยรวม
รายละเอียดดังต่อไปนี้เป็นรายการของ Includes ที่ต้องสร้างไว้กับรางวัลความสำเร็จ อาร์เรย์สำหรับสถิติเฉพาะสำหรับเกมของเรา และพอยน์เตอร์โดยรวมที่ชี้ไปยังออบเจ็กต์ช่วยเหลือของเรา โปรดทราบว่าข้อมูลสถิติจะตรงกับสถิติที่อยู่ในหน้าผู้ดูแลบน Steamworks
...
#include "steam_api.h"
#include "isteamuserstats.h"
#include "SteamStats.h"
// Stats array which will hold data about the stats and their state
Stat_t g_Stats[] =
{
_STAT_ID( 1, STAT_INT, "NumGames"),
_STAT_ID( 2, STAT_INT, "NumWins"),
_STAT_ID( 3, STAT_INT, "NumLosses"),
_STAT_ID( 4, STAT_FLOAT, "FeetTraveled"),
_STAT_ID( 5, STAT_AVGRATE, "AverageSpeed"),
_STAT_ID( 7, STAT_FLOAT, "MaxFeetTraveled"),
};
// Global access to Stats Object
CSteamStats* g_SteamStats = NULL;
...
การเริ่มเปิดใช้งาน
การเรียกไปยัง
SteamAPI_Init จะเริ่มเปิดใช้งาน Steam ทั้งหมด และจะต้องเรียกก่อนทุกอย่างเสมอ หากการเรียกประสบความสำเร็จ เราก็จะสามารถสร้างออบเจ็กต์ช่วยเหลือได้ด้วยการส่งเข้าไปในอาร์เรย์ของสถิติ พร้อมกับขนาดของอาร์เรย์
...
// Initialize Steam
bool bRet = SteamAPI_Init();
// Create the SteamStats object if Steam was successfully initialized
if (bRet)
{
g_SteamStats = new CSteamStats(g_Stats, 6);
}
...
การประมวลผลการคอลแบ็ก
เพื่อให้มั่นใจว่าทางเราได้ประมวลคอลแบ็กของ Steam ทั้งหมด เราจะต้องทำการปั๊มข้อความใหม่อยู่เป็นประจำ ซึ่งจะสามารถดำเนินการได้โดยเพิ่มการเรียกนี้เข้าไปยังลูปของเกม
...
SteamAPI_RunCallbacks();
...
การบันทึกสถิติ
สามารถบันทึกสถิติด้วยการเรียกเดียวไปยัง
StoreStats()
...
if (g_SteamStats)
g_SteamStats->StoreStats();
...
การปิดใช้งาน
การเรียกไปยัง
SteamAPI_Shutdown ควรจะเป็นบางสิ่งบางอย่างที่คุณได้ใส่เข้าไว้ในโค้ดของคุณแล้ว โดยการเรียกนี้จะปิดการใช้งาน Steam และจะต้องเรียกก่อนออกจากแอปพลิเคชัน และในขั้นตอนสุดท้าย เราก็จะลบออบเจ็กต์ช่วยเหลือที่ได้สร้างขึ้น
...
// Shutdown Steam
SteamAPI_Shutdown();
// Delete the SteamStats object
if (g_SteamStats)
delete g_SteamStats;
...
ขั้นตอนที่ 4 - การทดสอบและการแก้ไขปัญหา
โค้ดตัวอย่างนี้จะให้ผลลัพธ์ข้อมูลการดีบักไปยังคอนโซลดีบักที่จะสามารถช่วยให้คุณเข้าใจได้ว่าการเรียกใดสำเร็จหรือล้มเหลว ต่อไปนี้เป็นข้อความและการแก้ไขความล้มเหลวที่พบได้โดยทั่วไป:
ไม่สามารถเริ่มแอปพลิเคชันได้เพราะหา steam_api.dll ไม่พบ การติดตั้งแอปพลิเคชันซ้ำอีกครั้งอาจช่วยแก้ปัญหานี้ได้ตรวจสอบให้แน่ใจว่า steam_api.dll อยู่ในไดเรกทอรีเดียวกันกับตัวโปรแกรม
[S_API FAIL] SteamAPI_Init() ล้มเหลว หาอินสแตนซ์ของ Steam ที่ทำงานอยู่ หรือ steamclient.dll ภายในเครื่องไม่พบเป็นไปได้สูงว่าคุณไม่ได้มีไคลเอนต์ Steam ที่กำลังทำงานอยู่ ให้เริ่มต้น Steam แล้วเข้าสู่ระบบ
[S_API FAIL] SteamAPI_Init() ล้มเหลว หาไอดีแอปไม่พบเป็นไปได้สูงว่าคุณไม่ได้เตรียมไฟล์ steam_appid.txt ไว้ ให้วางไฟล์ดังกล่าวลงในโฟลเดอร์แหล่งที่มา แล้วตรวจสอบให้แน่ใจว่ามีหมายเลขไอดีแอป