10 Ekim 2026 Cumartesi

Google Play Games-præstationer i mobilspil: Butikspåvirkning, grænsen på 2.000 XP og MonoGame-arkitektur




Google Play Games-præstationer i mobilspil: Butikspåvirkning, grænsen på 2.000 XP og MonoGame-arkitektur

Når du har udviklet og udgivet et mobilspil i butikken, begynder den virkelige udfordring: at forvandle en spillers første nysgerrige minutter til et langsigtet engagement. Hvis spillerne kun overlades til et simpelt "gennemfør banen, start den næste"-loop, melder trætheden sig hurtigt—eller de lukker appen uden nogensinde at have opdaget halvdelen af de dybere spilmekanikker, du har skabt.

Ved første øjekast ligner præstationssystemet i Google Play Games Services (GPGS) Achievements måske blot en samling små emblemer på skærmen. Når det designes gennemtænkt, bliver det imidlertid en kraftfuld fastholdelsesmotor (retention), der guider spillerne gennem hvert eneste lag af spillets mekanikker.

I denne tekniske artikel gennemgår vi, hvad præstationer rent faktisk bidrager med i Google Play-økosystemet, hvordan vi designede 79 unikke præstationer under Googles strenge XP-regler til Blocked: Pixel Panzer, og hvordan vi konstruerede en asynkron MonoGame / C#-batchbehandlingspipeline, der forhindrer FPS-dyk og Android ANR-fejl (Application Not Responding) under intense arkadekampe.


1. Hvorfor er Google Play Games-præstationer vigtige?

Integrering af Google Play Games-præstationer giver fire konkrete fordele inden for både spillerpsykologi og butikkens præstationsmålinger:

  1. Alternative mål og fastholdelse af spillere (Day-7 / Day-30 Retention):
    Ikke alle spillere kan nå 1. pladsen på den globale førertavle (Leaderboard), men enhver spiller kan arbejde hen imod "Ødelæg 100 tårne" eller "Gennemfør en bane uden at tage skade." Gradvise (inkrementelle) præstationer giver en mærkbar statuslinje, der rykker sig fremad i hver spilsession.
  2. Naturlig indlæring af spilmekanikker (Implicit Onboarding):
    Spillere holder sig ofte til deres standardvåben og tøver med at eksperimentere. I Blocked: Pixel Panzer opfordrer vi dem til at opdage og mestre alle elementære tilstande ved at belønne spillere for at smelte blokke med grøn syre-ammunition på ColorWheel eller ramme kritiske pletskud med sort ammunition.
  3. Øjeblikkelig feedback og Google Play Gamer XP:
    At se det officielle Google Play Games-banner glide ned fra toppen af skærmen midt i en ophedet kamp—og optjene XP til deres globale Google Play Gamer-profil—giver spillerne en varig følelse af progression knyttet direkte til deres styresystem.
  4. Google Play-økosystemet og kvalitetssignaler:
    Google Play Games Services V2 (PGS V2)-integration giver automatisk Zero-Tap-login, problemfri kompatibilitet med Google Play Games on PC og stærkere engagementsignaler under fanen "Spil" i Google Play Butik.

Blocked: Pixel Panzer In-Game Achievement Unlock Toast
Den officielle Google Play Games "Turret Buster I"-underretning, der dukker op øverst på skærmen i præcis det øjeblik, det 10. tårn ødelægges under en bane 103-kamp i Blocked: Pixel Panzer.


2. Google Play Console-regler: Grænsen på 2.000 XP og 10.000 trin

Når du konfigurerer præstationer i Google Play Console, skal du designe ud fra tre strenge platformsbegrænsninger:

  • Den hårde grænse på 2.000 XP (Hard Cap): Summen af alle præstationspoint i et enkelt spil må ikke overstige 2.000 XP. Hver enkelt præstation skal tildele mellem 5 og 200 XP i intervaller af 5.
  • Grænsen på 10.000 trin for gradvise præstationer: Præstationer med kumulative tællere understøtter maksimalt 10.000 trin (steps) i Play Console.
  • Krav om Play Games Services V2: Google udfaser det ældre V1 SDK. Moderne Android-spil skal bygges på Xamarin.GooglePlayServices.Games.V2 (PlayGamesSdk og PlayGames.GetAchievementsClient).

