achievements service - UQcsse3200/2026-studio-4 GitHub Wiki

AchievementService

Purpose

AchievementService holds every achievement for the current run and passes game events to them. It is registered once in ServiceLocator, so any system can report an event without holding a reference to a manager, and nothing needs to re-subscribe when rooms change.

Setup

MainGameScreen builds it from configs/achievements.json and registers it:

java
ServiceLocator.registerAchievementService(createAchievementService());

Fetch it anywhere with:

java
ServiceLocator.getAchievementService()

It is created before RoomManager, because RoomManager's constructor subscribes to its events. Don't construct your own.

API

Method | Description -- | -- register(Achievement) | Adds an achievement to the list update(AchievementContext) | Sends an event to every achievement and announces any that unlock getEvents() | The service's EventHandler, for listening to "achievementUnlocked" getAchievements() | All achievements, used by the inventory page

Fields you don't set stay null or false, and every achievement ignores fields it doesn't use. Report one kind of event per context.

What happens on update

For each achievement, the service calls achievement.update(ctx). That returns true only on the call that unlocks it. Achievements that are already unlocked return false without evaluating their condition, so an unlock is announced exactly once. The service then:

  1. Logs Achievement unlocked: <name>.
  2. Triggers "achievementUnlocked" with the achievement's name as a String.

Listening for unlocks

java
ServiceLocator.getAchievementService()
    .getEvents()
    .addListener("achievementUnlocked", this::onUnlocked);

RoomManager is the existing listener. It passes the name to the current room's GameAreaDisplay.showAchievement(name), which queues the toast.

Testing

  • Achievement logic: test through AchievementsFactory.build(config) and achievement.update(ctx) with no service involved (see AchievementsFactoryTest).
  • Code that reports events: the code calls ServiceLocator.getAchievementService(), so tests that build players, enemies or inventories need a service available. Register one in setUp(), or make ServiceLocator default to an empty service.
⚠️ **GitHub.com Fallback** ⚠️