Wprowadzenie
Poniżej znajdują się instrukcje dotyczące integracji najprostszych osiągnięć z aplikacją, które mogą zostać wprowadzone w mniej niż 10 minut i do których nie trzeba więcej niż 10 linii kodu zawartych w głównym kodzie gry. W sekcji
Steamworks SDK znajdziesz doskonały przykład tego typu rozwiązania — aplikację
Spacewar. Na jej przykładzie możesz zapoznać się z całą gamę funkcji Steam. W tym przewodniku informacje prezentowane w Spacewar są filtrowane, aby wyświetlić statystyki i osiągnięcia potrzebne do zrozumienia interfejsu.
Instruktaż prezentuje najważniejsze informacje na temat Spacewar i interfejsu statystyk i osiągnięć, niezbędne do zrozumienia funkcjonowania Statystyk Steam. 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.
1. Definicja osiągnięć
Osiągnięcia są zdefiniowane dla konkretnej aplikacji i są instalowane na stronie osiągnięć
https://partner.steamgames.com/apps/achievements/ w części przeznaczonej dla administratora Steamworks. Oto osiągnięcia ze Spacewar:

2. Kapsułowanie osiągnięć
Poniższy kod działa we wszystkich grach i można go dodać do każdej z nich. Klasa jest już w pełni funkcjonalna, ale w razie potrzeby można ją łatwo rozszerzyć. Cały kod jest pobierany bezpośrednio z pliku Spacewar
StatsAndAchievements.cpp/h
.
Plik nagłówka
Zaczynamy od zdefiniowania struktury, która będzie zawierać nasze dane na temat osiągnięć otrzymane od Steam. Następnie udostępniamy makra do tworzenia obiektów tego typu. Dane te odnoszą się bezpośrednio do tego, co znajduje się na
stronie dostosowywania 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;
};
Ponadto definiowana jest klasa pomocnicza, która będzie zawierać wszystkie wywołania interfejsu API statystyk.
class CSteamAchievements
{
private:
int64 m_iAppID; // Nasz obecny identyfikator aplikacji
Achievement_t * m_pAchievements; // Dane o osiągnięciach
int m_iNumAchievements; // Liczba osiągnięć
bool m_bInitialized; // Czy zostało wysłane żądanie o statystyki 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);
};
Kod programu
Konstruktor
Parametry — konstruktor pobiera wskaźnik do tablicy osiągnięć i długość tablicy. Format tej tablicy zostanie pokazany w głównym kodzie gry.
Zwróć wartości — nie dotyczy.
To, co robi projektant — inicjuje kilku członków i akceptuje identyfikator AppID bieżącej aplikacji. Oprócz tego łączy on metody wywołań zwrotnych w celu obsługi wywołań asynchronicznych na Steam. Na koniec wywołuje wywołanie funkcji
RequestStats()
, aby uzyskać statystyki i osiągnięcia bieżącego użytkownika.
CSteamAchievements :: CSteamAchievements (Achievement_t * Osiągnięcia, int NumAchievements):
m_iAppID (0),
m_bInitialized (false),
m_CallbackUserStatsReceived (this, & CSteamAchievements :: OnUserStatsReceived),
m_CallbackUserStatsStored (this, & CSteamAchievements :: OnUserStatsStored),
m_CallbackStored (to i CSteamAchievements :: OnAchievementStored)
{
m_iAppID = SteamUtils()>GetAppID ();
m_pAchievements = Osiągnięcia;
m_iNumAchievements = NumAvievements;
RequestStats ();
}
RequestStats()
Parametry — Brak
Zwrócone wartości — bool, wskazuje, czy połączenie powiodło się. Jeśli połączenie nie powiedzie się, najprawdopodobniej Steam nie zostanie zainicjowany. Przed wywołaniem musisz upewnić się, że klient jest otwarty i że wcześniej wywołano funkcję
SteamAPI_Init.
To co robi polega na tym, że ta metoda jest zasadniczo wywołuje funkcję
ISteamUserStats::RequestCurrentStats, która jest asynchronicznym zapytaniem o statystyki i osiągnięcia bieżącego użytkownika. To wywołanie musi zostać wykonane przed zainstalowaniem statystyk i osiągnięć. Początkowe wywołanie tej metody występuje w konstruktorze. Możesz wywołać ją ponownie w dowolnym momencie, jeśli chcesz poznać zaktualizowane statystyki i osiągnięcia.
bool CSteamAchievements::RequestStats()
{
// Załadowano Steam? Jeśli nie, statystyki się nie powiodą.
if (NULL == SteamUserStats() || NULL == SteamUser())
{
return false;
}
// Użytkownik zalogowany? Jeśli nie, statystyki nie będą dostępne.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Poproś o statystyki.
return SteamUserStats()->RequestCurrentStats();
}
SetAchievement()
Parametry — identyfikator ciągu osiągnięcia, które ma zostać ustawione (na przykład "ACH_WIN_ONE_GAME")
Zwrócone wartości — bool, wskazuje, czy połączenie powiodło się. Jeśli połączenie nie powiedzie się, nie zostanie ono zainicjowane przez Steam, lub początkowe wywołania zwrotne
RequestStats
nie zostały jeszcze przetworzone. Bez otrzymania wywołania zwrotnego nie będzie możliwe ustalenie osiągnięć.
Jak działa — ta metoda ustala, że to osiągnięcie zostało zakończone, i przesyła wynik do Steam. Osiągnięcie można ustawić kilka razy, więc nie musisz się martwić instalowaniem tylko tych osiągnięć, które nie zostały jeszcze ustanowione. Jest to wywołanie asynchroniczne, w odpowiedzi na które będą odbierane dwa wywołania zwrotne:
OnUserStatsStored()
i
OnAchievementStored()
.
bool CSteamAchievements::SetAchievement(const char* ID)
{
// odebrał wywołanie zwrotne ze Steam?
if (m_bInitialized)
{
SteamUserStats()-> SetAchievement(ID);
return SteamUserStats()->StoreStats();
}
// Jeśli nie, osiągnięcie nie będzie działać
return false;
}
OnUserStatsReceived()
Parametry - nie dotyczy.
Zwrócone wartości — Nic.
Jak działa — Ta metoda to odpowiedź zwrotna, która jest wysyłana, gdy gra próbuje zażądać statystyk na Steam. Statystyki i osiągnięcia są wymagane przy użyciu
RequestStats()
. Ta metoda aktualizuje zmienną członka m_pAchievements w celu odzwierciedlenia najnowszych danych statystyk i osiągnięć zwróconych przez Steam.
void CSteamAchievements::OnUserStatsReceived( UserStatsReceived_t *pCallback )
{
// możemy otrzymywać odpwiedzi 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;
// ładowanie osiągnięć
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 — Brak.
Odpowiedzi zwrotne — Nic.
Zastosowanie — Ta metoda to odpowiedź zwrotna, która jest wysyłana za każdym razem, gdy gra próbuje zapisać statystyki na Steam.
void CSteamAchievements::OnUserStatsStored( UserStatsStored_t *pCallback )
{
// możemy orzymać wywołania zwrotne ze statystykami z innych gier, ignoruj 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 — Brak.
Odpowiedzi zwrotne — Nic.
Zastosowanie — Ta metoda to wywołanie zwrotne, które jest wysyłane, gdy osiągnięcia są zapisywane na platformie Steam.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback )
{
// możemy otrzymać wywołania zwrotne ze statystykami z innych gier, ignorouj je
if ( m_iAppID == pCallback->m_nGameID )
{
OutputDebugString( "Stored Achievement for Steam\n" );
}
}
3. Integracja w grze
Poniżej znajduje się pełna lista fragmentów kodu, które należy zintegrować z grą w odpowiednich miejscach.
Definicje i zmienne globalne
Poniżej znajduje się lista połączeń wymaganych dla obiektu Osiągnięcia, lista osiągnięć związanych z tą grą oraz globalny wskaźnik do obiektu pomocniczego. Osiągnięcia są zbieżne z tymi wymienionymi na stronie Steamworks.
...
#include "steam_api.h"
// definiujemy 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,
};
// szereg osiągnięć zawierających dane o osiągnięciach i 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 Osiągnięcia
CSteamAchievements* g_SteamAchievements = NULL;
...
Inicjalizacja
Wywołanie
SteamAPI_Init inicjuje Steam i musi zostać wykonane jako pierwsze. Jeśli wywołanie się powiedzie, tworzony jest obiekt pomocniczy, do którego przenoszona jest tablica osiągnięć i rozmiar tablicy.
...
// inicjalizacja Steam
bool bRet = SteamAPI_Init();
// twórz obiekt SteamAchievements, jeśli inicjalizacja Steam powiedzie się
if (bRet)
{
g_SteamAchievements = new CSteamAchievements(g_Achievements, 4);
}
...
Obsługa odpowiedzi zwrotnych
Aby obsłużyć wszystkie wywołania zwrotne Steam, musisz regularnie sprawdzać, czy nie pojawiły się nowe wiadomości. Aby to zrobić, należy dodać to połączenie do pętli gry.
...
SteamAPI_RunCallbacks();
...
Aktywacja osiągnięć
Osiągnięcie aktywacji jest proste. Potrzebne jest tylko jedno połączenie, które przekazuje identyfikator osiągnięcia.
...
if (g_SteamAchievements)
g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");
...
Zamykanie interfejsu SteamAPI
Wywołanie
SteamAPI_Shutdown, które zamyka Steam, najprawdopodobniej znajduje się już w twoim kodzie. Musi zostać wysłane przed zamknięciem aplikacji. Na końcu poprzednio utworzony obiekt pomocniczy zostaje usunięty.
...
// Wyłącz Steam
SteamAPI_Shutdown();
// Usuń SteamAchievements
if (g_SteamAchievements)
delete g_SteamAchievements;
...
4. Testowanie i rozwiązywanie problemów
Ten przykładowy kod wyświetla informacje debugowania w konsoli debugowania, które są potrzebne do zrozumienia, które połączenia są wykonywane, a które nie. Poniżej przedstawiono typowe komunikaty o błędach i rozwiązania:
This application has failed to start because steam_api.dll was not found. Re-installing the application may fix this problem. (Aplikacja nie została uruchomiona, ponieważ nie znaleziono pliku d3dx_??. Dll. Ponowna instalacja aplikacji może rozwiązać problem).Plik steam_api.dll powinien znajdować się w tym samym katalogu, co plik wykonywalny.
[S_API FAIL] SteamAPI_Init() failed; unable to locate a running instance of Steam, or a local steamclient.dll (Wywołanie funkcji SteamAPI_Init() nie powiodło się, ponieważ nie można znaleźć działającego pliku Steam lub lokalnego pliku steamclient.dll).Najprawdopodobniej klient Steam nie działa. Uruchom Steam i zaloguj się.
[S_API FAIL] SteamAPI_Init() failed; no appID found. (Wywołanie funkcji SteamAPI_Init () nie powiodło się, nie znaleziono AppID)Najprawdopodobniej brakuje pliku steam_appid.txt we właściwym folderze. Umieść go we właściwym miejscu i upewnij się, że ma numer aplikacji.