📖 PrzeglądOverview

Moduł Achievements umożliwia dodanie systemu osiągnięć i gamifikacji do aplikacji. Wspiera różne typy osiągnięć: jednorazowe, czasowe, streaki i ilościowe.The Achievements module enables adding an achievements and gamification system to your app. Supports various achievement types: one-time, time-based, streaks, and quantitative.

Szybki przykładQuick Example
// Definiowanie osiągnięciaof the achievement
ADict.Achievements.define("first_purchase") {
    title = "Pierwszy zakup!"
    description = "Dokonaj pierwszego zakupu"
    points = 100
    type = AchievementType.ONE_TIME
}

// Odblokowanie
ADict.Achievements.unlock("first_purchase")

// Inkrementacja postępu
ADict.Achievements.increment("articles_read", 1)

📦 TypyTypes osiągnięć

TypType OpisDescription PrzykładExample
ONE_TIME Jednorazowe - odblokuj raz i zostajeOne-time - unlock once and it stays Pierwszy zakup, Zarejestruj kontoFirst purchase, Register account
PROGRESSIVE Ilościowe - wymaga wykonania N czynnościQuantitative - requires performing N actions Przeczytaj 100 artykułówRead 100 articles
STREAK Streak - wymaga ciągłościStreak - requires continuity 7 dni z rzędu7 days in a row
TIMED Czasowe - dostępne tylko przez określony czasTime-limited - available only for a specific time Świąteczna promocjaHoliday promotion

📝 Definiowanie osiągnięćDefining Achievements

define(id: String, config: DefinitionBuilder.() -> Unit)

Zdefiniuj nowe osiągnięcie.Define a new achievement.

Właściwości DefinitionBuilderDefinitionBuilder Properties

WłaściwośćProperty TypType OpisDescription
title String Tytuł osiągnięciaof the achievementAchievement title
description String OpisDescription osiągnięciaof the achievement
icon Int? ID zasobu ikony (@DrawableRes)Icon resource ID (@DrawableRes)
points Int Liczba punktów za osiągnięciePoints for achievement
type AchievementType TypType osiągnięciaof the achievement
targetCount Int Cel dla PROGRESSIVE/STREAKTarget for PROGRESSIVE/STREAK
hidden Boolean Czy ukryte do momentu odblokowaniaWhether hidden until unlocked
expiresAt Long? Timestamp wygaśnięcia (TIMED)Expiration timestamp (TIMED)
availableFrom Long? Timestamp dostępności (TIMED)Availability timestamp (TIMED)
category String? Kategoria osiągnięciaof the achievementAchievement category
tier Int Poziom (1=bronze, 2=silver, 3=gold, 4=platinum)Level (1=bronze, 2=silver, 3=gold, 4=platinum)
prerequisiteIds List<String> Wymagane wcześniejsze osiągnięciaof the achievementRequired prior achievements
Definiowanie różnych typówDefining various types
// Jednorazowe
ADict.Achievements.define("first_purchase") {
    title = "Pierwszy zakup!"
    description = "Dokonaj pierwszego zakupu w aplikacji"
    icon = R.drawable.badge_purchase
    points = 100
    type = AchievementType.ONE_TIME
    category = "shopping"
    tier = 1 // Bronze
}

// Ilościowe (progressive)
ADict.Achievements.define("read_100_articles") {
    title = "Czytelnik"
    description = "Przeczytaj 100 artykułów"
    points = 500
    type = AchievementType.PROGRESSIVE
    targetCount = 100
    category = "reading"
    tier = 3 // Gold
}

// Streak
ADict.Achievements.define("streak_7") {
    title = "Tydzień z rzędu"
    description = "Używaj aplikacji 7 dni z rzędu"
    points = 200
    type = AchievementType.STREAK
    targetCount = 7
    tier = 2 // Silver
}

// Czasowe (np. świąteczne)
val christmasStart = Calendar.getInstance().apply {
    set(2024, Calendar.DECEMBER, 20)
}.timeInMillis
val christmasEnd = Calendar.getInstance().apply {
    set(2024, Calendar.DECEMBER, 27)
}.timeInMillis

