Game SDK
Game bicara ke arcade lewat window.taploka. Host menyuntikkan SDK ke index.html-mu saat menyajikan bundle, jadi
bundle-mu tidak boleh ikut mengirimnya. Panggil saja.
Kenapa ini jembatan, bukan klien HTTP
Game jalan di frame tersandbox pada origin buram: tidak ada cookie, tidak ada penyimpanan, tidak ada cara menjangkau API sendiri. Setiap panggilan adalah pesan ke halaman host, yang menjalankan permintaannya memakai sesi pemain lalu mengirim hasilnya balik. Inilah yang mencegah sebuah bundle bertindak sebagai pemain di luar gamenya.
Akibat praktisnya:
localStoragedansessionStoragetidak tersedia. Pakaisave()/load()sebagai gantinya.- Fetch relatif ke arcade tidak akan terautentikasi, karena tidak ada sesi di dalam frame.
- Semua yang dibutuhkan game harus ada di dalam bundle.
API
Setiap metode mengembalikan promise.
ready()
const { game, version, player, studio, sdk, room } = await taploka.ready();
Panggil sekali saat start-up. Dia memberi tahu kamu sedang jalan sebagai game dan versi apa, dan siapa yang bermain.
room adalah kode room yang disentuh pemain di halaman game di arcade, atau null pada peluncuran biasa; lihat
Room multiplayer.
version adalah nomor versi bundle yang diterima pemain, sama dengan yang tercatat di konsol, jadi layar judul atau
laporan bug bisa mencetaknya tanpa menyimpan string build sendiri. studio adalah kredit yang ditampilkan arcade untuk
game ini, yaitu nama studio developernya, atau arcade sendiri untuk game yang diterbitkan arcade. Cetak keduanya
daripada menulisnya tetap di bundle: versi yang ditulis tetap jadi basi pada push berikutnya, dan studio yang ditulis
tetap jadi basi begitu game berpindah tangan. Keduanya null kalau tidak ada host yang menjawab, jadi sediakan nilai
cadangan untuk mode standalone.
submitScore(score, meta?)
const { accepted, rank, best } = await taploka.submitScore(1200, { level: 4 });
Skor dibulatkan ke bawah menjadi bilangan bulat non-negatif. accepted bernilai false kalau skornya ditahan untuk
ditinjau. Gamemu harus tetap berjalan normal apa pun jawabannya. Game boleh mendeklarasikan skor tertinggi yang masuk
akal; apa pun di atas itu ditandai, bukan diterbitkan ke papan peringkat.
Game yang membiarkan pemain menamai dirinya sendiri, perusahaan, kru, atau stable, mengirim nama itu sebagai
meta.name:
await taploka.submitScore(1200, { name: 'PT Maju Jaya', level: 4 });
Nama itu yang tampil di papan game ini, di dalam game maupun di halaman peringkat arcade, dan tidak mengubah apa pun di akun. Kirim di tiap pengiriman skor: ganti nama tetap masuk walau skornya bukan rekor baru. Teksnya dibersihkan dari karakter kontrol dan dipotong di 24 karakter. Kalau tidak dikirim, nama akun yang dipakai, dan itu yang seharusnya dilakukan game yang tidak punya nama sendiri.
save(payload) dan load()
await taploka.save({ level: 3, coins: 120 });
const state = await taploka.load(); // objek terurai, atau null untuk pemain baru
Cloud save berlaku per pemain per game. Objek diserialisasi untukmu; string disimpan apa adanya. save() mengembalikan
nomor revisi.
leaderboard(limit?, period?)
const { entries, userRank, period } = await taploka.leaderboard(20);
const hariIni = await taploka.leaderboard(20, 'daily');
// entries: [{ rank, name, score, isCurrentUser }]
Baca nama tampilannya dari name; pemain tanpa nama datang sebagai "Pemain". userRank adalah posisi pemain saat
ini, kalau dia punya.
Setiap skor ditulis ke tiga papan sekaligus, dan period memilih papan mana yang kembali: daily (reset tengah malam WIB,
batas hari yang sama dengan quest dan streak), weekly (yang membayar koin waktu ditutup) atau alltime. Kalau tidak
diisi, yang kembali tetap mingguan. periodKey ikut kembali, jadi game bisa membedakan papan basi dari papan baru
setelah hari berganti.
wallet(), spend(amount, reason, options?)
const { balance, earned, spent } = await taploka.wallet();
const after = await taploka.spend(50, 'continue', { key: `continue-${runId}` });
Koin adalah mata uang arcade dan mengikuti pemain lintas game. spend() memotong dan tidak memberi apa pun, jadi pakai
untuk konsumsi yang tidak bisa diwakili tokomu. Dia ditolak dengan error.code === 'INSUFFICIENT_BALANCE' kalau saldo
pemain kurang.
shop(), buy(sku, options?), inventory()
const { items } = await taploka.shop(); // [{ sku, title, coin_price, type, owned, qty }]
const { item, balance } = await taploka.buy('engine_lv2');
const owned = await taploka.inventory(); // [{ sku, qty, granted_at }]
Harganya datang dari daftar yang kamu daftarkan per game, jadi bundle hanya bisa menyebut nama sku. Kepemilikan
disimpan di sisi server: baca inventory() saat start-up, jangan percaya cloud save yang ditulis klien dan bisa
diedit. Pembelian bersifat idempoten, dan buy() ditolak dengan ITEM_OWNED, ITEM_UNKNOWN, atau
INSUFFICIENT_BALANCE.
Lihat Koin dan toko untuk alur lengkapnya, termasuk cara mendaftarkan daftar harga.
prize.status(), prize.claim()
const { rank, coins, claimed, prizes, balance } = await taploka.prize.status();
const { paid } = await taploka.prize.claim(); // hadiah hari ini, sekali saja
Hadiah koin hari ini untuk kursi teratas papan harian game ini. Kursinya dibaca di server, dari papan peringkat yang
disimpan arcade, jadi game boleh minta dibayar tapi tidak pernah menentukan sendiri haknya. coins adalah nilai kursi
pemain saat itu, dan rank bernilai null untuk orang yang hari ini belum mencetak skor.
prizes adalah tabelnya sendiri, dikunci dengan kursi terakhir tiap tingkat, jadi { "1": 100, "2": 50, "3": 25, "10": 10 }
membayar juara 100 dan kursi 4 sampai 10 masing-masing 10 koin. Tampilkan sebelum ada yang mengklaim, itu alasan orang
main satu ronde lagi.
Satu hadiah per pemain per hari. claim() membayar sekali dan ketukan kedua menjawab paid: 0 dengan claimed: true.
Harinya juga ditutup sendiri sejam sebelum tengah malam waktu arcade, jadi game tanpa tombol klaim tetap memberi hadiah
ke pemainnya, dan mengklaim dari dalam game cuma mengambil koin yang sama lebih awal. Khusus pemain berakun, jadi tamu
ditolak dengan ACCOUNT_REQUIRED.
market.list(), market.sell(item, price), market.buy(id), market.cancel(id), market.claim()
const { listings, proceeds } = await taploka.market.list(); // [{ id, price, item, mine, seller, listed_at }]
const { listing } = await taploka.market.sell({ truck: 'hino', wear: 12 }, 7500000);
const { item } = await taploka.market.buy(listings[0].id); // barangnya, diserahkan sekali
await taploka.market.cancel(listing.id); // turunkan lapak, barang kembali
const { total, sales } = await taploka.market.claim(); // yang laku selagi kamu pergi
Lapak tempat pemain berjualan ke pemain lain, memakai uang gamemu sendiri, bukan koin arcade. Bentuk barangnya
milikmu dan sampai ke pembeli persis seperti yang kamu pasang. Selama lapak terbuka, barangnya dititipkan di arcade,
dan itulah yang membuat satu truk tidak bisa terjual dua kali: buy() mengunci barisnya, jadi dari dua pembeli yang
menekan bersamaan satu dapat barang dan satu lagi dapat LISTING_GONE.
Dua hal mengikuti dari letak uangnya. Penjual biasanya sedang pergi waktu barangnya laku, jadi harganya menunggu di
server sampai gamenya memanggil claim(); meminta dua kali tetap dibayar sekali. Dan arcade tidak pernah memeriksa
transaksinya: saldomu ada di simpanan yang ditulis klien, jadi "penjual memang punya barang ini" dan "pembeli memang
mampu" adalah klaim gamemu, bukan fakta yang bisa diverifikasi server. Potong di pembeli, bayar waktu klaim, dan jaga
harga tetap di rentang yang kamu tentukan.
Khusus pemain berakun, jadi tamu ditolak dengan ACCOUNT_REQUIRED. Dua belas lapak terbuka per pemain per game.
feed.on(listener), feed.send(payload)
taploka.feed.on((line) => {
if (line.payload.type !== 'jackpot') return;
marquee(`${line.from} dapat ${line.payload.prize}`); // line.from kamu sendiri yang escape
});
await taploka.feed.send({ type: 'jackpot', prize: 'emas' });
Room menjangkau orang yang sedang main bersamamu. Feed menjangkau semua orang yang sedang main game ini, di dalam
room maupun tidak, dan itulah yang dibutuhkan drop langka, jackpot, atau rekor yang pecah. line berbentuk
{ from, payload, at }.
from adalah nama tampilan pengirim, diambil server dari akunnya. Game tidak bisa menyetelnya dan pemain tidak bisa
memalsukannya, dan itu lebih penting di sini daripada di room, karena kanal ini publik: siapa pun yang bisa membuka
gamenya bisa membaca semua barisnya. Jangan taruh apa pun di payload yang tidak pantas dipajang di baliho, dan jangan
pernah simpanan, token, atau skor yang belum dilihat server. Maksimal 512 byte dan 12 kunci.
Soketnya baru terbuka di on() yang pertama dan tidak oleh apa pun yang lain, jadi game yang tidak pernah mengumumkan
apa-apa juga tidak menanggung biayanya. send() selesai terlepas dari ada atau tidaknya yang mendengarkan; tidak ada
riwayat, pemain yang sedang offline ya terlewat. Enam baris per menit per pemain, dan host yang lebih tua dari API ini
sama sekali tidak punya taploka.feed, jadi periksa dulu dan mundur ke room:
const wide = taploka.feed && typeof taploka.feed.send === 'function';
track(name, params?)
taploka.track('level_end', { level: 4, outcome: 'win' });
Event gameplay untuk analitik. Tembak dan lupakan.
exit()
taploka.exit();
Minta host menutup game dan mengembalikan pemain ke katalog. Panggil dari tombol keluarmu sendiri, bukan saat nyawa habis.
Contoh minimal
<script>
(async () => {
const session = await taploka.ready();
const state = await taploka.load() ?? { level: 1 };
startGame(state, {
onLevelEnd: (level) => taploka.track('level_end', { level }),
onGameOver: async (score) => {
await taploka.submitScore(score);
await taploka.save({ level: state.level });
},
});
})();
</script>
Bundle lib Astrocade
Bundle yang dibangun untuk host Astrocade memanggil global window.lib. Arcade memasang adaptor yang memetakan lib.*
ke jembatan yang sama, jadi bundle seperti itu jalan tanpa diubah, termasuk panggilan papan peringkatnya, yang kini
sampai ke server sungguhan alih-alih shim playtest bawaannya.
Checklist sebelum push
- Game mulai dari
index.htmltanpa proses build saat runtime. - Tidak ada URL absolut ke mesin dev-mu; semua aset ada di dalam bundle.
sdk_versiondigame.jsonsesuai SDK yang kamu tuju.- Skor dikirim saat game over, bukan tiap frame.
- Game tetap jalan saat
load()mengembalikannull. - Apa pun yang dijual dengan koin dibaca balik dari
inventory(), bukan dari cloud save.