Skip to content

Achievement Status Maintenance and Updates

wsxmr1234 edited this page Sep 14, 2022 · 2 revisions

Achievement Archive

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.

Update achievements

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.

Test

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

Table of Contents

Home

Game Design

User survey

Sprint 4

Eviction Menu and Win/lose Logic: Polishing tasks (Team 7)

Button Sounds and Ending Menu improve (Team 3)

Sound effect and Fixing the clue bug (Team 6)

Improvement of Enemy and Attack (Team 1)

Add Features When The Player Get Attacked and Overall UI Improvement (Team 8)

Sprint 1

Achievement System (Team 2)

Player Eviction Menu (Team 7)

Countdown Clock (Team 4)

Music (Team3)

Map (Team6)

Sprint 2

Player Eviction Menu (Team 7)

Character Design & Animation (Team 1)

Music (Team 3)

Inventory System and Consumables Items (Team 8)

Scenario design

Achievement System(team 2)

Storyline (Team 5)

Countdown Clock (Team 4)

Sprint 3

Ending Menu (Team 3)

NPC interaction (Team 2)

Win/lose Condition (Based on Eviction Menu) (Team 7)

Player Profile (Team 4)

Game Logo (Team 8)

Clue storage (Team 6)

Enemy Design and Attack (Team 1)

Scenario design for village(Team5)

Game design
Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Game Screens and Areas

Terrain

Concurrency & Threading

Settings

Troubleshooting

MacOS Setup Guide

Clone this wiki locally