ADict.Achievements.define("christmas_shopper") {
    title = "Świąteczny zakupoholik"
    description = "Dokonaj zakupu w okresie świątecznym"
    points = 300
    type = AchievementType.TIMED
    availableFrom = christmasStart
    expiresAt = christmasEnd
    hidden = true
}

// Z wymaganiami
ADict.Achievements.define("master_shopper") {
    title = "Mistrz zakupów"
    description = "Dokonaj 50 zakupów"
    points = 1000
    type = AchievementType.PROGRESSIVE
    targetCount = 50
    prerequisiteIds = listOf("first_purchase") // Wymaga first_purchase
    tier = 4 // Platinum
}

🔓 OdblokowywanieUnlocking

unlock(id: String): Boolean

Odblokuj osiągnięcie (dla ONE_TIME).Unlock achievement (for ONE_TIME).

ZwracaReturns: true jeśli odblokowano, false jeśli już było odblokowane lub nie spełniono wymagań

OdblokowywanieUnlocking osiągnięćUnlocking achievements
// Proste odblokowanie
if (ADict.Achievements.unlock("first_purchase")) {
    showAchievementUnlockedDialog("first_purchase")
}

// W kontekście zakupu
fun onPurchaseCompleted(product: Product) {
    // Sprawdź i odblokuj różne osiągnięciaof the achievement
    ADict.Achievements.unlock("first_purchase")

    if (product.category == "premium") {
        ADict.Achievements.unlock("premium_buyer")
    }

    // Inkrementuj purchase counter
    ADict.Achievements.increment("total_purchases")
}

📈 Postęp i streakiProgress and Streaks

increment(id: String, amount: Int = 1): Boolean

Inkrementuj postęp (dla PROGRESSIVE).Increment progress (for PROGRESSIVE).

ZwracaReturns: true jeśli osiągnięcie zostało odblokowane

setProgress(id: String, count: Int): Boolean

Ustaw postęp bezpośrednio.Set progress directly.

recordStreakDay(id: String): Boolean

Zapisz dzień streaka (dla STREAK).Record streak day (for STREAK).

resetStreak(id: String)

Zresetuj streak.Reset streak.

ZarządzanieManagement postępem
// Progressive - inkrementacja
fun onArticleRead(articleId: String) {
    val unlocked = ADict.Achievements.increment("read_100_articles")
    if (unlocked) {
        showCongratulations("Przeczytałeś 100 artykułów!")
    }

    // Możesz też dodać więcej niż 1
    ADict.Achievements.increment("total_words_read", article.wordCount)
}

// Streak - zapisz dzień
fun onAppOpened() {
    val unlocked = ADict.Achievements.recordStreakDay("streak_7")
    if (unlocked) {
        showCongratulations("7 dni z rzędu!")
    }

    // Sprawdź aktualny streak
    val state = ADict.Achievements.get("streak_7")?.state
    Log.d("Achievements", "Current streak: ${state?.streakDays}")
}

// Ustaw postęp bezpośrednio (np. z serwera)
fun syncProgressFromServer(serverProgress: Int) {
    ADict.Achievements.setProgress("read_100_articles", serverProgress)
}

🔍 Pobieranie osiągnięćFetching Achievements

getAll(includeHidden: Boolean = false): List<Achievement>

Pobierz wszystkie osiągnięciaof the achievement.

getUnlocked(): List<Achievement>

Pobierz odblokowane osiągnięciaof the achievement.

getLocked(includeHidden: Boolean = false): List<Achievement>

Pobierz zablokowane osiągnięciaof the achievement.

getByCategory(category: String): List<Achievement>

Pobierz osiągnięciaof the achievement w kategorii.

get(id: String): Achievement?

Pobierz pojedyncze osiągnięcie.Get a single achievement.

isUnlocked(id: String): Boolean

Sprawdź czy osiągnięcie jest odblokowane.Check if achievement is unlocked.

