โดยสรุป
ใช้รางวัลความสำเร็จเพื่อเป็นรางวัลแก่ผู้เล่นที่บรรลุหลักชัยบางระดับหรือตอบโต้กับเกมของคุณในบางลักษณะระดับการผสานระบบ
10 นาทีและโค้ดไม่เกิน 10 บรรทัด จำเป็นต้องมีการผสานระบบ Steamworks SDKบทนำ
รางวัลความสำเร็จอาจนำมาใช้เป็นวิธีที่ให้กำลังใจและเป็นรางวัลที่ผู้เล่นตอบโต้และบรรลุหลักชัยภายในเกมของคุณ ส่วนมากมักใช้เพื่อฉลองจำนวนการสังหาร ระยะทางที่ขับขี่ หีบสมบัติที่เปิดได้ หรือการกระทำทั่วไปภายในเกมของคุณ นอกจากนั้นยังสามารถนำมาใช้เพื่อช่วยให้ผู้เล่นของคุณค้นพบวิธีการเล่นเกมของคุณในรูปแบบต่าง ๆ อีกด้วย เมื่อปลดล็อคแล้ว รางวัลความสำเร็จเหล่านี้จะปรากฏขึ้นตรงมุมของหน้าต่างผู้เล่น และจะมีเครื่องหมายกำกับภายในหน้ารางวัลความสำเร็จสำหรับผู้เล่นนั้น
ภาพรวมเชิงเทคนิค
ต่อไปนี้เป็นคู่มือคำแนะนำขั้นตอนการดำเนินงานสั้น ๆ เพื่อผสานระบบรางวัลความสำเร็จ Steam ขั้นพื้นฐานเข้าไปสู่แอปพลิเคชันของคุณ โดยใช้เวลาไม่ถึง 10 นาทีและเพิ่มโค้ดไม่ถึง 10 บรรทัดไปยังโค้ดเดิมของคุณ
Steamworks SDK จะมาพร้อมกับแอปพลิเคชันตัวอย่างชั้นเลิศที่เรียกว่า
Spacewar ที่นำเสนอคุณสมบัติของ Steam อย่างเต็มรูปแบบ และคุณควรจะลองใช้งานเพื่อเรียนรู้การทำงานของคุณสมบัติต่าง ๆ ทั้งหมดของ Steam การฝึกสอนนี้จะกลั่นกรองข้อมูลที่อยู่ใน Spacewar และ API สถิติและรางวัลความสำเร็จให้เหลือเฉพาะข้อมูลที่จำเป็นต้องใช้ในสถิติ Steam เพื่อให้ตัวอย่างนี้ตรงประเด็นที่สุดเท่าที่จะเป็นไปได้ โปรดทราบว่าระบบสถิติและรางวัลความสำเร็จนั้น มีฟังก์ชันซ้ำกันมากพอสมควร ดังนั้น ถ้าคุณจะผสานทั้งสองอย่างเข้าระบบ โปรดทราบว่าสามารถรวมการเรียกฟังก์ชันหลายอย่างเข้าด้วยกันได้
ขั้นตอนที่ 1 - นิยามรางวัลความสำเร็จให้แก่เกมของคุณ
รางวัลความสำเร็จจะใช้งานได้เฉพาะกับแอปพลิเคชันของตัวเอง และสามารถตั้งค่าได้ที่หน้า
การกำหนดค่ารางวัลความสำเร็จ ในส่วนแบ็กเอนด์ของผู้ดูแลแอป Steamworks รายการต่อไปนี้คือรางวัลความสำเร็จจาก Spacewar ซึ่งเป็นแอปตัวอย่างของ Steamworks:
ขั้นตอนที่ 2 - การเอ็นแค็ปซูเลตรางวัลความสำเร็จ
โค้ดดังต่อไปนี้จะไม่ขึ้นอยู่กับเกม และสามารถเพิ่มเข้าไปในเกมของคุณได้ตามต้องการ คลาสดังกล่าวเป็นคลาสที่ทำงานได้ครบถ้วนอยู่แล้ว แต่ก็สามารถขยายให้ตรงกับความต้องการได้อย่างง่ายดาย โค้ดทั้งหมดนี้นำมาจากไฟล์ตัวอย่างของ Spacewar โดยตรงคือ
StatsAndAchievements.cpp/h
ไฟล์ส่วนหัว
ก่อนอื่นเราได้กำหนดโครงสร้างเพื่อบรรจุข้อมูลรางวัลความสำเร็จที่ได้รับจาก Steam และเตรียมมาโครไว้สำหรับสร้างออบเจ็กต์ประเภทนั้น ข้อมูลนี้จะแมปกับสิ่งที่พบในหน้า
การกำหนดรางวัลความสำเร็จ โดยตรง
#define _ACH_ID( id, name ) { id, #id, name, "", 0, 0 }
struct Achievement_t
{
int m_eAchievementID;
const char *m_pchAchievementID;
char m_rgchName[128];
char m_rgchDescription[256];
bool m_bAchieved;
int m_iIconImage;
};
จากนั้นเราจึงกำหนดคลาสช่วยเหลือที่จะมาแรปการเรียก AP สถิติทั้งหมดของ Steam และสร้าง
คอลแบ็ก Steam ทั้งหมด
class CSteamAchievements
{
private:
int64 m_iAppID; // Our current AppID
Achievement_t *m_pAchievements; // Achievements data
int m_iNumAchievements; // The number of Achievements
bool m_bInitialized; // Have we called Request stats and received the callback?
public:
CSteamAchievements(Achievement_t *Achievements, int NumAchievements);
~CSteamAchievements();
bool RequestStats();
bool SetAchievement(const char* ID);
STEAM_CALLBACK( CSteamAchievements, OnUserStatsReceived, UserStatsReceived_t,
m_CallbackUserStatsReceived );
STEAM_CALLBACK( CSteamAchievements, OnUserStatsStored, UserStatsStored_t,
m_CallbackUserStatsStored );
STEAM_CALLBACK( CSteamAchievements, OnAchievementStored,
UserAchievementStored_t, m_CallbackAchievementStored );
};
ไฟล์โค้ด
คอนสตรัคเตอร์
พารามิเตอร์ - คอนสตรัคเตอร์จะรับพอยน์เตอร์ที่ชี้ไปยังอาร์เรย์ของรางวัลความสำเร็จพร้อมกับความยาวของอาร์เรย์ ส่วนเรื่องการจัดรูปแบบอาร์เรย์นั้น เราจะอธิบายในส่วนโค้ดเกมหลักภายหลัง
คืนค่า - ไม่เกี่ยวข้อง
สิ่งที่ทำ - คอนสตรัคเตอร์จะเริ่มต้นสมาชิกจำนวนหนึ่งพร้อมกับจับไอดีแอปที่เราใช้งานในขณะนั้น นอกจากนั้นก็ยังจะฮุคกับเมธอดคอลแบ็กเพื่อจัดการกับการเรียกแบบอะซิงโครนัสที่เกิดขึ้นกับ Steam ในที่สุด ก็จะเรียกไปยัง
RequestStats()
เป็นครั้งแรก เพื่อรับสถิติและรางวัลความสำเร็จของผู้ใช้ปัจจุบัน
CSteamAchievements::CSteamAchievements(Achievement_t *Achievements, int NumAchievements):
m_iAppID( 0 ),
m_bInitialized( false ),
m_CallbackUserStatsReceived( this, &CSteamAchievements::OnUserStatsReceived ),
m_CallbackUserStatsStored( this, &CSteamAchievements::OnUserStatsStored ),
m_CallbackAchievementStored( this, &CSteamAchievements::OnAchievementStored )
{
m_iAppID = SteamUtils()->GetAppID();
m_pAchievements = Achievements;
m_iNumAchievements = NumAchievements;
RequestStats();
}
RequestStats()
พารามิเตอร์ - ไม่มี
คืนค่า - bool ที่จะแสดงว่าการเรียกนั้นประสบความสำเร็จหรือไม่ หากการเรียกล้มเหลว ก็เป็นไปได้สูงว่ายังไม่ได้เริ่มใช้งาน Steam กรุณาตรวจสอบให้มั่นใจว่าไคลเอนต์ Steam เปิดอยู่ในเวลาที่คุณพยายามจะเรียก และมีการเรียก
SteamAPI_Init ไว้ก่อนแล้ว
สิ่งที่ทำ - เมธอดนี้จะแรปการเรียกไปยัง
ISteamUserStats::RequestCurrentStats ซึ่งเป็นการเรียกแบบอะซิงโครนัสไปยัง Steam เพื่อขอสถิติและรางวัลความสำเร็จของผู้ใช้ปัจจุบัน โดยต้องเรียกก่อน คุณจึงสามารถตั้งค่าสถิติหรือรางวัลความสำเร็จได้ การเรียกเมธอดนี้ครั้งแรกจะเกิดขึ้นในคอนสตรัคเตอร์ หลังจากนั้น คุณจะสามารถเรียกได้อีกในเวลาใดก็ได้ หากคุณต้องการตรวจสอบสถิติหรือรางวัลความสำเร็จที่ได้รับการอัปเดต
bool CSteamAchievements::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();
}
SetAchievement()
พารามิเตอร์ - ตัวระบุสตริงของรางวัลความสำเร็จที่คุณต้องการจะตั้งค่า (กล่าวคือ "ACH_WIN_ONE_GAME")
คืนค่า - bool ที่จะแสดงว่าการเรียกนั้นประสบความสำเร็จหรือไม่ หากการเรียกนั้นล้มเหลว ก็แสดงว่ายังไม่ได้เปิดใช้งาน Steam หรือคุณยังไม่ได้ประมวลผลคอลแบ็กจากการเรียกครั้งแรกไปยัง
RequestStats
คุณจะไม่สามารถตั้งค่ารางวัลความสำเร็จได้จนกว่าจะได้รับคอลแบ็กนั้นแล้ว
สิ่งที่ทำ - เมธอดนี้จะตั้งค่ารางวัลความสำเร็จที่ระบุไว้ให้มีสถานะ "สำเร็จแล้ว" และจะส่งผลลัพธ์ไปยัง Steam คุณสามารถตั้งค่ารางวัลความสำเร็จได้หลายครั้ง ดังนั้นไม่ต้องกังวลเกี่ยวกับการตั้งค่าเฉพาะรางวัลความสำเร็จที่ยังไม่ได้ตั้งค่า นี่เป็นการเรียกแบบอะซิงโครนัส ซึ่งจะทำให้เกิดคอลแบ็ก 2 ครั้ง ได้แก่:
OnUserStatsStored()
และ
OnAchievementStored()
bool CSteamAchievements::SetAchievement(const char* ID)
{
// Have we received a call back from Steam yet?
if (m_bInitialized)
{
SteamUserStats()->SetAchievement(ID);
return SteamUserStats()->StoreStats();
}
// If not then we can't set achievements yet
return false;
}
OnUserStatsReceived()
พารามิเตอร์ - ไม่เกี่ยวข้อง
คืนค่า - ไม่คืนค่าใด ๆ
สิ่งที่ทำ - เมธอดนี้คือคอลแบ็กที่จะถูกเรียกในทุกครั้งที่คุณพยายามขอค่าสถิติ คุณสามารถขอค่าสถิติได้โดยใช้
RequestStats()
เมธอดดังกล่าวจะอัปเดตตัวแปรสมาชิก m_pAchievements เพื่อสะท้อนถึงข้อมูลค่าสถิติและรางวัลความสำเร็จล่าสุดที่ได้รับคืนมาจาก Steam
void CSteamAchievements::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");
m_bInitialized = true;
// load achievements
for ( int iAch = 0; iAch < m_iNumAchievements; ++iAch )
{
Achievement_t &ach = m_pAchievements[iAch];
SteamUserStats()->GetAchievement(ach.m_pchAchievementID, &ach.m_bAchieved);
_snprintf( ach.m_rgchName, sizeof(ach.m_rgchName), "%s",
SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID,
"name"));
_snprintf( ach.m_rgchDescription, sizeof(ach.m_rgchDescription), "%s",
SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID,
"desc"));
}
}
else
{
char buffer[128];
_snprintf( buffer, 128, "RequestStats - failed, %d\n", pCallback->m_eResult );
OutputDebugString( buffer );
}
}
}
OnUserStatsStored()
พารามิเตอร์ - ไม่เกี่ยวข้อง
คืนค่า - ไม่คืนค่าใด ๆ
สิ่งที่ทำ - เมธอดนี้คือคอลแบ็กที่จะถูกเรียกในทุกครั้งที่คุณพยายามจะจัดเก็บค่าสถิติบน Steam
void CSteamAchievements::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( "Stored stats for Steam\n" );
}
else
{
char buffer[128];
_snprintf( buffer, 128, "StatsStored - failed, %d\n", pCallback->m_eResult );
OutputDebugString( buffer );
}
}
}
OnAchievementStored()
พารามิเตอร์ - ไม่เกี่ยวข้อง
คืนค่า - ไม่คืนค่าใด ๆ
สิ่งที่ทำ - เมธอดนี้คือคอลแบ็กที่จะถูกเรียกทุกครั้งที่จัดเก็บรางวัลความสำเร็จบน Steam ได้สำเร็จ
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback )
{
// we may get callbacks for other games' stats arriving, ignore them
if ( m_iAppID == pCallback->m_nGameID )
{
OutputDebugString( "Stored Achievement for Steam\n" );
}
}
ขั้นตอนที่ 3 - การผสานเข้ากับเกมของคุณ
รายการต่อไปนี้แสดง Code Snippet ทั้งหมดที่คุณจะต้องผสานเข้าไปในเกมของคุณในตำแหน่งที่เหมาะสม
ค่านิยามและค่าโดยรวม
ต่อไปนี้เป็นรายการของ Includes ที่ต้องสร้างไว้กับรางวัลความสำเร็จ, Enum ของรางวัลความสำเร็จเฉพาะสำหรับเกมของเรา และตัวชี้ส่วนกลางสำหรับออบเจ็กต์ช่วยเหลือของเรา โปรดทราบว่ารางวัลความสำเร็จจะตรงกับรางวัลความสำเร็จที่อยู่บนหน้าเว็บแอดมินใน Steamworks
...
#include "steam_api.h"
// Defining our achievements
enum EAchievements
{
ACH_WIN_ONE_GAME = 0,
ACH_WIN_100_GAMES = 1,
ACH_TRAVEL_FAR_ACCUM = 2,
ACH_TRAVEL_FAR_SINGLE = 3,
};
// Achievement array which will hold data about the achievements and their state
Achievement_t g_Achievements[] =
{
_ACH_ID( ACH_WIN_ONE_GAME, "Winner" ),
_ACH_ID( ACH_WIN_100_GAMES, "Champion" ),
_ACH_ID( ACH_TRAVEL_FAR_ACCUM, "Interstellar" ),
_ACH_ID( ACH_TRAVEL_FAR_SINGLE, "Orbiter" ),
};
// Global access to Achievements object
CSteamAchievements* g_SteamAchievements = NULL;
...
การเริ่มเปิดใช้งาน
การเรียกไปยัง
SteamAPI_Init จะเริ่มเปิดใช้งาน Steam ทั้งหมด และจะต้องเรียกก่อนทุกอย่างเสมอ หากการเรียกประสบความสำเร็จ เราก็จะสามารถสร้างออบเจ็กต์ช่วยเหลือได้โดยส่งเข้าไปในอาร์เรย์ของรางวัลความสำเร็จ พร้อมกับขนาดของอาร์เรย์
...
// Initialize Steam
bool bRet = SteamAPI_Init();
// Create the SteamAchievements object if Steam was successfully initialized
if (bRet)
{
g_SteamAchievements = new CSteamAchievements(g_Achievements, 4);
}
...
การประมวลผลการคอลแบ็ก
เราจะต้องทำการปั๊มข้อความใหม่อยู่เป็นประจำ เพื่อให้มั่นใจว่าเราประมวลคอลแบ็กทั้งหมดของ Steam ซึ่งจะสามารถดำเนินการได้โดยเพิ่มการเรียกนี้เข้าไปยังลูปของเกม
...
SteamAPI_RunCallbacks();
...
การเรียกใช้งานรางวัลความสำเร็จ
การเรียกใช้รางวัลความสำเร็จสามารถทำได้ง่ายพอ ๆ กับการส่งการเรียกพร้อมกับตัวระบุรางวัลความสำเร็จ
...
if (g_SteamAchievements)
g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");
...
การปิดใช้งาน
บางที การเรียกไปยัง
SteamAPI_Shutdown อาจเป็นสิ่งที่คุณมีอยู่ในโค้ดของคุณเรียบร้อยแล้ว โดยการเรียกนี้จะปิดการใช้งาน Steam และจะต้องเรียกก่อนออกจากแอปพลิเคชัน ในขั้นตอนสุดท้าย เราจะลบออบเจ็กต์ช่วยเหลือที่ได้สร้างขึ้นออก
...
// Shutdown Steam
SteamAPI_Shutdown();
// Delete the SteamAchievements object
if (g_SteamAchievements)
delete g_SteamAchievements;
...
ขั้นตอนที่ 4 - การทดสอบและการแก้ไขปัญหาเบื้องต้น
หากต้องการตั้งค่าหรือลบค่าสถิติหรือรางวัลความสำเร็จโดยไม่เพิ่มรหัสให้แก่เกมของคุณ คุณสามารถใช้คอนโซลของไคลเอนต์ Steam ได้ ใช้งานด้วย steam.exe -console จากนั้น:
- achievement_clear <appid> <achievement name>
- reset_all_stats <appid>