-
Notifications
You must be signed in to change notification settings - Fork 1
Achievement Status Maintenance and Updates
The status of game achievements is an important part of the achievement system. The display of the achievement interface and the prompts for achievement achievement depend on a long-term maintenance achievement status. In general stand-alone games, the maintenance of achievement system information often needs to be reflected in a mechanism similar to archives. Unlike ordinary game archives, achievement archives are often created when the game is run for the first time, and are updated every time the player plays.
I also used this idea for this, I added AchievementService in ServiceLocater. code show as below
public class AchievementService implements Disposable {
private static final Logger logger = LoggerFactory.getLogger(AchievementService.class);
private static final String ROOT_DIR = "DECO2800Game";
private static final String ACHE_FILE = "achievement_archive.json";
private Map<String, AchievementStatus> achievementStatusMap;
public Map<String, AchievementStatus> getAchievementStatusMap() {
return achievementStatusMap;
}
public AchievementService() {
String path = ROOT_DIR + File.separator + ACHE_FILE;
AchievementArchive achievementArchive = FileLoader.readClass(AchievementArchive.class, path, FileLoader.Location.EXTERNAL);
/* If the local achievement archive does not exist,
create initial state blank achievement information
*/
if (achievementArchive == null) {
achievementStatusMap = new LinkedHashMap<>();
List<AchievementPropertyConfig> achievements = FileLoader.readClass(AchievementConfigs.class, "configs/achievements.json").achievements;
achievements.stream().forEach(config -> {
String name = config.name;
if (config.type.equals(AchievementPropertyConfig.TYPE_COLLECTION)) {
CollectionAchievementStatus status = new CollectionAchievementStatus(
name
, false
, config.condition.item);
achievementStatusMap.put(name, status);
}
if (config.type.equals(AchievementPropertyConfig.TYPE_PLOT)) {
// TODO Add logic related to plot achievements
}
});
} else {
this.achievementStatusMap = achievementArchive.achievementStatusMap;
logger.info("Successfully write achievement.json");
}
}
public void wirteToLocal() {
String path = ROOT_DIR + File.separator + ACHE_FILE;
if (achievementStatusMap != null) {
FileLoader.writeClass(new AchievementArchive(achievementStatusMap), path, FileLoader.Location.EXTERNAL);
}
logger.info("Successfully write achievement.json");
}
@Override
public void dispose() {
wirteToLocal();
}
}
We know that before entering a new screen, it is often accompanied by the loading of ServiceLocater, and closing a screen is also accompanied by the dispose operation of services. I added the code to save the achievement information to the player's computer in the dispose() method of Achievement. At the same time, in the construction method of AchievementService, the achievement information will be read from the file and restored to the game.
In order to achieve the update of the achievement status, we use the AchievementUpdater to trigger the achievement update operation every time there is contact with the pickup item.
public class AchievementsUpdater extends Component {
private HitboxComponent hitboxComponent;
@Override
public void create() {
hitboxComponent = entity.getComponent(HitboxComponent.class);
entity.getEvents().addListener("collisionStart", this::onCollisionStart);
}
private void onCollisionStart(Fixture me, Fixture other) {
if (hitboxComponent.getFixture() != me) {
// Not triggered by hitbox, ignore
return;
}
Entity player = ((BodyUserData) other.getBody().getUserData()).entity;
AchievementStatsComponent achvStatsComponent = player.getComponent(AchievementStatsComponent.class);
if (achvStatsComponent == null) {
return;
}
if (isConsumableItem(entity)) {
achvStatsComponent.updateConsumableCollectionAchievement(entity);
}
if (isClueItem(entity)) {
achvStatsComponent.updateClueCollectionAchievement(entity);
}
}
public boolean isConsumableItem(Entity entity) {
return entity.getComponent(ConsumeableItemComponent.class) != null;
}
public boolean isClueItem(Entity entity) {
return entity.getComponent(ConsumeableItemComponent.class) == null
&& entity.getComponent(AddToInventoryComponent.class) != null;
}
public boolean isPickUp(Entity entity) {
return isClueItem(entity) || isConsumableItem(entity);
}
}
The main content of the above code is that each time a collision event of picking up a prop occurs, the type of the prop will be judged. If there is an achievement related to the item, go to update the achievement status in AchievementStatsComponet.
When the AchievementStatsComponent is initialized, it will read the basic information of achievements from the configuration file. At present, we have added 6 achievements in achievements.json. After testing, the information of these six achievements can be successfully obtained.
@Test
void shouldLoadInitializationData() {
AchievementStatsComponent achievementStats = new AchievementStatsComponent();
assertEquals(6, achievementStats.getNumOfAchievements());
}
The following is a test of reading and saving the achievement archive. After the player exits the game interface, the achievement archive will be saved to the player's computer, so that even if the player re-runs the game, the achievement data will not be lost.
@Test
void shouldWriteFile() {
AchievementService achievementService = new AchievementService();
achievementService.wirteToLocal();
AchievementArchive achievementArchive = FileLoader.readClass(AchievementArchive.class, "DECO2800Game/achievement_archive.json", FileLoader.Location.EXTERNAL);
assertNotEquals(achievementArchive, null);
}
- Uniform Pixel Grid Resolution
- Storyline
- Instruction
- NPC info
- NPC Communication Script
- Inventory-System-and-Consumables
- Storyline User Test
- Traitor Clues
- Game Characters
- Player Profile User Test
- Player Eviction Menu Sprint1: User survey (Team 7)
- Player Eviction Menu Sprint2: User survey (Team 7)
- Sprint3 - Win/lose Condition: User survey (Team 7)
- Sprint4 - Polishing-tasks: User survey (Team 7)
- Transition Animation/Special Effects/Sound Effects: Feature Overviews
- Transition Animation and Effects: Design Process & Guideline
- Sprint 4 User Testing
- Transition Animation & Effect: Code Guideline-Sprint4
- Sound effect when players complete npc tasks and hover over npc cards
- Fixing the clue bug
- Music Test
- Player Eviction Menu: Design Process & Guideline
- Player Eviction Menu (Feature Overviews)
- Player Eviction Menu: Code Guideline - Sprint1
- Sprint 1 User Testing
- Detailed Eviction Card: Design Process & Guideline
- Detailed Eviction Card: Feature Overviews
- Sprint 2 User Testing
- Player Eviction Menu: Code Guideline - Sprint2
- Sprint 2 Inventory System and Consumables Items User Testing
- Sprint 2 Inventory System and Consumables Items Functionality
- NPC interaction testing plan sprint3
- NPC interaction testing results sprint3
- NPC Dialogue Scripts
- Code Guideline
- Win/lose Condition: Design Process & Guideline
- Win/lose Condition: Feature Overviews
- Sprint 3 User Testing
- Win/lose condition: Code Guideline - Sprint3
- Enemy List
- User Testing 1: Enemy Image Filter
- User Testing 2: Enemy Animation and AI
- User Testing 3: Basic Attack