Design af et katalog med 79 præstationer i Blocked: Pixel Panzer

Ved at analysere vores centrale spilenheder (TurretBlock, FighterJet, EnemyRocket, ColorWheel, HydraRegenerationSkill, Season) opbyggede vi 79 præstationer på i alt 1.995 / 2.000 XP fordelt på 6 hovedkategorier:

Kategori Eksempler på præstationer Type Mål / Mekanik
Enemy Hunters Jet Hunter I–III, Sky Dominator, Turret Buster I–III, Siege Master Gradvis Ødelæg 10, 100, 1.000 og 10.000 jagerfly, forsvarstårne og målsøgende raketter.
Block Destruction & Explosives Pioneer Breaker, Demolition Crew, Crusher Supreme, Pixel Obliterator, Chain Reaction Gradvis / Standard Knus fra 1.000 til 10.000 blokke og spræng 5/25/50 mål i en enkelt dynamiteksplosion.
ColorWheel & Weapon Mastery Prismatic Pilot, Acid Dissolver, Critical Striker, Power Blaster, Speedy Sprinter, Beam Vaporizer Gradvis Smelt blokke med grøn syre, lav sorte kritiske drab, affyr røde kraftskud, lasere og raketter.
Stage & Boss Progression First Blood, Giant Slayer, Decimator, Speedrunner I–III Gradvis / Standard Første fjendedrab, første bosssejr og gennemførelse af baner på under 4 minutter.
Purist Challenges Untouchable, Clean Victory I–III, Purist Gladiator, Mono Specialist Gradvis / Standard Besejr bosser og gennemfør svære baner uden at tage skade eller uden brug af færdigheder.
Atmosphere, Supplies & Meta Storm Fighter, Retro Connoisseur, Gem Tycoon, Quad Spectrum, Audiophile, Loyal Supporter Gradvis / Skjult Ødelæg 100 tårne i regnvejr, saml CRT-skærme og lyt til hele numre i musikafspilleren.

For hver præstation skabte vi skræddersyede 512x512 pixel-art emblemer, hvis rammer udvikler sig fra bronze til guld og prismatiske niveauer i takt med sværhedsgraden:

Blocked: Pixel Panzer Custom Achievement Badges
Seks eksempler på 512x512 emblemer fra vores katalog med 79 præstationer: Sky Dominator, Turret Buster III, Pixel Obliterator, Prismatic Pilot IV, Acid Dissolver II og Power Blaster II.

Pro-tip (Masseimport via ZIP): At indtaste 79 præstationer manuelt i webgrænsefladen på Google Play Console tager flere timer. Brug i stedet Play Consoles funktion "Import achievements" ved at pakke AchievementsMetadata.csv, AchievementsIconsMappings.csv og dine 512x512 .jpg-ikoner i et enkelt .zip-arkiv for at importere hele kataloget på få sekunder.

Google Play Console Published Achievements Table
Vores offentliggjorte præstationer og XP-fordeling i Google Play Console.


3. Ren arkitektur: IGamesService og AchievementDirector i delt kode

Blocked: Pixel Panzer er et tværplatforms MonoGame-projekt, der kører på både Windows PC (Microsoft Store) og Android (Google Play). For at holde vores delte gameplay-projekt (Blocked.Shared) fuldstændig fri for afhængigheder af Android SDK, anvender vi princippet om afhængighedsinversion (Dependency Inversion Principle - SOLID).

Først definerer vi en platformsuafhængig IGamesService-kontrakt i det delte lag:

namespace Blocked.Shared.Services
{
    public interface IGamesService
    {
        void Initialize();
        Task<bool> SignIn();
        Task<bool> IsAuthenticated();
        
        // Leaderboards
        void SubmitScore(string leaderboardId, long score);
        void ShowLeaderboards();
        void ShowLeaderboard(string leaderboardId);

        // Achievements
        void UnlockAchievement(string achievementId);
        void IncrementAchievement(string achievementId, int steps = 1);
        void ShowAchievements();
    }
}

