Dokumentasi Steamworks
Langkah demi Langkah: Pencapaian
Secara singkat
Gunakan pencapaian untuk mengapresiasi pemain yang mencapai titik pencapaian tertentu atau karena melakukan interaksi tertentu dengan game-mu.
Tingkat integrasi
10 menit dan tidak lebih dari 10 baris kode. Integrasi SDK Steamworks dibutuhkan.

Pendahuluan

Pencapaian bisa digunakan sebagai cara untuk mendorong dan menghargai interaksi dan pencapaian pemain dalam game-mu. Biasanya diberikan untuk menandai jumlah kill, jarak yang ditempuh, peti yang dibuka, atau tindakan umum lainnya dalam game-mu. Dan ini juga bisa digunakan untuk membantu pemainmu menemukan berbagai cara dalam memainkan game-mu. Ketika dibuka, pencapaian ini akan muncul di sudut jendela pemain dan di halaman pencapaian pemain tersebut.

Ringkasan Teknis

Berikut ini adalah panduan lengkap untuk mengintegrasikan Pencapaian Steam yang paling dasar ke aplikasi dalam waktu kurang dari 10 menit dan mengintegrasikan kurang dari 10 baris kode ke kode dasarmu. SDK Steamworks hadir dengan contoh aplikasi yang sangat bagus, yaitu Spacewar, yang menunjukkan beragamnya pilihan fitur Steam dan seharusnya menjadi tempat pertamamu untuk melihat kerja seluruh fitur Steam. Tutorial ini merangkum informasi yang ditemukan di Spacewar dan API Statistik dan Pencapaian, sehingga hanya menyajikan informasi yang diperlukan untuk memahami cara kerja Statistik Steam. Harap diingat bahwa ada banyak tumpang tindih antara statistik dan pencapaian, sehingga jika kamu mengintegrasikan keduanya, banyak panggilan yang akan terkonsolidasi.

Langkah 1 - Mendefinisikan Pencapaian game-mu

Pencapaian bersifat khusus untuk aplikasi dan diatur di halaman Konfigurasi Pencapaian di backend Admin Aplikasi Steamworks. Berikut adalah daftar pencapaian dari aplikasi Spacewar di Steamworks:

spacewar_achievement_examplescreenshot.jpg

Langkah Ke-2 - Mengenkapsulasi kerja Pencapaian

Kode berikut bisa diterapkan pada game apa pun dan bisa ditambahkan ke game-mu sesuai kebutuhan. Kelasnya berfungsi penuh tanpa harus diubah, tapi bisa diekstensi untuk memenuhi kebutuhan lebih lanjut. Semua kode ini diambil langsung dari file Spacewar StatsAndAchievements.cpp/h.

File Tajuk

Kita mulai dengan mendefinisikan stuktur untuk menyimpan data pencapaian yang kita terima dari Steam dan menyediakan makro untuk membuat objek jenis ini. Data ini memetakan langsung apa yang ditemukan di halaman Konfigurasi Pencapaian.
#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; };

