10 Ekim 2026 Cumartesi

Assoliments de Google Play Games en jocs mòbils: Impacte a la botiga, límit de 2.000 XP i arquitectura MonoGame




Assoliments de Google Play Games en jocs mòbils: Impacte a la botiga, límit de 2.000 XP i arquitectura MonoGame

Un cop crees i publiques un joc mòbil a la botiga, comença el veritable desafiament: transformar la curiositat dels primers minuts del jugador en un compromís a llarg termini. Quan els jugadors es troben amb un simple bucle de "supera el nivell, comença el següent", tard o d'hora arriba la fatiga — o tanquen l'aplicació sense haver descobert ni la meitat de les mecàniques de joc profundes que vas dissenyar.

A primera vista, el sistema d'assoliments de Google Play Games Services (GPGS) pot semblar simplement una col·lecció de petites insígnies. Tanmateix, quan es dissenya amb criteri, es converteix en un potent motor de retenció (retention) que guia els jugadors a través de cada capa de les mecàniques del joc.

En aquest article tècnic, desglossem què aconsegueixen realment els assoliments a l'ecosistema de Google Play, com vam dissenyar 79 assoliments únics sota les estrictes regles d'XP de Google per a Blocked: Pixel Panzer, i com vam desenvolupar una canalització asíncrona de processament per lots en MonoGame / C# que evita caigudes d'FPS i errors ANR (Application Not Responding) a Android durant els combats arcade més intensos.


1. Per què són importants els assoliments de Google Play Games?

La integració dels assoliments de Google Play Games aporta quatre beneficis concrets tant en la psicologia del jugador com en les mètriques de rendiment a la botiga:

  1. Objectius alternatius i retenció de jugadors (Day-7 / Day-30 Retention):
    No tots els jugadors poden arribar al número 1 de la taula de classificació global (Leaderboard), però tothom pot treballar per assolir objectius com "Destrueix 100 torretes" o "Supera una fase sense rebre danys." Els assoliments incrementals ofereixen una barra de progrés tangible que avança amb cada sessió de joc.
  2. Ensenyar mecàniques de joc de manera natural (Onboarding implícit):
    Els jugadors sovint s'aferren a la seva arma per defecte i dubten a l'hora d'experimentar. A Blocked: Pixel Panzer, premiar els jugadors per fondre blocs simultàniament amb munició àcida verda a la ColorWheel o per aconseguir cops crítics amb munició negra els anima a descobrir i dominar cada mode elemental.
  3. Retroacció instantània i Google Play Gamer XP:
    Veure com la pancarta oficial de Google Play Games llisca des de la part superior de la pantalla enmig d'un combat intens —i guanyar XP per al seu nivell global de jugador de Google Play— proporciona als jugadors una sensació permanent de progrés vinculada al perfil del seu sistema operatiu.
  4. Ecosistema de Google Play i senyals de qualitat:
    La integració de Google Play Games Services V2 (PGS V2) aporta inici de sessió automàtic sense tocs (Zero-Tap), compatibilitat perfecta amb Google Play Games a PC i senyals de compromís més forts a la pestanya "Jocs" de Google Play Store.

Blocked: Pixel Panzer In-Game Achievement Unlock Toast
La notificació emergent (toast) oficial de Google Play Games "Turret Buster I" que apareix a la part superior de la pantalla just quan es destrueix la desena torreta durant una batalla al nivell 103 de Blocked: Pixel Panzer.


2. Normes de Google Play Console: El límit de 2.000 XP i la restricció de 10.000 passos

Quan configureu assoliments a Google Play Console, heu de dissenyar tenint en compte tres limitacions estrictes de la plataforma:

  • Límit rígid de 2.000 XP: La suma de tots els punts d'assoliment d'un mateix joc no pot superar els 2.000 XP. Cada assoliment individual ha d'atorgar entre 5 i 200 XP, en increments múltiples de 5.
  • Límit de 10.000 passos per a assoliments incrementals: Els assoliments amb comptador acumulatiu admeten un màxim de 10.000 passos (steps) a Play Console.
  • Requisit de Play Games Services V2: Google està retirant l'antic SDK V1. Els jocs moderns per a Android s'han de construir sobre Xamarin.GooglePlayServices.Games.V2 (PlayGamesSdk i PlayGames.GetAchievementsClient).

Disseny d'un catàleg de 79 assoliments a Blocked: Pixel Panzer

Després d'auditar les nostres entitats bàsiques de joc (TurretBlock, FighterJet, EnemyRocket, ColorWheel, HydraRegenerationSkill, Season), vam estructurar 79 assoliments que sumen 1.995 / 2.000 XP repartits en 6 categories fonamentals:

