Накратко
Използвайте постиженията, така че да възнаграждавате играчите за постигането на специфични значими достижения или за взаимодействия с играта по определени начини.Ниво на интеграция
10 минути и по-малко от 10 реда код. Нужна е интеграция на Steamworks SDK.Въведение
Постиженията могат да се използват като начин за насърчаване и възнаграждаване на взаимодействията на играчите и значимите достижения в играта Ви. Те често се използват за отбелязване на броя на убийствата, изминатите километри, отворените сандъци или други общи действия в играта. Те също така могат да се използват, за да помогнат на Вашите играчи да открият различни начини за пускане на играта Ви. 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.
Технически обзор
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. The
Steamworks SDK comes with a great example application called
Spacewar that shows off the full breadth of Steam features and should be your first stop to see all Steam features in action. This tutorial distills the information found in Spacewar and the Stats and Achievements API down to just the necessary information required for Steam Stats to keep things as straightforward as possible. Please note that there is a considerable amount of overlap between stats and achievements, as such if you are integrating both be aware that a lot of calls can be consolidated.
Стъпка 1 — Определяне на постиженията за играта Ви
Постиженията са специфични за приложението и се настройват на страницата
„Конфигуриране на постиженията“ в крайната инфраструктура на Steamworks админ. на приложението. По-долу е списъкът с постиженията от примерното приложение Spacewar на Steamworks:
Стъпка 2 — Работа по капсулиране на постиженията
Следният код е независим от играта и може да бъде добавен към нея по Ваше усмотрение. Класът е напълно функционален в този си вид, но може лесно да бъде разширен, за да отговаря на всякакви допълнителни изисквания. All of this code was taken directly from the Spacewar example files
StatsAndAchievements.cpp/h
.
Файл на заглавната част
We first define a structure to hold our achievement data received from Steam and provide a macro for creating objects of that type. Тези данни конфигурират директно на тези, които могат да се намерят на страницата
„Конфигуриране на постиженията“.
#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;
};
Next we define a helper class that will wrap all of the Steam Stats API calls as well as creating all of the
Steam callbacks.
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 );
};
Файл с код
Конструктор
Параметри - The constructor takes a pointer to an array of achievements along with the length of the array. The formating of that array will be covered in the main game code later.
Връща — Не е налично
Какво прави - 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. Finally it makes an initial call to
RequestStats()
to get stats and achievements for the current user.
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()
Параметри — Няма;
Връща - a bool representing if the call succeeded or not. If the call failed then most likely Steam is not initialized. Make sure you have a Steam client open when you try to make this call and that
SteamAPI_Init has been called before it.
Какво прави - 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. Първоначалното повикване към този метод се прави в конструктора. 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? If not we can't get stats.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Request user stats.
return SteamUserStats()->RequestCurrentStats();
}
SetAchievement()
Параметри - The string identifier of the Achievement that you want to set (ie. „ACH_WIN_ONE_GAME“)
Връща - 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.
Какво прави - 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)
{
// 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()
Параметри — Не е налично
Връща — Нищо.
Какво прави - 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()
Параметри — Не е налично
Връща — Нищо.
Какво прави - 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()
Параметри — Не е налично
Връща — Нищо.
Какво прави - 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;
...
Инициализация
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.
...
// Initialize Steam
bool bRet = SteamAPI_Init();
// Create the SteamAchievements object if Steam was successfully initialized
if (bRet)
{
g_SteamAchievements = new CSteamAchievements(g_Achievements, 4);
}
...
Обработване на обратни повиквания
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 an achievement is as simple as a single call passing along the achievement identifier.
...
if (g_SteamAchievements)
g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");
...
Изключване
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 <№_на_приложение> <име на постижение>;
- reset_all_stats <№_на_приложение>