Steamworks-dokumentasjon
Steg for steg: prestasjoner
Kort oppsummert
Bruk prestasjoner for å belønne spillere for å oppnå spesifikke milepæler, eller for å samhandle med spillet ditt på spesifikke måter.
Integrasjonsnivå
10 minutes and under 10 lines of code. Integrasjon med Steamworks' SDK kreves.

Innledning

Achievements can be used as a way to encourage and reward player interactions and milestones within your game. De brukes ofte for å markere antall drap, kilometer kjørt, kister åpnet eller andre vanlige handlinger i et spill. And they can also be used to help your players discover different ways of playing your game. When unlocked, these achievements will pop up in the corner of the players' window and will be marked within an achievement page for that player.

Teknisk oversikt

The following is a quick step by step guide to integrating very basic Steam Achievements into your application in under 10 minutes and under 10 lines of code integrated into your code base. Steamworks' SDK kommer med en fantastisk eksempelapplikasjon med navn Spacewar som viser det fullstendige omfanget av funksjoner på Steam og bør være første steg for å se alle funksjonene til Steam i bruk. Denne veiledningen fokuserer på informasjonen som finnes i Spacewar og prestasjons-API-et, og har kun med nødvendig informasjon for Steam-statistikk for å gjøre det så enkelt som mulig. Merk at det finnes betydelig overlapp mellom statistikk og prestasjoner, så hvis du integrerer begge deler må du være klar over at mange kall kan samles sammen.

1. steg – definer spillets prestasjoner

Prestasjoner er spesifikke for en applikasjon, og settes opp i prestasjonskonfigurasjonen i applikasjonsadministrasjonen på Steamworks. Følgende er listen over prestasjoner fra eksempelapplikasjonen Spacewar i Steamworks:

spacewar_achievement_examplescreenshot.jpg

2. steg – arbeid med å fange opp prestasjoner

Følgende kode er uavhengig av spill, og kan legges til i spillet ditt etter egne krav. The class is fully functional as is but can be easily extended to meet any further needs. All dene koden ble hentet direkte fra eksempelfilene til Spacewar – StatsAndAchievements.cpp/h.

Header File

Vi definerer først en struktur for å holde prestasjonsdata fra Steam, og leverer en makro for å opprette objekter av denne typen. Disse dataene kan tilordnes direkte til det som finnes i prestasjonskonfigurasjonen.
#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; };

Det neste vi må gjør er å definere en hjelperklasse som pakker inn all API-kallene for Steam-statistikk, og opprette alle tilbakekallene til Steam.
class CSteamAchievements { private: int64 m_iAppID; // Aktuell app-ID. Achievement_t *m_pAchievements; // Prestasjonsdata int m_iNumAchievements; // Antallet prestasjoner bool m_bInitialized; // Har vi kalt RequestStats() og mottatt et tilbakekall? 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 ); };

Kodefil

Constructor

Parametre - The constructor takes a pointer to an array of achievements along with the length of the array. Vi tar for oss formatering av tabellen i hovedkoden til spillet senere.
Returns – Ikke aktuelt
Hva dette gjør - The constructor initializes a number of members along with grabbing the AppID we are currently running as. In addition it hooks up the call back methods to handle asynchronous calls made to Steam. Til slutt utfører det et innledende kall til RequestStats() for å hente statistikk og prestasjoner for gjeldende bruker.
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()

Parametre – Ingen
Returns - a bool representing if the call succeeded or not. If the call failed then most likely Steam is not initialized. Pass på at Steam-klienten er åpen når du prøver å utføre dette kallet, og at SteamAPI_Init er blitt kalt tidligere.
Hva dette gjør – Denne metoden pakker inn et kall til ISteamUserStats::RequestCurrentStats, som er et asynkront kall til Steam som ber om statistikk og prestasjoner for gjeldende bruker. This call needs to be made before you can set any stats or achievements. The initial call to this method is made in the constructor. You can call it again any time after that if you want to check on updated stats or achievements.
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? Hvis ikke, kan vi ikke hente statistikk. if ( !SteamUser()->BLoggedOn() ) { return false; } // Request user stats. return SteamUserStats()->RequestCurrentStats(); }

SetAchievement()

Parametre - The string identifier of the Achievement that you want to set (ie. "ACH_WIN_ONE_GAME")
Returns - a bool representing if the call succeeded or not. If the call failed then either Steam is not initialized or you still haven't processed the callback from the initial call to RequestStats. Du kan ikke angi prestasjoner inntil dette tilbakekallet er blitt mottatt.
Hva dette gjør – Denne metoden angir en gitt prestasjon som skal utstedes, og sender resultatet til Steam. Du kan angi en gitt prestasjon flere ganger, så du behøver ikke å bekymre deg om å kun angi prestasjoner som ikke allerede er blitt angitt. Dette er et asynkront kall som utløser to tilbakekall: OnUserStatsStored() og OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Har vi mottatt et tilbakekall fra Steam? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Hvis ikke så kan vi ikke angi prestasjoner enda return false; }

OnUserStatsReceived()

Parametre – Ikke aktuelt
Returns – Ingenting
Hva dette gjør - This method is a callback that is called anytime you attempt to request stats. Stats and achievements are requested by using RequestStats(). The method updates the member variable m_pAchievements to reflect the latest stats and achievement data returned from 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()

Parameters - N/A
Returns - Nothing
What it does - This method is a callback that is called anytime you attempt to store stats on 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()

Parameters - N/A
Returns - Nothing
What it does - This method is a callback that is called anytime Achievements are successfully stored on 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" ); } }

Step 3 - Integrating into your game

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

Defines and Globals

The following is the list of includes that are needed to build with Achievements, an enum of our game specific achievements and a global pointer to our helper object. Please note that the achievements match those of the Admin page on 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; ...

Initialization

The call to SteamAPI_Init initializes all of Steam and must be called before anything else. Hvis kallet lykkes, så oppretter vi et hjelperobjekt ved å sende inn tabellen med prestasjoner sammen med størrelsen på tabellen.
... // Initialize Steam bool bRet = SteamAPI_Init(); // Create the SteamAchievements object if Steam was successfully initialized if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

Processing Callbacks

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(); ...

Triggering Achievements

Triggering an achievement is as simple as a single call passing along the achievement identifier.
... if (g_SteamAchievements) g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES"); ...

Shutdown

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

Step 4 - Testing and Troubleshooting


To set or clear stats or an achievement without adding code to your game, you can use the Steam client console. Run with steam.exe -console, then:
  • achievement_clear <appid> <achievement name>
  • reset_all_stats <appid>