Categoria Assoliments de mostra Tipus Objectiu / Mecànica
Enemy Hunters Jet Hunter I–III, Sky Dominator, Turret Buster I–III, Siege Master Incremental Destrueix 10, 100, 1.000 i 10.000 caces de combat, torretes defensives i coets teledirigits.
Block Destruction & Explosives Pioneer Breaker, Demolition Crew, Crusher Supreme, Pixel Obliterator, Chain Reaction Incremental / Estàndard Trenca d'1.000 a 10.000 blocs i detona 5/25/50 objectius en una sola explosió de dinamita.
ColorWheel & Weapon Mastery Prismatic Pilot, Acid Dissolver, Critical Striker, Power Blaster, Speedy Sprinter, Beam Vaporizer Incremental Fon blocs amb munició d'àcid verd, aconsegueix baixes crítiques negres, dispara trets potents vermells, làsers i míssils teledirigits.
Stage & Boss Progression First Blood, Giant Slayer, Decimator, Speedrunner I–III Incremental / Estàndard Primera baixa enemiga, primera victòria contra un Boss i superar fases en menys de 4 minuts.
Purist Challenges Untouchable, Clean Victory I–III, Purist Gladiator, Mono Specialist Incremental / Estàndard Derrota Bosses i supera fases d'alt nivell sense rebre danys o sense utilitzar habilitats.
Atmosphere, Supplies & Meta Storm Fighter, Retro Connoisseur, Gem Tycoon, Quad Spectrum, Audiophile, Loyal Supporter Incremental / Ocult Destrueix 100 torretes amb pluja, recull monitors CRT i escolta cançons senceres al reproductor de música.

Per a cada assoliment, vam crear icones d'insígnia de píxel-art de 512x512 personalitzades, els marcs de les quals evolucionen des de nivells de bronze i or fins a prismàtics a mesura que augmenta la dificultat:

Blocked: Pixel Panzer Custom Achievement Badges
Sis insígnies d'exemple de 512x512 del nostre catàleg de 79 assoliments: Sky Dominator, Turret Buster III, Pixel Obliterator, Prismatic Pilot IV, Acid Dissolver II i Power Blaster II.

Consell professional (Importació massiva en ZIP): Escriure manualment 79 assoliments a la interfície web de Google Play Console requereix hores. En lloc d'això, utilitzeu la funció "Import achievements" de Play Console empaquetant AchievementsMetadata.csv, AchievementsIconsMappings.csv i les vostres icones .jpg de 512x512 en un únic fitxer .zip per importar tot el catàleg en qüestió de segons.

Taula d'assoliments publicats a Google Play Console
Els nostres assoliments publicats i la distribució d'XP a Google Play Console.


3. Arquitectura neta: IGamesService i AchievementDirector en codi compartit

Blocked: Pixel Panzer és un projecte multiplataforma basat en MonoGame que s'executa tant a Windows PC (Microsoft Store) com a Android (Google Play). Per mantenir el nostre projecte de joc compartit (Blocked.Shared) completament lliure de dependències de l'SDK d'Android, apliquem el Principi d'inversió de dependències (SOLID).

En primer lloc, definim un contracte independent de la plataforma IGamesService a la capa compartida:

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();
    }
}

En lloc de dispersar les comprovacions d'assoliments per CollisionManager, GameplayScreen i Player, centralitzem les 79 regles dins d'una única classe coordinadora, 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; // Safely no-ops on Desktop PC builds

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

            // Turrets destroyed during rainy weather advance "Storm Fighter"
            if (Season.Current == SeasonKind.Rainy)
            {
                gamesService.IncrementAchievement(AchievementIds.StormFighter, 1);
            }
        }

        TrackWeaponKill(gamesService, killingBullet, killedByLaser);
    }
}

4. Enginyeria crítica: Eliminació de la sobrecàrrega de JNI / Binder IPC per prevenir ANR

En un joc arcade ràpid, connectar els activadors d'assoliments directament a l'SDK de Google Play crea un parany de rendiment molt perillós:

Quan un jugador detona un bloc explosiu (ExplosiveBlock) o dispara l'habilitat del raig làser (Laser Beam), es poden destruir entre 20 i 30 blocs i enemics en un sol fotograma (16,6 mil·lisegons). Quan cada destrucció actualitza 5 o 6 nivells incrementals, un sol fotograma pot activar més de 150 crides a IncrementAchievement!

