Steamworks dokumentáció
Lépésről lépésre: Teljesítmények
Röviden
A teljesítmények használatával jutalmazhatod a játékosokat bizonyos mérföldkövek eléréséért, vagy bizonyos fajta interakciókért a játékoddal.
Az integrálás szintje
Tíz perc, és kevesebb mint tíz sornyi kód. Steamworks SDK integráció szükséges.

Bevezetés

A teljesítmények a játékos-interakciók és mérföldkövek elérésének ösztönzésére és jutalmazására használhatók a játékodban. Gyakran jelölnek velük ölésszámot, megtett kilométert, kinyitott ládák számát vagy más gyakori tevékenységet a játékodban. A használatukkal segíthetsz a játékosoknak felfedezni a játékod játszásának különféle módjait is. A feloldáskor ezek a teljesítmények megjelennek a játékosok ablakának sarkában, és bejelölésre kerülnek az adott játékos teljesítményoldalán.

Műszaki áttekintés

Az alábbi egy gyors, lépésenkénti útmutató nagyon alapszintű Steam Teljesítmények integrálásához az alkalmazásodba kevesebb mint tíz perc alatt, és kevesebb, mint tíz sornyi kód integrálásával a kódbázisodba. A Steamworks SDK tartalmaz egy nagyszerű, Spacewar nevű példaalkalmazást, amely bemutatja a Steam szolgáltatások teljes skáláját, és érdemes ezzel kezdeni, hogy lásd az összes Steam funkciót működés közben. Ez az oktatás leszűkíti a Spacewarban és a Statisztikák és Teljesítmények API-ban található információkat a csak a Steam Statisztikához szükségesekre, hogy a dolgok a lehető legegyszerűbbek legyenek. Vedd figyelembe, hogy jelentős átfedés van a statisztikák és a teljesítmények között, így ha mindkettőt integrálod, sok hívás konszolidálható.

1. lépés – A játékod teljesítményeinek meghatározása

A teljesítmények alkalmazásspecifikusak, és a Steamworks alkalmazás-adminisztrációs háttérrendszer Teljesítmény-beállítások oldalán állíthatók be. Alább látható a Spacewar Steamworks példaalkalmazás teljesítménylistája:

spacewar_achievement_examplescreenshot.jpg

2. lépés – A teljesítménybeágyazási munka

Az alábbi kód játékfüggetlen, és tetszés szerint hozzáadható a játékodhoz. Az osztály jelen állapotában is teljesen működőképes, de könnyen bővíthető bármilyen további igény kielégítésére. Ezt a kódot közvetlenül a Spacewar példafájljaiból vettük: StatsAndAchievements.cpp/h.

Fejléc fájl

Először definiálunk egy struktúrát a Steamtől kapott teljesítményadatok tárolására, és adunk egy makrót ilyen típusú objektumok létrehozásához. Ezek az adatok közvetlenül a Teljesítmény-beállítások oldalon találhatókra képeződnek le.
#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; };