I stedet for at sprede præstationstjek ud over CollisionManager, GameplayScreen og Player, samler vi alle 79 regler i en enkelt koordinatorklasse, AchievementDirector:

public static class AchievementDirector
{
    public static void OnEnemyKilled(
        bool isJet = false,
        bool isTurret = false,
        bool isRocket = false,
        bool isBoss = false,
        Bullet? killingBullet = null,
        bool killedByLaser = false)
    {
        var gamesService = ScreenManager.Instance?.GamesService;
        if (gamesService == null) return; // Udfører sikkert ingenting på pc-udgaver

        if (isTurret)
        {
            gamesService.IncrementAchievement(AchievementIds.TurretBuster1, 1);
            gamesService.IncrementAchievement(AchievementIds.TurretBuster2, 1);
            gamesService.IncrementAchievement(AchievementIds.TurretBuster3, 1);
            gamesService.IncrementAchievement(AchievementIds.SiegeMaster, 1);

            // Tårne ødelagt under regnvejr fremmer "Storm Fighter"
            if (Season.Current == SeasonKind.Rainy)
            {
                gamesService.IncrementAchievement(AchievementIds.StormFighter, 1);
            }
        }

        TrackWeaponKill(gamesService, killingBullet, killedByLaser);
    }
}

4. Kritisk udvikling: Eliminering af JNI / Binder IPC-overhead for at forhindre ANR

I et hæsblæsende arkadespil skaber det en alvorlig ydeevnefælde, hvis præstationstriggere forbindes direkte til Google Play SDK:

Når en spiller sprænger en eksplosiv blok (ExplosiveBlock) eller affyrer færdigheden laserstråle (Laser Beam), kan 20 til 30 blokke og fjender blive ødelagt inden for en enkelt frame (16,6 millisekunder). Når hver ødelæggelse opdaterer 5 eller 6 gradvise niveauer, kan en enkelt frame udløse mere end 150 IncrementAchievement-kald!

Hvis du afsender 150 synkrone JNI- og Binder IPC-kald til Google Play Services på spillets primære opdateringstråd:

  1. Grundlæggende Android-enheder (Android Go-telefoner med 1–2 GB RAM) rammes øjeblikkeligt af voldsomme billedhak.
  2. Tabellen for globale JNI-referencer (GREF) fyldes op, hvilket udløser ANR-rapporter (Input dispatching timed out) i Google Play Vitals.

Vores løsning: 1,5 sekunders batchbehandling i hukommelsen og sessions-deduplikering

Vores implementering i GooglePlayGamesService.cs adskiller fuldstændigt MonoGame-opdateringsløkken fra Google Play IPC-kald:

  1. Sessions-deduplikering (_unlockedInSession):
    Når en standardpræstation låses op under en session, føjes dens id til et HashSet<string>. Gentagne udløsere i samme eller efterfølgende frames returnerer øjeblikkeligt i C# uden JNI-omkostninger.
  2. 1,5 sekunders baggrunds-batchbehandling (_pendingIncrements):
    Kald til IncrementAchievement øger blot et heltal i et Dictionary<string, int> i hukommelsen på hovedtråden (nul JNI-kald). En baggrundsarbejder oprettet via Task.Run vågner efter 1,5 sekunder, tager et øjebliksbillede af de akkumulerede totaler og sender dem til Google Play Services i et enkelt samlet kald pr. præstation.
  3. Håndtering af 26502: CLIENT_RECONNECT_REQUIRED og offline caching:
    Hvis en spiller lægger spillet i baggrunden i flere timer og vender tilbage, kan Google Play-sessionstokenet udløbe og kaste fejlen 26502 (CLIENT_RECONNECT_REQUIRED). Vores tjeneste opfanger dette, forsøger et enkelt lydløst SignIn() i baggrunden med en cooldown-sikring og falder tilbage på GPGS's lokale offline cache (client.Unlock), hvis enheden er offline—hvilket sikrer, at ingen spillerfremgang nogensinde går tabt.
private static readonly HashSet<string> _unlockedInSession = new(StringComparer.Ordinal);
private static readonly Dictionary<string, int> _pendingIncrements = new(StringComparer.Ordinal);
private static readonly object _achievementBatchLock = new();
private static bool _incrementFlushScheduled = false;