Si envieu 150 crides síncrones de JNI i Binder IPC a Google Play Services al fil d'execució principal del bucle de joc:

  1. Els dispositius Android de gamma d'entrada (telèfons Android Go amb 1–2 GB de RAM) pateixen immediatament caigudes greus de fotogrames.
  2. La taula de referències globals de JNI (GREF) s'omple, desencadenant informes d'ANR (Input dispatching timed out) a Google Play Vitals.

La nostra solució: Processament per lots de 1,5 s en memòria i deduplicació de sessions

La nostra implementació a GooglePlayGamesService.cs aïlla completament el bucle d'actualització de MonoGame de les crides IPC de Google Play:

  1. Deduplicació per sessió (_unlockedInSession):
    Un cop desbloquejat un assoliment estàndard durant una sessió, el seu ID s'afegeix a un HashSet<string>. Els desencadenants repetits en el mateix fotograma o en fotogrames posteriors retornen immediatament a C# amb un cost zero de JNI.
  2. Processament per lots en segon pla d'1,5 segons (_pendingIncrements):
    La crida a IncrementAchievement només incrementa un enter dins d'un Dictionary<string, int> en memòria al fil principal (zero crides JNI). Un treballador de fons mitjançant Task.Run es desperta després d'1,5 segons, pren una instantània dels totals acumulats i els envia a Google Play Services en una sola crida combinada per assoliment.
  3. Gestió de l'error 26502: CLIENT_RECONNECT_REQUIRED i memòria cau fora de línia:
    Si un jugador deixa el joc en segon pla durant hores i hi torna, el testimoni de sessió de Google Play pot caducar i llançar 26502 (CLIENT_RECONNECT_REQUIRED). El nostre servei ho intercepta, intenta un únic inici de sessió silenciós SignIn() en segon pla amb protecció contra sobrecàrrega, i recorre a la memòria cau fora de línia local de GPGS (client.Unlock) si el dispositiu no té connexió—assegurant que no es perdi mai cap assoliment aconseguit pel jugador.
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)
    {
        // ZERO JNI cost on the game loop thread — pure in-memory aggregation!
        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 frame events become 1 combined step call to GPGS
            client.Increment(kvp.Key, kvp.Value);
        }
    }
}

5. Com fan el seguiment dels assoliments els jugadors dins del joc?

Les notificacions emergents durant el combat són excel·lents, però els jugadors també necessiten un lloc clar per explorar les insígnies bloquejades, comprovar el progrés percentual en els nivells incrementals i triar el seu següent objectiu.

Per oferir això de manera neta, vam transformar la nostra pantalla d'estadístiques mòbils en un centre unificat STATS & RANKS. A la part superior de la pantalla, dos botons daurats —LEADERBOARD i ACHIEVEMENTS— bateguen amb una brillantor sinusoïdal suau de 2 segons (Math.Sin). A les versions per a Windows Desktop, aquests botons específics per a mòbils s'amaguen automàticament, mantenint neta la disposició clàssica de STATISTICS.

Quan el jugador toca ACHIEVEMENTS:

  1. S'executa immediatament FlushPendingIncrementsNow() perquè qualsevol progrés dels últims 1,5 segons quedi registrat abans que s'obri la interfície.
  2. GetAchievementsIntent() llança la superposició (overlay) nativa d'assoliments de Google Play Games directament sobre el joc:

Superposició nativa d'assoliments de Google Play Games a Blocked: Pixel Panzer
La superposició nativa d'assoliments de Google Play Games oberta des de la pantalla STATS & RANKS, que mostra la compleció total (2 / 79), objectius recomanats, insígnies desbloquejades (Loyal Supporter, Audiophile) i anells de progrés bloquejats.

Els jugadors poden inspeccionar el seu progrés 2 / 79, consultar recomanacions personalitzades i fer el seguiment dels anells de percentatge incremental sense sortir mai de l'aplicació.


6. Conclusió i els nostres jocs

Quan es construeixen amb un pressupost equilibrat de 2.000 XP i una canalització de processament per lots en segon pla no bloquejant, els assoliments de Google Play Games són una de les maneres més efectives d'afegir profunditat i rejugabilitat a llarg termini a un joc arcade sense sacrificar la taxa de fotogrames.

Si voleu experimentar de primera mà el nostre sistema de progressió de 79 assoliments, les mecàniques de combat amb ColorWheel i les taules de classificació globals —o donar un cop d'ull als nostres altres títols—, els podeu trobar a les botigues següents:

🎮 Els nostres jocs:

📢 Segueix els nostres diaris de desenvolupament i la comunitat:

Segueix-nos per rebre més articles tècnics, vídeos del desenvolupament entre bastidors i actualitzacions dels nostres jocs:


Etiquetes i temes

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




Hiç yorum yok:

Yorum Gönder