getProgress(id: String): Float

Pobierz postęp (0.0 - 1.0).Get progress (0.0 - 1.0).

getTotalPoints(): Int

Pobierz sumę punktów za odblokowane osiągnięciaof the achievement.

getStats(): Stats

Pobierz statystyki osiągnięć.Get achievement statistics.

Pobieranie i wyświetlanieFetching and displaying
// Lista wszystkich osiągnięć
val allAchievements = ADict.Achievements.getAll()
allAchievements.forEach { achievement ->
    println("${achievement.title}: ${if (achievement.isUnlocked) "✅" else "🔒"}")
    println("  Progress: ${(achievement.progress * 100).toInt()}%")
    println("  Points: ${achievement.points}")
}

// Odblokowane
val unlockedCount = ADict.Achievements.getUnlocked().size

// Statystyki
val stats = ADict.Achievements.getStats()
println("Odblokowane: ${stats.unlocked}/${stats.total}")
println("Punkty: ${stats.totalPoints}")
println("Completion: ${(stats.completionRate * 100).toInt()}%")

// W RecyclerView
class AchievementsAdapter : RecyclerView.Adapter<...>() {
    private var achievements = listOf()

    fun setAchievements(list: List) {
        achievements = list.sortedWith(
            compareByDescending { it.isUnlocked }
                .thenByDescending { it.definition.tier }
        )
        notifyDataSetChanged()
    }
}

// Obserwacja zmian (Flow)
lifecycleScope.launch {
    ADict.Achievements.achievements.collect { achievementsMap ->
        updateUI(achievementsMap)
    }
}

🔔 CallbackiCallbacks

onUnlock(callback: (Achievement) -> Unit)

Callback wywoływany przy odblokowaniu osiągnięciaof the achievement.

Callback na odblokowanieUnlock callback
// Globalny callback
ADict.Achievements.onUnlock { achievement ->
    // Pokaż UI
    showAchievementToast(achievement)

    // Analytics
    ADict.Analytics.log("achievement_unlocked", mapOf(
        "achievement_id" to achievement.id,
        "achievement_name" to achievement.title,
        "points" to achievement.points,
        "tier" to achievement.definition.tier
    ))

    // Może nagroda?
    if (achievement.definition.tier >= 3) {
        grantBonusCoins(achievement.points)
    }
}

fun showAchievementToast(achievement: Achievement) {
    Toast.makeText(
        context,
        "🏆 ${achievement.title} (+${achievement.points} pts)",
        Toast.LENGTH_LONG
    ).show()
}

💡 PrzykładyExamples praktycznepractical

Pełna konfiguracjaFull Configuration dla gry