public void IncrementAchievement(string achievementId, int steps = 1)
{
    if (!_isInitialized || string.IsNullOrEmpty(achievementId) || steps <= 0)
        return;

    bool shouldSchedule = false;
    lock (_achievementBatchLock)
    {
        // NUL JNI-omkostning på spillets opdateringstråd — ren aggregering i hukommelsen!
        if (_pendingIncrements.TryGetValue(achievementId, out int current))
            _pendingIncrements[achievementId] = current + steps;
        else
            _pendingIncrements[achievementId] = steps;

        if (!_incrementFlushScheduled)
        {
            _incrementFlushScheduled = true;
            shouldSchedule = true;
        }
    }

    if (shouldSchedule)
    {
        Task.Run(async () =>
        {
            await Task.Delay(1500).ConfigureAwait(false);
            FlushPendingIncrementsNow();
        });
    }
}

private void FlushPendingIncrementsNow()
{
    List<KeyValuePair<string, int>>? snapshot = null;

    lock (_achievementBatchLock)
    {
        _incrementFlushScheduled = false;
        if (_pendingIncrements.Count == 0) return;

        snapshot = new List<KeyValuePair<string, int>>(_pendingIncrements);
        _pendingIncrements.Clear();
    }

    var act = _activity;
    if (act == null || act.IsFinishing || act.IsDestroyed) return;

    var client = PlayGames.GetAchievementsClient(act);
    foreach (var kvp in snapshot)
    {
        if (kvp.Value > 0)
        {
            // 150 begivenheder i en frame bliver til 1 samlet trinvist kald til GPGS
            client.Increment(kvp.Key, kvp.Value);
        }
    }
}

5. Hvordan følger spillerne deres præstationer i spillet?

Popups under kampen er fantastiske, men spillerne har også brug for et overskueligt sted at gennemse låste emblemer, kontrollere procentvis fremgang på gradvise trin og vælge deres næste mål.

For at understøtte dette elegant forvandlede vi den mobile statistikskærm til et samlet STATS & RANKS-center. Øverst på skærmen pulserer to gyldne knapper—LEADERBOARD og ACHIEVEMENTS—med en jævn 2-sekunders sinusbølgeglød (Math.Sin). På Windows Desktop-versioner skjules disse mobilspecifikke knapper automatisk for at bevare det klassiske og rene layout på STATISTICS.

Når spilleren trykker på ACHIEVEMENTS:

  1. FlushPendingIncrementsNow() køres øjeblikkeligt, så al fremgang fra de sidste 1,5 sekunder gemmes, inden brugerfladen åbnes.
  2. GetAchievementsIntent() åbner Google Play Games' oprindelige Achievements-overlay direkte oven på spillet:

Native Google Play Games Achievements Overlay in Blocked: Pixel Panzer
Det oprindelige Google Play Games Achievements-overlay åbnet fra skærmen STATS & RANKS, som viser den samlede gennemførelse (2 / 79), anbefalede mål, oplåste emblemer (Loyal Supporter, Audiophile) og låste gradvise fremskridtsringe.

Spillere kan gennemse deres 2 / 79-fremgang, se personlige anbefalinger og spore gradvise procentringe uden nogensinde at forlade appen.


6. Konklusion og vores spil

Når det implementeres med et afbalanceret budget på 2.000 XP og en ikke-blokerende baggrunds-batchpipeline, er Google Play Games-præstationer en af de mest effektive måder at tilføje dybde og langsigtet genspilningsværdi til et arkadespil uden at gå på kompromis med billedhastigheden.

Hvis du vil opleve vores progressionssystem med 79 præstationer, ColorWheel-kampmekanikker og globale ranglister med egne øjne—eller udforske vores andre spil—kan du finde dem i butikkerne herunder:

🎮 Vores spil:

📢 Følg vores devlogs og fællesskab:

Følg os for flere tekniske artikler, klip bag kulisserne og spilopdateringer:


Tags og emner

#GooglePlayGames #Achievements #MonoGame #CSharp #MobileGameDev #AndroidDev #IndieDev #GameArchitecture #BlockedPixelPanzer #PaintTrek #ArarGames




Hiç yorum yok:

Yorum Gönder