W skrócie
Użyj osiągnięć, by nagrodzić graczy, gdy osiągną pewien kamień milowy lub wejdą w jakąś konkretną interakcję z twoją grą.Poziom integracji
10 minut i mniej niż 10 linii kodu. Integracja ze Steamworks SDK jest konieczna.Wprowadzenie
Osiągnięcia można wykorzystać, by zachęcić oraz nagrodzić gracza za wchodzenie w interakcję z twoją grą oraz za osiągnięte kamienie milowe. Często używa się ich do oznaczania liczby zabójstw, przejechanych kilometrów, otwartych skrzyń lub innych częstych działań w twojej grze. Mogą być one również wykorzystane, by pomóc twoim graczom odkryć różne sposoby, na jakie można grać w twoją grę. Osiągnięcia pojawiają się w rogu okna graczy po zdobyciu i zostaną oznaczone na stronie osiągnięć danego gracza.
Wprowadzenie techniczne
Poniżej znajduje się szybki poradnik krok po kroku dotyczący integracji najprostszych osiągnięć Steam z aplikacją, które mogą zostać wprowadzone w mniej niż 10 minut i które wymagają mniej niż 10 linii kodu w głównym kodzie gry. Sekcja
Steamworks SDK zawiera doskonały przykład aplikacji o nazwie
Spacewar. Pokazuje on całą gamę funkcji Steam w akcji, dlatego zalecamy zapoznanie się z nim. Ten artykuł prezentuje tylko najbardziej podstawowe informacje w oparciu o Spacewar oraz API osiągnięć i statystyk, by kwestia statystyk Steam była jak najbardziej przejrzysta. Zauważ, że statystyki i osiągnięcia pokrywają się w wielu miejscach. Jeśli więc zintegrujesz obie funkcje, wiele wywołań będzie mogło zostać skonsolidowanych.
Krok 1 – definiowanie osiągnięć twojej gry
Osiągnięcia są definiowane dla konkretnej aplikacji oraz konfigurowane na
stronie osiągnięć w back-endzie administratora aplikacji Steamworks. Poniżej znajduje się lista osiągnięć z przykładowej aplikacji Steamworks o nazwie Spacewar:
Krok 2 – enkapsulacja osiągnięć
Poniższy kod działa we wszystkich grach i możesz go zaimplementować wedle uznania. Ta klasa jest w pełni funkcjonalna sama w sobie, ale w razie potrzeby można ją łatwo rozszerzyć. Cały kod pochodzi bezpośrednio ze Spacewar z plików
StatsAndAchievements.cpp/h
.
Plik nagłówkowy
Zaczynamy od zdefiniowania struktury, która będzie przechowywać nasze dane na temat osiągnięć otrzymane od Steam. Następnie zapewniamy makra do tworzenia obiektów tego typu. Dane te odnoszą się bezpośrednio do tego, co znajduje się na
stronie konfiguracji osiągnięć.
#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;
};
Następnie definiujemy klasę pomocniczą, która będzie opakowywać wszystkie wywołania API statystyk Steam oraz tworzyć wszystkie
wywołania zwrotne Steam.
class CSteamAchievements
{
private:
int64 m_iAppID; // Nasze obecne AppID
Achievement_t *m_pAchievements; // Dane o osiągnięciach
int m_iNumAchievements; // Liczba osiągnięć
bool m_bInitialized; // Czy wywołaliśmy żądanie statystyk i czy otrzymaliśmy wywołanie zwrotne?
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 );
};
Plik kodu
Konstruktor
Parametry – argumentami konstruktora są wskaźnik do tablicy osiągnięć oraz długość tablicy. Format tej tablicy zostanie pokazany w głównym kodzie gry poniżej.
Zwraca – nie dotyczy.
Zastosowanie – konstruktor inicjalizuje kilka pól i równocześnie pobiera AppID bieżącej aplikacji. Oprócz tego łączy on metody wywołań zwrotnych w celu obsługi wywołań asynchronicznych przekazywanych do Steam. Na koniec wykonuje wstępne wywołanie funkcji
RequestStats()
, aby uzyskać statystyki i osiągnięcia bieżącego użytkownika.
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()
Parametry – brak.
Zwraca – wartość bool wskazującą, czy wywołanie powiodło się. Jeśli wywołanie nie powiodło się, najprawdopodobniej Steam nie jest zainicjalizowany. Musisz upewnić się, że klient Steam jest otwarty w momencie wykonywania tego wywołania i że wcześniej wywołano funkcję
SteamAPI_Init.
Zastosowanie – ta metoda zasadniczo zawiera wywołanie
ISteamUserStats::RequestCurrentStats, które asynchronicznie żąda od Steam przesłania statystyk i osiągnięć bieżącego użytkownika. To wywołanie musi zostać wykonane przed ustawieniem jakichkolwiek statystyk i osiągnięć. Początkowe wywołanie tej metody występuje w konstruktorze – możesz potem wywołać je ponownie w dowolnym momencie, jeśli chcesz sprawdzić zaktualizowane statystyki i osiągnięcia.
bool CSteamAchievements::RequestStats()
{
// Czy Steam został wczytany? Jeśli nie, nie możemy uzyskać statystyk.
if (NULL == SteamUserStats() || NULL == SteamUser())
{
return false;
}
// Czy użytkownik jest zalogowany? Jeśli nie, nie możemy uzyskać statystyk.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Zażądaj statystyk użytkownika.
return SteamUserStats()->RequestCurrentStats();
}
SetAchievement()
Parametry – identyfikator typu string osiągnięcia, którego wartość chcesz ustawić (np. „ACH_WIN_ONE_GAME”).
Zwraca – wartość bool wskazującą, czy wywołanie powiodło się. Jeśli wywołanie nie powiodło się, to albo Steam nie został zainicjalizowany, albo wywołanie zwrotne z początkowego wywołania
RequestStats
nie zostało jeszcze przez ciebie przetworzone. Bez otrzymania wywołania zwrotnego nie będzie możliwe ustawienie statusu osiągnięć.
Zastosowanie – ta metoda ustawia status danego osiągnięcia na zdobyte i przesyła wynik do Steam. Status osiągnięcia można ustawiać wiele razy, więc nie musisz martwić się innymi osiągnięciami, które nie zostały jeszcze ustawione jako zdobyte. Jest to wywołanie asynchroniczne, które aktywuje dwa wywołania zwrotne:
OnUserStatsStored()
i
OnAchievementStored()
.
bool CSteamAchievements::SetAchievement(const char* ID)
{
// Czy otrzymaliśmy wywołanie zwrotne ze Steam?
if (m_bInitialized)
{
SteamUserStats()->SetAchievement(ID);
return SteamUserStats()->StoreStats();
}
// Jeśli nie, to nie można zmieniać jeszcze statusów osiągnięć
return false;
}
OnUserStatsReceived()
Parametry – nie dotyczy.
Zwraca – nic.
Zastosowanie – ta metoda to wywołanie zwrotne wykonywane za każdym razem, gdy próbujesz zażądać statystyk. Żądanie o przesłanie statystyk i osiągnięć jest wysyłane przy użyciu
RequestStats()
. Ta metoda aktualizuje pole m_pAchievements w celu odzwierciedlenia najnowszych danych statystyk i osiągnięć zwróconych przez Steam.
void CSteamAchievements::OnUserStatsReceived( UserStatsReceived_t *pCallback )
{
// możliwe, że otrzymamy wywołania zwrotne o nadejściu statystyk innych gier, zignoruj je
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString("Received stats and achievements from Steam\n");
m_bInitialized = true;
// wczytaj osiągnięcia
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()
Parametry – nie dotyczy.
Zwraca – nic.
Zastosowanie – ta metoda to wywołanie zwrotne wykonywane za każdym razem, gdy próbujesz zapisać statystyki na Steam.
void CSteamAchievements::OnUserStatsStored( UserStatsStored_t *pCallback )
{
// możliwe, że otrzymamy wywołania zwrotne o nadejściu statystyk innych gier, zignoruj je
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()
Parametry – nie dotyczy.
Zwraca – nic.
Zastosowanie – ta metoda to wywołanie zwrotne wykonywane za każdym razem, gdy osiągnięcia zostają pomyślnie zapisane na Steam.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback )
{
// możliwe, że otrzymamy wywołania zwrotne o nadejściu statystyk innych gier, zignoruj je
if ( m_iAppID == pCallback->m_nGameID )
{
OutputDebugString( "Stored Achievement for Steam\n" );
}
}
Krok 3 – integracja w twojej grze
Poniżej znajduje się pełna lista fragmentów kodu, które należy zintegrować z twoją grą w odpowiednich miejscach.
Definicje i zmienne globalne
Poniżej znajduje się lista dyrektyw #include wymaganych dla obiektu Achievements, typ wyliczeniowy naszych osiągnięć dla danej gry oraz globalny wskaźnik do naszego obiektu pomocniczego. Pamiętaj, że osiągnięcia są zbieżne z tymi wymienionymi na stronie administratora Steamworks.
...
#include "steam_api.h"
// Definiujemy nasze osiągnięcia
enum EAchievements
{
ACH_WIN_ONE_GAME = 0,
ACH_WIN_100_GAMES = 1,
ACH_TRAVEL_FAR_ACCUM = 2,
ACH_TRAVEL_FAR_SINGLE = 3,
};
// Tablica osiągnięć, która będzie przechowywać dane o osiągnięciach oraz o ich statusie
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" ),
};
// Globalny dostęp do obiektu Achievements
CSteamAchievements* g_SteamAchievements = NULL;
...
Inicjalizacja
Wywołanie
SteamAPI_Init całościowo inicjalizuje Steam i musi zostać wykonane jako pierwsze. Jeśli będzie ono pomyślne, to następnie tworzymy obiekt pomocniczy, przekazując do niego tablicę osiągnięć wraz z jej rozmiarem.
...
// Zainicjalizuj Steam
bool bRet = SteamAPI_Init();
// Stwórz obiekt SteamAchievements, jeśli Steam został pomyślnie zainicjalizowany
if (bRet)
{
g_SteamAchievements = new CSteamAchievements(g_Achievements, 4);
}
...
Obsługa wywołań zwrotnych
Aby upewnić się, że obsłużymy wszystkie wywołania zwrotne Steam, musimy regularnie sprawdzać, czy nie pojawiły się nowe komunikaty. Aby to zrobić, należy dodać to wywołanie do pętli gry.
...
SteamAPI_RunCallbacks();
...
Aktywacja osiągnięć
Aktywacja osiągnięcia jest prosta. Potrzebne jest tylko jedno wywołanie, które przekazuje identyfikator osiągnięcia.
...
if (g_SteamAchievements)
g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");
...
Zamykanie
Wywołanie
SteamAPI_Shutdown najprawdopodobniej znajduje się już w twoim kodzie. Zamyka ono Steam i musi zostać ono wywołane przed zamknięciem twojej aplikacji. Na końcu usuwamy poprzednio utworzony obiekt pomocniczy.
...
// Zamknij Steam
SteamAPI_Shutdown();
// Usuń obiekt SteamAchievements
if (g_SteamAchievements)
delete g_SteamAchievements;
...
Krok 4 – testowanie i rozwiązywanie problemów
Aby ustawić lub wyczyścić statystyki lub osiągnięcie bez dodawania kodu do twojej gry, możesz użyć konsoli klienta Steam. Uruchom steam.exe z parametrem -console, a następnie:
- achievement_clear <ID aplikacji> <nazwa osiągnięcia>
- reset_all_stats <ID aplikacji>