System osiągnięćAchievements system w grze
class AchievementsSetup {
    fun setup() {
        // === ONBOARDING ===
        ADict.Achievements.define("first_level") {
            title = "Początek przygody"
            description = "Ukończ pierwszy poziom"
            points = 10
            type = AchievementType.ONE_TIME
            category = "onboarding"
            tier = 1
        }

        ADict.Achievements.define("tutorial_complete") {
            title = "Gotowy do gry"
            description = "Ukończ tutorial"
            points = 25
            type = AchievementType.ONE_TIME
            category = "onboarding"
            tier = 1
        }

        // === POSTĘP ===
        ADict.Achievements.define("levels_10") {
            title = "Podróżnik"
            description = "Ukończ 10 poziomów"
            points = 100
            type = AchievementType.PROGRESSIVE
            targetCount = 10
            category = "progress"
            tier = 2
        }

        ADict.Achievements.define("levels_50") {
            title = "Weteran"
            description = "Ukończ 50 poziomów"
            points = 500
            type = AchievementType.PROGRESSIVE
            targetCount = 50
            category = "progress"
            tier = 3
            prerequisiteIds = listOf("levels_10")
        }

        ADict.Achievements.define("levels_100") {
            title = "Legenda"
            description = "Ukończ 100 poziomów"
            points = 1000
            type = AchievementType.PROGRESSIVE
            targetCount = 100
            category = "progress"
            tier = 4
            prerequisiteIds = listOf("levels_50")
        }

        // === STREAK ===
        ADict.Achievements.define("daily_3") {
            title = "Regularny gracz"
            description = "Graj 3 dni z rzędu"
            points = 50
            type = AchievementType.STREAK
            targetCount = 3
            category = "engagement"
            tier = 1
        }

        ADict.Achievements.define("daily_7") {
            title = "Oddany gracz"
            description = "Graj 7 dni z rzędu"
            points = 150
            type = AchievementType.STREAK
            targetCount = 7
            category = "engagement"
            tier = 2
        }

        ADict.Achievements.define("daily_30") {
            title = "Uzależniony"
            description = "Graj 30 dni z rzędu"
            points = 500
            type = AchievementType.STREAK
            targetCount = 30
            category = "engagement"
            tier = 4
        }

        // === KOLEKCJONOWANIE ===
        ADict.Achievements.define("collect_all_characters") {
            title = "Kolekcjoner"
            description = "Odblokuj wszystkie postacie"
            points = 300
            type = AchievementType.ONE_TIME
            category = "collection"
            tier = 3
            hidden = true
        }

        // === SOCIAL ===
        ADict.Achievements.define("first_share") {
            title = "Społecznik"
            description = "Udostępnij wynik znajomym"
            points = 30
            type = AchievementType.ONE_TIME
            category = "social"
            tier = 1
        }

        // === SKILL ===
        ADict.Achievements.define("perfect_level") {
            title = "Perfekcja"
            description = "Ukończ poziom z 3 gwiazdkami"
            points = 50
            type = AchievementType.ONE_TIME
            category = "skill"
            tier = 2
        }

        ADict.Achievements.define("no_damage") {
            title = "Nietykalny"
            description = "Ukończ poziom bez obrażeń"
            points = 100
            type = AchievementType.ONE_TIME
            category = "skill"
            tier = 3
            hidden = true
        }

        // Callback
        ADict.Achievements.onUnlock { achievement ->
            GameManager.showAchievementPopup(achievement)
            GameManager.addCoins(achievement.points)
        }
    }
}

// Użycie w grze
class GameManager {
    fun onLevelComplete(level: Level, stars: Int, damage: Int) {
        // Podstawowe
        ADict.Achievements.unlock("first_level")
        ADict.Achievements.increment("levels_10")
        ADict.Achievements.increment("levels_50")
        ADict.Achievements.increment("levels_100")

        // Skill-based
        if (stars == 3) {
            ADict.Achievements.unlock("perfect_level")
        }
        if (damage == 0) {
            ADict.Achievements.unlock("no_damage")
        }
    }

    fun onDailyLogin() {
        ADict.Achievements.recordStreakDay("daily_3")
        ADict.Achievements.recordStreakDay("daily_7")
        ADict.Achievements.recordStreakDay("daily_30")
    }

    fun onShare() {
        ADict.Achievements.unlock("first_share")
    }

    fun onAllCharactersUnlocked() {
        ADict.Achievements.unlock("collect_all_characters")
    }
}

📚 Klasy danychData Classes

data class AchievementDefinition

  • idString
  • titleString
  • descriptionString
  • iconInt?
  • pointsInt
  • typeAchievementType
  • targetCountInt
  • hiddenBoolean
  • expiresAtLong?
  • availableFromLong?
  • categoryString?
  • tierInt
  • prerequisiteIdsList<String>

data class AchievementState

  • idString
  • unlockedBoolean
  • unlockedAtLong?
  • currentCountInt
  • streakDaysInt
  • lastStreakDateString?
  • progressFloat

data class Stats

  • totalIntŁączna liczba osiągnięćTotal number of achievements
  • unlockedIntLiczba odblokowanychNumber of unlocked
  • totalPointsIntSuma punktówTotal points
  • completionRateFloatProcent ukończenia (0-1)Completion percentage (0-1)