Ezután definiálunk egy segítő osztályt, amely becsomagolja az összes Steam Statisztikák API-hívást, valamint létrehozza az összes Steam callbacket.
class CSteamAchievements { private: int64 m_iAppID; // a jelenlegi AppID-nk Achievement_t *m_pAchievements; // teljesítményadatok int m_iNumAchievements; // a teljesítmények száma bool m_bInitialized; // meghívtuk már a statisztikakérést, és megkaptuk a callbacket? 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 ); };

Kódfájl

Konstruktor

Paraméterek: A konstruktor egy, a teljesítmények tömbjére mutató mutatót fogad, valamint a tömb hosszát. E tömb formázásával majd később, a játék fő kódja foglalkozik.
Visszatérési érték: nincs.
Mit csinál: A konstruktor számos tagot inicializál, valamint elkapja az AppID-t, amely alatt jelenleg futunk. Továbbá felcsatolja a callback metódusokat a Steam felé indított aszinkron hívások kezelésére. Végül végrehajtja az első RequestStats() hívást a jelenlegi felhasználó statisztikáinak és teljesítményeinek lekérésére.
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()

Paraméterek: nincs.
Visszatérési érték: A hívás sikerességét vagy sikertelenségét jelző bool. Ha a hívás sikertelen volt, akkor a Steam valószínűleg nincs inicializálva. Győződj meg róla, hogy van nyitott Steam kliens, amikor megpróbálkozol ezzel a hívással, és hogy a SteamAPI_Init meg volt hívva előtte.
Mit csinál: Ez a metódus lényegében becsomagol egy ISteamUserStats::RequestCurrentStats hívást, amely egy aszinkron hívás a Steamhez a jelenlegi felhasználó statisztikáinak és teljesítményeinek lekérésére. Ezt a hívást végre kell hajtani, mielőtt bármilyen statisztikát vagy teljesítményt tudnál beállítani. E metódus első hívása a konstruktorban történik. Ezt követően bármikor újra meghívhatod, ha a frissült statisztikákat vagy teljesítményeket szeretnéd ellenőrizni.
bool CSteamAchievements::RequestStats() { // Be van töltve a Steam? Ha nem, nem tudunk statisztikákat kérni. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Be van jelentkezve a felhasználó? Ha nem, nem tudunk statisztikákat kérni. if ( !SteamUser()->BLoggedOn() ) { return false; } // Felhasználóstatisztikák lekérése. return SteamUserStats()->RequestCurrentStats(); }

SetAchievement()

Paraméterek: A beállítani kívánt teljesítmény azonosító karakterlánca (pl. "ACH_WIN_ONE_GAME").
Visszatérési érték: A hívás sikerességét vagy sikertelenségét jelző bool. Ha a hívás sikertelen, akkor a Steam nincs inicializálva, vagy még nem dolgoztad fel a callbacket az inicializáló RequestStats-tól. Amíg azt a callbacket nem kaptad meg, nem tudsz teljesítményeket beállítani.
Mit csinál: Ez a metódus elértre állít egy adott teljesítményt, és elküldi az eredményeket a Steamnek. Egy teljesítményt többször is beállíthatsz, így nem kell amiatt aggódnod, hogy csak olyan teljesítményt állíts be, ami még nincs beállítva. Ez egy aszinkron hívás, amely két callbacket fog elindítani: OnUserStatsStored() és OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Kaptunk már callbacket a Steamtől? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Ha nem, még nem tudunk teljesítményeket beállítani. return false; }

OnUserStatsReceived()

Paraméterek: nincs.
Visszatérési érték: semmi.
Mit csinál: Ez a metódus egy callback, amely meghívódik, valahányszor statisztikákat próbálsz lekérni. A statisztikák és a teljesítmények a RequestStats()használatával kérhetők le. A metódus frissíti az m_pAchievements tagváltozót, hogy az tükrözze a Steam által visszaküldött legfrissebb statisztika- és teljesítményadatokat.
void CSteamAchievements::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // kaphatunk callbacket más játékok statisztikáinak beérkezésekor, ezekkel nem törődünk if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString("Received stats and achievements from Steam\n"); m_bInitialized = true; // teljesítmények betöltése 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()

Paraméterek: nincs.
Visszatérési érték: semmi.
Mit csinál: Ez a metódus egy callback, amely meghívódik, valahányszor statisztikákat próbálsz tárolni a Steamen.
void CSteamAchievements::OnUserStatsStored( UserStatsStored_t *pCallback ) { // kaphatunk callbacket más játékok statisztikáinak beérkezésekor, ezekkel nem törődünk 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()

Paraméterek: nincs.
Visszatérési érték: semmi.
Mit csinál: Ez a metódus egy callback, amely meghívódik, valahányszor sikeres volt teljesítmények tárolása a Steamen.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback ) { // kaphatunk callbacket más játékok statisztikáinak beérkezésekor, ezekkel nem törődünk if ( m_iAppID == pCallback->m_nGameID ) { OutputDebugString( "Stored Achievement for Steam\n" ); } }

3. lépés – Integrálás a játékba

Az alábbi mindazon kódrészletek felsorolása, amelyeket a megfelelő helyeken integrálnod kell a játékba.

Defines és Globals

Az alábbi azon include-ok listája, amelyek szükségesek a Teljesítményekkel végzett buildhez, egy enum a játékspecifikus teljesítményeinkkel és egy, a helper objektumunkra mutató globális mutató. Vedd észre, hogy a teljesítmények megegyeznek a Steamworks adminisztrációs oldalán levőkkel.
... #include "steam_api.h" // Definiáljuk a teljesítményeinket enum EAchievements { ACH_WIN_ONE_GAME = 0, ACH_WIN_100_GAMES = 1, ACH_TRAVEL_FAR_ACCUM = 2, ACH_TRAVEL_FAR_SINGLE = 3, }; // A teljesítmények tömbje, amely a teljesítményeket és azok állapotait fogja tartalmazni 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" ), }; // Globális hozzáférés az Achievements objektumhoz CSteamAchievements* g_SteamAchievements = NULL; ...

Inicializálás

Az SteamAPI_Init meghívása inicializálja a teljes Steamet, és minden más előtt kell meghívni. Ha ez a hívás sikeres, akkor létrehozzuk a helper objektumot, átadva neki a teljesítmények tömbjét és a tömb méretét.
... // A Steam inicializálása bool bRet = SteamAPI_Init(); // A SteamAchievements objektum létrehozása, ha a Steam inicializálása sikeres volt if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

Callbackek feldolgozása

Az összes Steam callback feldolgozásának biztosítására rendszeresen keresnünk kell az új üzeneteket. Ezt az alábbinak a játékhurokhoz adásával érjük el:.
... SteamAPI_RunCallbacks(); ...

Teljesítmények aktiválása

Egy teljesítmény aktiválása egyszerűen egyetlen hívás végrehajtásával és a teljesítményazonosító átadásával történik.
... if (g_SteamAchievements) g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES"); ...

Leállítás

A SteamAPI_Shutdown meghívása már valószínűleg szerepel a kódodban. Ez állítja le a Steamet, és az alkalmazásod kilépése előtt meg kell hívni. Végül töröljük az általunk létrehozott helper objektumot.
... // Steam leállítása SteamAPI_Shutdown(); // A SteamAchievements objektum törlése if (g_SteamAchievements) delete g_SteamAchievements; ...

4. lépés – Tesztelés és hibaelhárítás


Teljesítmény vagy statisztika beállításához vagy törléséhez anélkül, hogy kódot adnál a játékodhoz, használni tudod a Steam kliens konzolját. Futtasd a steam.exe -console paranccsal, majd:
  • achievement_clear <AppID> <teljesítménynév>
  • reset_all_stats <AppID>