Adding Achievements - UQdeco2800/2021-ext-studio-2 GitHub Wiki
Note: In Sprint 4, the Achievements System had undergone a major refactor, so the process of adding achievements has changed as well. This is the updated guide.
Description
This is a guide for future maintainers/contributors of this repository for adding new achievements in the game.
We'll be using GameBreaker
achievement as an example here, where the user has to survive for 5, 8 and 10 minutes respectively, with full health in order to unlock its bronze, silver and gold variants.
Prerequisites: Make sure the achievement cards and associated trophies have been designed and committed to the repository. The assets go in this folder. Notice the naming format. This has to be consistent, in camelcase. Make sure that your assets are the same size and design as the ones here.
- Trophies:
gameBreakerGoldTrophy.png
- Card:
gameBreakerGold.png
The same convention has to be followed with the bronze and silver variants.
Steps
Game Breaker
achievement config additons
Step 1: Append the achievements.json
file with desired details following the JSON syntax. The config can be found here. For the Game Breaker achievement, we have:
{
"propertyList": {
"class": "java.util.LinkedHashMap",
// ...
"health": {
"operation": "<=",
"defaultValue": 100 // This is discrete, but health may be greater than 100,
}, // and can go up to 170 if prop store items are bought.
// ...
"time": {
"operation": "<=", // This is a continuous variable, hence '<=' minute checks should be valid operations
"defaultValue": 0
}
},
"achievements": [
// ...
{
"name": "Game Breaker",
"type": "BRONZE",
"iconPath": "images/achievements/gameBreakerBronze.png",
"message": "You've survived for 5 minutes with full health!",
"bonus": 15,
"condition": {
"time": 5,
"health": 100
}
},
{
"name": "Game Breaker",
"type": "SILVER",
"iconPath": "images/achievements/gameBreakerSilver.png",
"message": "You've survived for 8 minutes with full health!",
"bonus": 20,
"condition": {
"time": 8,
"health": 100
}
},
{
"name": "Game Breaker",
"type": "GOLD",
"iconPath": "images/achievements/gameBreakerGold.png",
"message": "You've survived for 10 minutes with full health!",
"bonus": 25,
"condition": {
"time": 10,
"health": 100
}
},
// ...
]
}
time
and health
variables
Step 2: Tracking the in game The current values of time
and health
need to be known so that the achievement can be validated, and then unlocked if its valid.
Time can be tracked directly from the AchievementStatsComponent
since its provided through a method called ServiceLocator.getTimeSource()
. Now, Go to AchievementStatsComponent.java
, which can be found here.
time
Step 2.1: Tracking @Override
public void update() {
// ...
setTime(ServiceLocator.getTimeSource().getTime());
// ...
}
Set the time
: The updateConditionsAndRevalidate
method maintains a track of the current time and calls functions internally to validate the achievement and unlock it if need be. Whenever a property is updated, this has to be called.
/**
* Maintains the in game time
*
* @param time current game time
*/
public void setTime(long time) {
updateConditionsAndRevalidate("time", time);
}
health
Step 2.2: Tracking Tracking the current health
of the player is slightly more tricky. Go to the AchievementsHelper.java
class which acts as a global event listener for the achievements system, used for keeping a 'track' of game variables that cannot be easily accessed, and are within different entities. The AchievementsHelper
file can be found here.
public class AchievementsHelper {
// ...
public static final String EVENT_HEALTH = "healthEvent";
// ...
// ...
/**
* Tracks changes in the health property of the player
* and triggers an event for the achievements system
*
* @param health the player's health
*/
public void trackHealthEvent(int health) {
handler.trigger(EVENT_HEALTH, health);
}
// ...
}
Now, we can listen to this event in AchievementStatsComponent.java
class.
@Override
public void create() {
// ...
AchievementsHelper.getInstance().getEvents()
.addListener(AchievementsHelper.EVENT_HEALTH, this::setHealth);
// ...
}
// ...
/**
* Maintains the current health of player
*
* @param health player's changed health
*/
public void setHealth(int health) {
updateConditionsAndRevalidate("health", health);
}
// ...
Congratulations! You've successfully added new achievements into the game. These will be dynamically loaded and displayed when conditions are applicable across all screens, and all features where achievements are being used.
Extra Notes
In achievementsStatsComponent.java
add additional conditions in the isValid()
method. If you've added new properties, you'll need to setup a set
method for your property for testing. Tests go in AchievementStatsComponentTest.java
.
Refer the following UML class diagram to have an idea about the affected classes when appending properties.