Skip to content

feat: add achievements display menu and integrate into menus (#307)#309

Open
Keerthi421 wants to merge 1 commit intojvondermarck:mainfrom
Keerthi421:main
Open

feat: add achievements display menu and integrate into menus (#307)#309
Keerthi421 wants to merge 1 commit intojvondermarck:mainfrom
Keerthi421:main

Conversation

@Keerthi421
Copy link
Contributor

✅ PR Checklist

  • [ x] My PR title follows the format: [Type]: clear description of change
  • [ x] I used the correct type: Feature, Fix, Refactor, Docs, Test, Chore
  • [ x] I reviewed my code and removed unnecessary debug logs or comments.
  • [ x] I tested my changes and verified they work as expected.
  • [ x] I ran the project to confirm it compiles and runs correctly.
  • [ x] I read the Code of Conduct and the Contribution Guidelines.

📝 What does this PR do?

This PR implements a centralized Achievements system with full UI integration, allowing players to track milestones and rewards from both the main menu and during gameplay.

Key changes:

-> UI Implementation
Created AchievementsMenu.java as a scrollable SubScene based on FXGLMenu
Dynamically displays all achievements with status and rewards

-> System Integration

Added navigation entry points .

-> Manager Enhancement

Extended AchievementManager to:
      Centralize achievement registration
      Provide structured data access for the UI layer

🔗 Related Issue

  • [x ] This PR fixes/closes: #<307>

@vercel
Copy link

vercel bot commented Jan 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Review Updated (UTC)
dinosaur-exploder Ignored Ignored Preview Jan 26, 2026 3:06pm

allAchievements.add(new KillCountAchievement("ach_kill_10_name", "ach_kill_10_desc", 10, 50));
allAchievements.add(new KillCountAchievement("ach_kill_20_name", "ach_kill_20_desc", 20, 100));
allAchievements.add(new KillCountAchievement("ach_kill_50_name", "ach_kill_50_desc", 50, 250));
allAchievements.add(new KillCountAchievement("ach_kill_100_name", "ach_kill_100_desc", 100, 500));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
allAchievements.add(new KillCountAchievement("ach_kill_100_name", "ach_kill_100_desc", 100, 500));
allAchievements.add(
new KillCountAchievement("ach_kill_100_name", "ach_kill_100_desc", 100, 500));

private boolean completed = false;

public KillCountAchievement(int targetKills, int rewardCoins) {
public KillCountAchievement(String nameKey, String descriptionKey, int targetKills, int rewardCoins) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
public KillCountAchievement(String nameKey, String descriptionKey, int targetKills, int rewardCoins) {
public KillCountAchievement(
String nameKey, String descriptionKey, int targetKills, int rewardCoins) {


public boolean isCompleted() {
return completed;
return com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance().getTranslation(descriptionKey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
return com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance().getTranslation(descriptionKey)
return com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance()
.getTranslation(descriptionKey)


public void onComplete() {
FXGL.getNotificationService().pushNotification("Achievement unlocked: " + getDescription());
String achievementName = com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance().getTranslation(nameKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
String achievementName = com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance().getTranslation(nameKey);
String achievementName =
com.dinosaur.dinosaurexploder.utils.LanguageManager.getInstance().getTranslation(nameKey);

import com.dinosaur.dinosaurexploder.achievements.Achievement;
import com.dinosaur.dinosaurexploder.achievements.AchievementManager;
import com.dinosaur.dinosaurexploder.achievements.KillCountAchievement;
import com.dinosaur.dinosaurexploder.constants.GameConstants;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
import com.dinosaur.dinosaurexploder.constants.GameConstants;

Comment on lines +94 to +103
private VBox createAchievementsList() {
VBox list = new VBox(15);
list.setPadding(new Insets(10));
list.setAlignment(Pos.TOP_CENTER);
list.setStyle("-fx-background-color: transparent;");

List<Achievement> achievements = achievementManager.getAllAchievements();
for (Achievement achievement : achievements) {
list.getChildren().add(createAchievementBox(achievement));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
private VBox createAchievementsList() {
VBox list = new VBox(15);
list.setPadding(new Insets(10));
list.setAlignment(Pos.TOP_CENTER);
list.setStyle("-fx-background-color: transparent;");
List<Achievement> achievements = achievementManager.getAllAchievements();
for (Achievement achievement : achievements) {
list.getChildren().add(createAchievementBox(achievement));
}
return list;
}

list.getChildren().add(createAchievementBox(achievement));
}

return list;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
return list;
private VBox createAchievementBox(Achievement achievement) {
String name = languageManager.getTranslation(achievement.getNameKey());
String description = "";
if (achievement instanceof KillCountAchievement) {
description = ((KillCountAchievement) achievement).getDescription();
} else {
description = languageManager.getTranslation(achievement.getDescriptionKey());

Comment on lines +108 to +143
private VBox createAchievementBox(Achievement achievement) {
String name = languageManager.getTranslation(achievement.getNameKey());
String description = "";
if (achievement instanceof KillCountAchievement) {
description = ((KillCountAchievement) achievement).getDescription();
} else {
description = languageManager.getTranslation(achievement.getDescriptionKey());
}

Label nameLabel = new Label(name);
nameLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 14px; -fx-text-fill: #00FF00; -fx-font-weight: bold;");

Text descText = getUIFactoryService().newText(description, Color.WHITE, 12);
descText.setWrappingWidth(400);

HBox statusBox = new HBox(10);
statusBox.setAlignment(Pos.CENTER_LEFT);

boolean isCompleted = achievement.isCompleted();
Label statusLabel = new Label(isCompleted ? languageManager.getTranslation("unlocked").toUpperCase() : languageManager.getTranslation("locked").toUpperCase());
statusLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: " + (isCompleted ? "#00FF00" : "#FF6666") + ";");

Label rewardLabel = new Label(languageManager.getTranslation("reward") + ": " + achievement.getRewardCoins() + " " + languageManager.getTranslation("coin"));
rewardLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: #FFFF00;");

VBox box = new VBox(8, nameLabel, descText, new HBox(20, statusLabel, rewardLabel));
box.setPadding(new Insets(15));
box.setStyle(
"-fx-background-color: rgba(0, 0, 0, 0.6);"
+ "-fx-background-radius: 8;"
+ "-fx-border-color: " + (isCompleted ? "rgba(0, 255, 0, 0.5)" : "rgba(255, 255, 255, 0.2)") + ";"
+ "-fx-border-width: 1;"
+ "-fx-border-radius: 8;");

return box;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
private VBox createAchievementBox(Achievement achievement) {
String name = languageManager.getTranslation(achievement.getNameKey());
String description = "";
if (achievement instanceof KillCountAchievement) {
description = ((KillCountAchievement) achievement).getDescription();
} else {
description = languageManager.getTranslation(achievement.getDescriptionKey());
}
Label nameLabel = new Label(name);
nameLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 14px; -fx-text-fill: #00FF00; -fx-font-weight: bold;");
Text descText = getUIFactoryService().newText(description, Color.WHITE, 12);
descText.setWrappingWidth(400);
HBox statusBox = new HBox(10);
statusBox.setAlignment(Pos.CENTER_LEFT);
boolean isCompleted = achievement.isCompleted();
Label statusLabel = new Label(isCompleted ? languageManager.getTranslation("unlocked").toUpperCase() : languageManager.getTranslation("locked").toUpperCase());
statusLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: " + (isCompleted ? "#00FF00" : "#FF6666") + ";");
Label rewardLabel = new Label(languageManager.getTranslation("reward") + ": " + achievement.getRewardCoins() + " " + languageManager.getTranslation("coin"));
rewardLabel.setStyle("-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: #FFFF00;");
VBox box = new VBox(8, nameLabel, descText, new HBox(20, statusLabel, rewardLabel));
box.setPadding(new Insets(15));
box.setStyle(
"-fx-background-color: rgba(0, 0, 0, 0.6);"
+ "-fx-background-radius: 8;"
+ "-fx-border-color: " + (isCompleted ? "rgba(0, 255, 0, 0.5)" : "rgba(255, 255, 255, 0.2)") + ";"
+ "-fx-border-width: 1;"
+ "-fx-border-radius: 8;");
return box;
}
Label nameLabel = new Label(name);
nameLabel.setStyle(
"-fx-font-family: 'Public Pixel'; -fx-font-size: 14px; -fx-text-fill: #00FF00; -fx-font-weight: bold;");
Text descText = getUIFactoryService().newText(description, Color.WHITE, 12);
descText.setWrappingWidth(400);
HBox statusBox = new HBox(10);
statusBox.setAlignment(Pos.CENTER_LEFT);
boolean isCompleted = achievement.isCompleted();
Label statusLabel =
new Label(
isCompleted
? languageManager.getTranslation("unlocked").toUpperCase()
: languageManager.getTranslation("locked").toUpperCase());
statusLabel.setStyle(
"-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: "
+ (isCompleted ? "#00FF00" : "#FF6666")
+ ";");
Label rewardLabel =
new Label(
languageManager.getTranslation("reward")
+ ": "
+ achievement.getRewardCoins()
+ " "
+ languageManager.getTranslation("coin"));
rewardLabel.setStyle(
"-fx-font-family: 'Public Pixel'; -fx-font-size: 10px; -fx-text-fill: #FFFF00;");
VBox box = new VBox(8, nameLabel, descText, new HBox(20, statusLabel, rewardLabel));
box.setPadding(new Insets(15));
box.setStyle(
"-fx-background-color: rgba(0, 0, 0, 0.6);"
+ "-fx-background-radius: 8;"
+ "-fx-border-color: "
+ (isCompleted ? "rgba(0, 255, 0, 0.5)" : "rgba(255, 255, 255, 0.2)")
+ ";"
+ "-fx-border-width: 1;"
+ "-fx-border-radius: 8;");
return box;
}


achievementsButton.setMinSize(140, 60);
achievementsButton.setTranslateY(470);
achievementsButton.setOnAction(event -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
achievementsButton.setOnAction(event -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));
achievementsButton.setOnAction(
event -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));


LanguageManager languageManager = LanguageManager.getInstance();
PauseButton btnBack = new PauseButton(languageManager.getTranslation("back"), this::fireResume);
PauseButton btnAchievements = new PauseButton(languageManager.getTranslation("achievements"), () -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💄Spotless - Format] reported by reviewdog 🐶

Suggested change
PauseButton btnAchievements = new PauseButton(languageManager.getTranslation("achievements"), () -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));
PauseButton btnAchievements =
new PauseButton(
languageManager.getTranslation("achievements"),
() -> FXGL.getSceneService().pushSubScene(new AchievementsMenu()));

@github-actions
Copy link
Contributor

🎨 Code Formatting Issues

badge

5 Java file(s) need formatting.

💡 Quick fix

Click the suggestions below:

  1. Go to "Files changed" tab
  2. Click ✅ Commit suggestion on each [💄 Spotless] comment

Or run locally:

mvn spotless:apply
git add -A && git commit -m "style: apply Spotless" && git push
📚 More options

Auto-format in your IDE:

Style guide: Google Java Style Guide


🤖 The DinoBot Team 🦖

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

@github-actions
Copy link
Contributor

❌ Build Failed

badge-fail

Thanks for your contribution to this open-source project! ❤️

Unfortunately the build for this pull request has failed:

  • 🚩 Workflow Run: View Logs
  • 🔖 Commit: 89d6e9ee8d0538ddbc7aad0bc42efffe0dde16f8

Tip

Please check the logs and fix any issues before re-running the workflow.

Good luck with your debugging! 🐛 (or should I say dino-bugging? 🦖)

The DinoBot Team 🦖

Copy link
Owner

@jvondermarck jvondermarck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please verify these elements:

@jvondermarck jvondermarck added status: in-review PR currently in review status: pending-request-changes Request changes from the contributor status: invalid This doesn't seem right labels Jan 27, 2026
@jvondermarck jvondermarck added the status: pending-conflict-resolution Wait the author to resolve the conflicts before merging label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: in-review PR currently in review status: invalid This doesn't seem right status: pending-conflict-resolution Wait the author to resolve the conflicts before merging status: pending-request-changes Request changes from the contributor

Projects

Development

Successfully merging this pull request may close these issues.

2 participants