Documentation Steamworks
Les succès, étape par étape
En quelques mots
Utilisez les succès afin de récompenser vos fans pour avoir réussi certaines étapes clés ou pour avoir interagi avec votre jeu d'une certaine façon.
Niveau d'intégration
10 minutes et moins de 10 lignes de code. Intégration du SDK Steamworks nécessaire.

Introduction

Les succès sont une façon d'encourager et de récompenser les interactions et les progrès dans votre jeu. Ils sont souvent utilisés pour célébrer un nombre de victimes atteint, de kilomètres parcourus, de coffres ouverts ou d'autres actions fréquentes présentes dans votre jeu. Ils peuvent également servir à aider les joueurs et les joueuses à découvrir de nouvelles façons d'aborder votre jeu. Une fois déverouillés, ces succès apparaitront dans le coin de la fenêtre pour la personne en jeu et seront indiqués sur sa page des succès.

Présentation technique

Ci-dessous, vous trouverez un guide rapide qui vous aidera, étape par étape, à intégrer dans votre application des succès Steam très basiques en moins de 10 minutes et en moins de 10 lignes de code dans votre base de code. Le SDK Steamworks est livré avec une excellente application exemple, appelée Spacewar, qui démontre toute l'ampleur des fonctionnalités de Steam. Il est conseillé de commencer par là pour voir toutes les fonctionnalités de Steam en action. Ce didacticiel concentre les informations trouvées dans Spacewar et dans l'API des statistiques et des succès pour vous fournir uniquement les informations nécessaires pour comprendre le fonctionnement de l'interface SteamUserStats. Notez qu'il existe une grande quantité de chevauchements entre les statistiques et les succès. Ainsi, si vous intégrez les deux, sachez que beaucoup d'appels peuvent être regroupés.

Étape 1 : définir les succès de votre jeu

Les succès sont spécifiques à l'application et peuvent être configurés sur la page de configuration des succès de l'administration de l'application dans Steamworks. Voici la liste des succès de l'application exemple de Steamworks, Spacewar :

spacewar_achievement_examplescreenshot.jpg

Étape 2 : travail d'encapsulation des succès

Le code qui suit est indépendant du jeu et peut être ajouté au vôtre comme vous le souhaitez. La classe est entièrement fonctionnelle en l'état, mais peut être facilement étendue pour répondre à d'autres besoins. Tout ce code est directement tiré des fichiers exemples de Spacewar StatsAndAchievements.cpp/h.

Fichier d'entête

Nous commençons par définir une structure qui contiendra nos données de succès reçues depuis Steam et une macro qui crée des objets de ce type. Ces données correspondent exactement à ce que l'on retrouve sur la page de configuration des succès.
#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; };

Ensuite, nous définissons une classe auxiliaire qui enveloppera tous les appels de l'API Steam Stats et créera tous les rappels Steam.
class CSteamAchievements { private: int64 m_iAppID; // AppID actuel Achievement_t *m_pAchievements; // Données des succès int m_iNumAchievements; // Nombre de succès bool m_bInitialized; // A-t-on appelé RequestStats et reçu le rappel ? 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 ); };

Fichier de code

Constructeur

Paramètres : le constructeur prend un pointeur sur un tableau de succès ainsi que la taille du tableau. Le formatage du tableau sera traité plus tard dans le code principal du jeu.
Éléments renvoyés : aucun.
Action : le constructeur initialise un certain nombre de membres tout en récupérant l'AppID que nous utilisons actuellement. Il connecte également les méthodes de rappel pour gérer les appels asynchrones effectués vers Steam. Enfin, il effectue un appel initial à RequestStats() pour obtenir les statistiques et les succès du compte actuel.
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ètres : aucun.
Éléments renvoyés : un booléen qui indique si l'appel a réussi ou non. Si l'appel a échoué, il est très probable que Steam n'est pas initialisé. Make sure you have a Steam client open when you try to make this call and that SteamAPI_Init has been called before it.
Action : - This method basically wraps a call to ISteamUserStats::RequestCurrentStats which is an asynchronous call to steam requesting the stats and achievements of the current user. 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() { // Est-ce que Steam est lancé ? Si non, il est impossible d'obtenir des statistiques. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Est-ce que la personne est connectée ? Si non, il est impossible d'obtenir des statistiques. if ( !SteamUser()->BLoggedOn() ) { return false; } // Demander les statistiques de l'utilisateur ou l'utilisatrice. return SteamUserStats()->RequestCurrentStats(); }

SetAchievement()

Paramètres : - The string identifier of the Achievement that you want to set (ie. "ACH_WIN_ONE_GAME")
Éléments renvoyés : - 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. You can't set any achievements until that callback has been received.
Action : - This method sets a given achievement to achieved and sends the results to Steam. You can set a given achievement multiple times so you don't need to worry about only setting achievements that aren't already set. This is an asynchronous call which will trigger two callbacks: OnUserStatsStored() and OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Un appel de Steam a-t-il été reçu ? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Si non, les succès ne peuvent pas être définis. return false;

OnUserStatsReceived()

Paramètres : - N/A
Éléments renvoyés : - Nothing
Action : - 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 ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les. if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString("Stats et succès reçus de Steam\n"); m_bInitialized = true; // chargez les succès for ( int iAch = 0; 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, "nom")); _snprintf( ach.m_rgchDescription, sizeof(ach.m_rgchDescription), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "desc")); } } else { char buffer[128]; _snprintf( buffer, 128, "Échec de RequestStats, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnUserStatsStored()

Paramètres : - N/A
Éléments renvoyés : - Nothing
Action : - This method is a callback that is called anytime you attempt to store stats on Steam.
void CSteamAchievements::OnUserStatsStored( UserStatsStored_t *pCallback ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les. if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "Stats stockées pour Steam\n" ); } else { char buffer[128]; _snprintf( buffer, 128, "Échec de StatsStored, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnAchievementStored()

Paramètres : - N/A
Éléments renvoyés : - Nothing
Action : - This method is a callback that is called anytime Achievements are successfully stored on Steam.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les. if ( m_iAppID == pCallback->m_nGameID ) { OutputDebugString( "Succès stocké pour Steam\n" ); } }

Étape 3 : intégration dans votre jeu

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

Définitions et variables globales

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" // On définit nos succès. enum EAchievements { ACH_WIN_ONE_GAME = 0, ACH_WIN_100_GAMES = 1, ACH_TRAVEL_FAR_ACCUM = 2, ACH_TRAVEL_FAR_SINGLE = 3, }; // Tableau des succès qui contient des données sur les succès et leur état. Achievement_t g_Achievements[] = { _ACH_ID( ACH_WIN_ONE_GAME, "Vainqueur" ), _ACH_ID( ACH_WIN_100_GAMES, "Champion" ), _ACH_ID( ACH_TRAVEL_FAR_ACCUM, "Interstellaire" ), _ACH_ID( ACH_TRAVEL_FAR_SINGLE, "Étoile" ), }; // Accès global à l'objet Achievements CSteamAchievements* g_SteamAchievements = NULL; ...

Initialisation

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 by passing in the array of achievements along with the size of the array.
... // Initialiser Steam bool bRet = SteamAPI_Init(); // Créer l'objet SteamAchievements si Steam a été initialisé avec succès. if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

Traitement des rappels

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

Déclenchement des succès

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");

Arrêt

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.
... // Arrêter Steam SteamAPI_Shutdown(); // Supprimer l'objet SteamAchievements if (g_SteamAchievements) delete g_SteamAchievements; ...

Étape 4 : test et dépannage


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
  • reset_all_stats