Kemudian, definisikan kelas helper yang akan membungkus panggilan API Statistik Steam, dan akan membuat semua callback Steam.
class CSteamAchievements { private: int64 m_iAppID; // Our current AppID Achievement_t *m_pAchievements; // Data Pencapaian int m_iNumAchievements; // Jumlah Pencapaian bool m_bInitialized; // Sudahkah kamu memanggil statistik Permintaan dan menerima 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 ); };

File Kode

Konstruktor

Parameter - Konstruktor menyertakan penunjuk ke array pencapaian beserta panjang array. Format array ini tercakup dalam kode utama game di bawah ini.
Hasil - N/A
Fungsi - Konstruktor menginisialisasi sejumlah anggota sambil mengambil AppID yang sedang kita gunakan. Metode callback juga disertakan untuk memproses panggilan asinkron ke Steam. Terakhir, panggilan awal ke RequestStats() dilakukan untuk mengambil statistik dan pencapaian pengguna saat ini.
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()

Parameter - Tidak ada
Hasil - nilai boolean menunjukkan apakah panggilan berhasil atau gagal. Jika panggilan gagal, maka kemungkinan besar Steam tidak diinisialisasi. Pastikan Steam Client terbuka ketika melakukan panggilan ini dan bahwa SteamAPI_Init telah dipanggil sebelumnya.
Fungsi - Metode ini pada dasarnya membungkus panggilan ISteamUserStats::RequestCurrentStats yang merupakan panggilan asinkron ke Steam untuk meminta statistik dan pencapaian dari pemain saat ini. Panggilan ini harus dibuat sebelum kamu mengatur statistik dan pencapaian. Panggilan awal untuk metode ini dibuat di konstruktor. Kamu bisa memanggilnya lagi kapan pun setelahnya jika kamu ingin melihat pembaruan statistik atau pencapaian.
bool CSteamAchievements::RequestStats() { // Apakah Steam dimuat? Kita tidak bisa mendapatkan statistik jika tidak. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Apakah pengguna login? Kita tidak bisa mendapatkan statistik jika tidak. if ( !SteamUser()->BLoggedOn() ) { return false; } // Meminta statistik pengguna. return SteamUserStats()->RequestCurrentStats(); }

SetAchievement()

Parameter - Pengidenfikasi string dari Pencapaian yang ingin kamu atur (cth. "ACH_WIN_ONE_GAME")
Hasil - nilai boolean menunjukkan apakah panggilan berhasil atau gagal. Jika panggilan gagal, maka ini bisa disebabkan karena Steam belum diinisialisasi atau belum memproses callback dari panggilan awal ke RequestStats. Kamu tidak bisa mengatur pencapaian apa pun hingga callback sudah diterima.
Fungsi - Metode ini mengatur pencapaian tertentu untuk dicapai dan mengirim hasilnya ke Steam. Kamu bisa menetapkan pencapaian beberapa kali, jadi kamu tidak perlu khawatir untuk menetapkan hanya pencapaian yang belum kamu atur. Ini adalah panggilan asinkron yang akan memicu dua callback: OnUserStatsStored() dan OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Apakah kamu sudah menerima callback dari Steam? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Pencapaian tidak dapat diatur jika belum return false; }

OnUserStatsReceived()

Parameter - N/A
Hasil - Tidak ada
Fungsi - Metode ini adalah callback yang dipanggil kapan saja kamu mencoba meminta statistik. Statistik dan pencapaian diminta menggunakan RequestStats(). Metode ini memperbarui variabel anggota m_pAchievements untuk mencerminkan data statistik dan pencapaian yang paling terkini yang didapatkan dari Steam.
void CSteamAchievements::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // kita mungkin akan mendapatkan callback untuk statistik game lain yang datang, abaikanlah 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()

Parameter - N/A
Hasil - Tidak ada
Fungsi - Metode ini adalah callback yang dipanggil kapan saja kamu mencoba untuk menyimpan statistik di Steam.
void CSteamAchievements::OnUserStatsStored( UserStatsStored_t *pCallback ) { // kita mungkin akan mendapatkan callback untuk statistik game lain yang datang, abaikanlah 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()

Parameter - N/A
Hasil - Tidak ada
Fungsi - Metode ini adalah callback yang dipanggil kapan saja Pencapaian berhasil disimpan di 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" ); } }

Langkah Ke-3 - Mengintegrasikan ke game-mu

Berikut adalah daftar lengkap cuplikan kode yang harus kamu integrasikan ke game-mu di lokasi yang sesuai.

Definisi dan Global

Berikut ini adalah daftar pernyataan penyertaan yang dibutuhkan untuk membuat Pencapaian, penghitungan dari pencapaian khusus game kita, dan penunjuk global ke objek helper kita. Pastikan bahwa pencapaiannya sesuai dengan yang ada di halaman Admin di Steamworks.
... #include "steam_api.h" // Mendefinisikan pencapaian kita enum EAchievements { ACH_WIN_ONE_GAME = 0, ACH_WIN_100_GAMES = 1, ACH_TRAVEL_FAR_ACCUM = 2, ACH_TRAVEL_FAR_SINGLE = 3, }; // Array Pencapaian akan menyimpan data tentang pencapaian dan statusnya 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" ), }; // Akses global ke objek Pencapaian CSteamAchievements* g_SteamAchievements = NULL; ...

Inisialisasi

Panggilan ke SteamAPI_Init menginisialisasi keseluruhan Steam dan harus dipanggil sebelum yang lainnya. Jika panggilannya berhasil, buat objek helper dengan meneruskan array pencapaian dan ukuran array.
... // Menginisialisasi Steam bool bRet = SteamAPI_Init(); // Buat objek Pencapaian Steam jika Steam berhasil diinisialisasi if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

Memproses Callback

Untuk memastikan bahwa kita sudah memproses semua callback Steam, kita harus mengirimkan pesan baru secara teratur. Ini dicapai dengan menambahkan panggilan ini ke loop game.
... SteamAPI_RunCallbacks(); ...

Memicu Pencapaian

Untuk memicu pencapaian, hanya diperlukan satu panggilan yang meneruskan pengidentifikasi pencapaian.
... if (g_SteamAchievements) g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES"); ...

Mematikan

Panggilan ke SteamAPI_Shutdown adalah sesuatu yang mungkin sudah ada di kodemu. Ini akan menutup Steam dan harus dipanggil sebelum aplikasimu tertutup. Terakhir, hapus objek helper yang kita buat.
... // Matikan Steam SteamAPI_Shutdown(); // Hapus objek SteamAchievments if (g_SteamAchievements) delete g_SteamAchievements; ...

Langkah 4 - Pengujian dan Troubleshoot


Untuk mengatur atau menghapus pencapaian tanpa menambahkan kode ke game-mu, kamu bisa menggunakan konsol Steam Client. Jalankan dengan steam.exe -console, kemudian:
  • achievement_clear <appid> <achievement name>
  • reset_all_stats <appid>