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 :

É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 ne soit pas initialisé. Assurez-vous que vous avez un client Steam ouvert lorsque vous essayez d'effectuer cet appel et que
SteamAPI_Init a bien été appelée avant.
Action : cette méthode enveloppe un appel à
ISteamUserStats::RequestCurrentStats. Cet appel vers Steam est asynchrone et demande les statistiques et les succès du compte actuel. Cet appel doit être effectué avant que vous ne puissiez définir un succès ou des statistiques. L'appel initial de cette méthode est effectué par le constructeur. Par la suite, vous pouvez renouveler cet appel à tout moment si vous voulez vérifier les statistiques ou les succès mis à jour.
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 : identifiant de chaine du succès que vous voulez définir (exemple : « ACH_WIN_ONE_GAME »).
Éléments renvoyés : un booléen qui indique si l'appel a réussi ou non. Si l'appel a échoué, soit Steam n'est pas initialisé, soit vous n'avez toujours pas traité le rappel depuis l'appel initial de
RequestStats
. Vous ne pouvez pas définir de succès tant que le rappel n'a pas été reçu.
Action : cette méthode définit un succès comme « réussi » et envoie le résultat à Steam. Vous pouvez définir un même succès plusieurs fois, vous n'avez donc pas à vous inquiéter de ne définir que ceux en attente d'être définis. Il s'agit d'un appel asynchrone qui déclenche deux rappels :
OnUserStatsStored()
et
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 : aucun.
Éléments renvoyés : aucun.
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de demander des statistiques. Les statistiques et les succès sont demandés en utilisant :
RequestStats()
. La méthode met à jour la variable membre m_pAchievements pour refléter les dernières données de statistiques et de succès renvoyées depuis 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 < 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,
"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 : aucun.
Éléments renvoyés : aucun.
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de stocker des statistiques sur 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 : aucun.
Éléments renvoyés : aucun.
Action : cette méthode est un rappel qui est appelé chaque fois que des succès sont effectivement sauvegardés sur 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
Voici une liste complète d'extraits de code que vous devez intégrer dans votre jeu aux emplacements appropriés.
Définitions et variables globales
Vous trouverez ci-dessous la liste des inclusions qui sont nécessaires pour construire avec l'objet « Achievements », un enum contenant nos succès spécifiques au jeu et un pointeur global vers notre objet helper. Notez que les succès correspondent à ceux de la page d'administration sur 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
L'appel de
SteamAPI_Init initialise l'entièreté de Steam et doit être effectué avant toute autre chose. Si cet appel aboutit, l'objet helper est alors créé en transmettant le tableau des succès et la taille du tableau.
...
// 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
Pour nous assurer de traiter tous les rappels Steam, nous devons régulièrement faire remonter les nouveaux messages. Pour cela, il suffit d'ajouter cet appel dans la boucle du jeu.
...
SteamAPI_RunCallbacks();
Déclenchement des succès
Pour déclencher un succès, un seul appel qui transmet l'identifiant du succès est suffisant.
...
if (g_SteamAchievements)
g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");
Arrêt
L'appel de
SteamAPI_Shutdown se trouve probablement déjà dans votre code. Il éteint Steam et doit être appelé avant la fermeture de votre application. Enfin, nous supprimons l'objet helper que nous avons créé.
...
// Arrêter Steam
SteamAPI_Shutdown();
// Supprimer l'objet SteamAchievements
if (g_SteamAchievements)
delete g_SteamAchievements;
...
Étape 4 : test et dépannage
Pour établir ou supprimer des statistiques ou un succès sans modifier le code de votre jeu, vous pouvez utiliser la console du client Steam. Exécutez-le jeu avec steam.exe -console, suivi de :
- achievement_clear <appid> <achievement name>
- reset_all_stats <appid>