Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f05fdd2
实现完整的成就系统Book界面功能 - 在暂停界面添加玩家昵称和头像显示 - 从主菜单移除Achievement按钮,整合到Book中 -…
ozozozo686 Oct 16, 2025
e0d8094
合并远程更改并解决冲突 - 保留Achievement Book功能并兼容UPGRADES屏幕
ozozozo686 Oct 16, 2025
50cdd3a
improve the game defeat time the ranking will show the mark
ozozozo686 Oct 21, 2025
c4f8736
Merge origin/main into team-7-sprint-3: Integrate both ACHIEVEMENT_BO…
Alex118099 Oct 21, 2025
781a727
improve of the achievement ui
ozozozo686 Oct 21, 2025
065a20b
fix name system
Alex118099 Oct 21, 2025
b6525ab
add new achievements book
0arthurr Oct 21, 2025
e4a5166
Merge branch 'team-7-sprint-3' of https://github.com/UQcsse3200/2025-…
0arthurr Oct 21, 2025
9a4810b
name system
Alex118099 Oct 21, 2025
332bc39
improve of the achievement
ozozozo686 Oct 21, 2025
23d3865
Merge origin/main into team-7-sprint-3
Alex118099 Oct 22, 2025
f76f58e
fixed
Alex118099 Oct 22, 2025
cdf65c2
modify name system background
Alex118099 Oct 22, 2025
11c4f1f
improve ranking ui
Alex118099 Oct 22, 2025
7500e83
fix achievement system
0arthurr Oct 22, 2025
9fb10df
Add comprehensive test suite for VictoryScreen with 25 test cases
ozozozo686 Oct 22, 2025
39e428c
test for achievement show
ozozozo686 Oct 22, 2025
8b3bfe2
test for achievement show
ozozozo686 Oct 22, 2025
4b61d51
replace profile images
0arthurr Oct 23, 2025
736c879
replace profile images
0arthurr Oct 23, 2025
f310b93
test for achievement show
ozozozo686 Oct 23, 2025
064e631
improve of achievement ui
ozozozo686 Oct 23, 2025
0ceb551
Merge remote changes
ozozozo686 Oct 23, 2025
b1ee4df
fix leadboard profile
0arthurr Oct 23, 2025
71b790d
Merge branch 'team-7-sprint-3' of https://github.com/UQcsse3200/2025-…
0arthurr Oct 23, 2025
c5aa16c
Merge branch 'main' into team-7-sprint-3
Alex118099 Oct 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified source/core/assets/images/profile1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified source/core/assets/images/profile2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified source/core/assets/images/profile3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified source/core/assets/images/profile4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion source/core/src/main/com/csse3200/game/GdxGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ private Screen newScreen(ScreenType screenType, boolean isContinue, String saveF
return new BookScreen(this, BookPage.ENEMY_PAGE);
case TOWER_BOOK:
return new BookScreen(this, BookPage.TOWER_PAGE);
case ACHIEVEMENT_BOOK:
return new BookScreen(this, BookPage.ACHIEVEMENT_PAGE);
case HERO_BOOK:
return new BookScreen(this, BookPage.HERO_PAGE);
default:
Expand All @@ -172,7 +174,7 @@ private Screen newScreen(ScreenType screenType, boolean isContinue, String saveF

public enum ScreenType {
MAIN_MENU, MAIN_GAME, SETTINGS, SAVE_SELECTION, OPENING_CUTSCENE, VICTORY, DEFEAT,
MAP_SELECTION, BOOK, CURRENCY_BOOK, ENEMY_BOOK, TOWER_BOOK, UPGRADES, HERO_BOOK
MAP_SELECTION, BOOK, CURRENCY_BOOK, ENEMY_BOOK, TOWER_BOOK, ACHIEVEMENT_BOOK, UPGRADES, HERO_BOOK
}

public void setOpeningCutsceneWithBackground(int backgroundIndex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.csse3200.game.services.ServiceLocator;

/**
* Holds the player's points and notifies the HUD on change.
Expand All @@ -26,6 +27,17 @@ public void addPoints(int points) {
int oldScore = totalScore;
totalScore += points;
logger.info("Added {} points to player score: {} -> {}", points, oldScore, totalScore);

// 更新GameScoreService的缓存
try {
var scoreService = ServiceLocator.getGameScoreService();
if (scoreService != null && scoreService.isGameInProgress()) {
scoreService.setCurrentScore(totalScore);
}
} catch (Exception e) {
logger.debug("Could not update GameScoreService cache: {}", e.getMessage());
}

if (entity != null) {
entity.getEvents().trigger("updateScore", totalScore);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.csse3200.game.components.deck.*;
import com.csse3200.game.entities.configs.*;
import com.csse3200.game.files.FileLoader;
import com.csse3200.game.services.AchievementService;
import com.csse3200.game.services.ServiceLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -177,6 +179,70 @@ private static List<DeckComponent> createDecks() {
}
}

/**
* A book component containing achievement decks.
*/
public static class AchievementBookComponent extends BookComponent {
/** Constructs an achievement book component with all achievements. */
public AchievementBookComponent() {
super("ACHIEVEMENTS", createDecks());
}

/**
* Creates a list of achievement deck components.
*
* @return a list of {@link DeckComponent} for all achievements
*/
private static List<DeckComponent> createDecks() {
List<DeckComponent> decks = new ArrayList<>();

// Get achievement service
AchievementService achievementService = ServiceLocator.getAchievementService();

// Achievement definitions with descriptions and images
addAchievement(decks, achievementService,
AchievementService.TOUGH_SURVIVOR,
"Tough Survivor",
"Survive with minimal damage and prove your resilience.",
"images/tough survivor.jpg");

addAchievement(decks, achievementService,
AchievementService.SPEED_RUNNER,
"Speed Runner",
"Complete the level in record time.",
"images/speed runner.jpg");

addAchievement(decks, achievementService,
AchievementService.SLAYER,
"Slayer",
"Defeat a massive number of enemies.",
"images/slayer.jpg");

addAchievement(decks, achievementService,
AchievementService.PERFECT_CLEAR,
"Perfect Clear",
"Complete a level without taking any damage.",
"images/perfect clear.jpg");

addAchievement(decks, achievementService,
AchievementService.PARTICIPATION,
"Participation",
"Join the game and start your journey.",
"images/participation.jpg");

return decks;
}

/**
* Helper method to add an achievement deck to the list.
*/
private static void addAchievement(List<DeckComponent> decks, AchievementService service,
String achievementId, String name, String description, String image) {
boolean locked = service == null || !service.isUnlocked(achievementId);
decks.add(new AchievementBookDeckComponent(name, description, image, locked));
}
}

public static class HeroBookComponent extends BookComponent {
public HeroBookComponent() {
super("HEROES", createDecks());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class BookDisplay extends UIComponent {
/**
* Constructs a BookDisplay for a specific page type.
*
* @param bookPage the type of book page to display (TOWER_PAGE, ENEMY_PAGE, or CURRENCY_PAGE)
* @param bookPage the type of book page to display (TOWER_PAGE, ENEMY_PAGE, CURRENCY_PAGE, ACHIEVEMENT_PAGE, or HERO_PAGE)
*/
public BookDisplay(BookPage bookPage) {
super();
Expand All @@ -75,6 +75,9 @@ public BookDisplay(BookPage bookPage) {
} else if (bookPage == BookPage.TOWER_PAGE) {
this.book = new BookComponent.TowerBookComponent();
maxWordsLore = 25;
} else if (bookPage == BookPage.ACHIEVEMENT_PAGE) {
this.book = new BookComponent.AchievementBookComponent();
maxWordsLore = 25;
} else if (bookPage == BookPage.HERO_PAGE) {
this.book = new BookComponent.HeroBookComponent();
maxWordsLore = 30;
Expand All @@ -93,8 +96,8 @@ public void create() {
rightTable.setFillParent(true);
rightTable.top().right()
.padLeft(stage.getViewport().getWorldWidth() * 0.2f)
.padTop(stage.getViewport().getWorldHeight() * 0.08f)
.padRight(stage.getViewport().getWorldWidth()* 0.17f);
.padTop(stage.getViewport().getWorldHeight() * 0.15f)
.padRight(stage.getViewport().getWorldWidth()* 0.19f);
addActors();
stage.addActor(rightTable);
this.entity.getEvents().addListener(eventName, this::renderRightDeck);
Expand Down Expand Up @@ -219,20 +222,25 @@ private void renderContentList() {
TextButton.TextButtonStyle buttonStyle;
TextButton button;
String lockedValue = stats.get(DeckComponent.StatType.LOCKED);
if (lockedValue != null && lockedValue.equals("true")) {
buttonStyle = createCustomButtonStyle(DeckComponent.StatType.LOCKED.getTexturePath(), false);
button = new TextButton("", buttonStyle);
} else {
buttonStyle = createCustomButtonStyle(stats.get(DeckComponent.StatType.TEXTURE_PATH), true);
button = new TextButton("", buttonStyle);
button.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent changeEvent, Actor actor) {
logger.debug("Button inside bookPage clicked");
entity.getEvents().trigger(eventName, currentDeck);
}
});
boolean isLocked = lockedValue != null && lockedValue.equals("true");

// 始终使用成就的图标,不管是否锁定,且所有成就都可点击
buttonStyle = createCustomButtonStyle(stats.get(DeckComponent.StatType.TEXTURE_PATH), true);
button = new TextButton("", buttonStyle);

// 如果锁定,添加半透明效果
if (isLocked) {
button.setColor(1f, 1f, 1f, 0.4f); // 40% 透明度表示锁定状态
}

// 所有成就都可以点击查看详情
button.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent changeEvent, Actor actor) {
logger.debug("Button inside bookPage clicked");
entity.getEvents().trigger(eventName, currentDeck);
}
});

// Wrap button with a bordered table
Table borderedButton = new Table();
Expand Down Expand Up @@ -365,10 +373,10 @@ private void renderRightDeck(DeckComponent deck) {
if (lore != null && !lore.isEmpty()) {
String trimmedLore = trimWords(lore, maxWordsLore);
Label loreLabel = new Label(trimmedLore, skin, "small"); // use a smaller style
loreLabel.setFontScale(stageWidth * 0.0008f);
loreLabel.setFontScale(stageWidth * 0.0006f); // Reduced from 0.0008f to make text smaller
loreLabel.setWrap(true);
rightTable.add(loreLabel)
.width(stageWidth * 0.3f)
.width(stageWidth * 0.25f) // Reduced from 0.3f to keep within book bounds
.center();
rightTable.row().padTop(stageHeight * 0.02f);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum BookPage {
TOWER_PAGE,
ENEMY_PAGE,
CURRENCY_PAGE,
ACHIEVEMENT_PAGE,
HERO_PAGE,
NONE
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
public class MainBookDisplay extends UIComponent {
private static final Logger logger = LoggerFactory.getLogger(MainBookDisplay.class);

/** Background images for buttons: enemies, currencies, towers, back button. */
/** Background images for buttons: enemies, currencies, towers, achievements, heroes, back button. */
private final String[] buttonBackGround = {
"images/book/enemies_book.png",
"images/book/currencies_book.png",
"images/book/towers_book.png",
"images/book/hologram.png",
"images/book/heroes_book.png"
"images/book/achievements_book.png",
"images/book/heroes_book.png",
"images/book/hologram.png"
};

private Table contentTable;
Expand Down Expand Up @@ -99,21 +100,22 @@ private void renderBackGround() {
stage.addActor(backgroundImage);
}

/** Renders the navigation buttons for enemies, currencies, and towers. */
/** Renders the navigation buttons for enemies, currencies, towers, achievements, and heroes. */
private void renderContentList() {
float stageWidth = stage.getViewport().getWorldWidth();
float stageHeight = stage.getViewport().getWorldHeight();

// Scale buttons relative to stage size
float buttonWidth = stageWidth * 0.2f; // 8% of stage width
float buttonHeight = stageHeight * 0.26f; // 12% of stage height
// Scale buttons relative to stage size (now 5 buttons)
float buttonWidth = stageWidth * 0.18f; // Adjusted to fit 5 buttons
float buttonHeight = stageHeight * 0.24f;

Table table = new Table();
table.setFillParent(true);

TextButton.TextButtonStyle enemyButtonStyle = createCustomButtonStyle(buttonBackGround[0]);
TextButton.TextButtonStyle currencyButtonStyle = createCustomButtonStyle(buttonBackGround[1]);
TextButton.TextButtonStyle towerButtonStyle = createCustomButtonStyle(buttonBackGround[2]);
TextButton.TextButtonStyle achievementButtonStyle = createCustomButtonStyle(buttonBackGround[3]);
TextButton.TextButtonStyle heroButtonStyle = createCustomButtonStyle(buttonBackGround[4]);

TextButton enemyButton = new TextButton("", enemyButtonStyle);
Expand Down Expand Up @@ -146,45 +148,32 @@ public void changed(ChangeEvent changeEvent, Actor actor) {
}
});

TextButton heroButton = new TextButton("", heroButtonStyle);
heroButton.getLabel().setColor(Color.WHITE);
heroButton.addListener(new ChangeListener() {
@Override public void changed(ChangeEvent e, Actor a) {
logger.debug("Go to hero clicked");
entity.getEvents().trigger("goToHero");
}
});

/* Map book -> replace this
TextButton tmpMapButton = new TextButton("", heroButtonStyle);
heroButton.getLabel().setColor(Color.WHITE);
heroButton.addListener(new ChangeListener() {
@Override public void changed(ChangeEvent e, Actor a) {
logger.debug("Go to hero clicked");
entity.getEvents().trigger("goToHero");
TextButton achievementButton = new TextButton("", achievementButtonStyle);
achievementButton.getLabel().setColor(Color.WHITE);
achievementButton.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent changeEvent, Actor actor) {
logger.debug("Go to achievement clicked");
entity.getEvents().trigger("goToAchievement");
}
});
*/

/* Achievement book -> replace this
TextButton tmpAchievementButton = new TextButton("", heroButtonStyle);
TextButton heroButton = new TextButton("", heroButtonStyle);
heroButton.getLabel().setColor(Color.WHITE);
heroButton.addListener(new ChangeListener() {
@Override public void changed(ChangeEvent e, Actor a) {
logger.debug("Go to hero clicked");
entity.getEvents().trigger("goToHero");
}
});
*/

table.row().padTop(stageHeight * 0.02f); // First row of books
table.add(enemyButton).size(buttonWidth, buttonHeight);
table.add(currencyButton).size(buttonWidth, buttonHeight);
table.add(towerButton).size(buttonWidth, buttonHeight);
table.add(enemyButton).size(buttonWidth, buttonHeight).padRight(stageWidth * 0.01f);
table.add(currencyButton).size(buttonWidth, buttonHeight).padRight(stageWidth * 0.01f);
table.add(towerButton).size(buttonWidth, buttonHeight).padRight(stageWidth * 0.01f);
table.row().padTop(stageHeight * 0.02f); // Second row of books
table.add(achievementButton).size(buttonWidth, buttonHeight).padRight(stageWidth * 0.01f);
table.add(heroButton).size(buttonWidth, buttonHeight);
// table.add(tmpMapButton).size(buttonWidth, buttonHeight);
// table.add(tmpAchievementButton).size(buttonWidth, buttonHeight);

table.row().padTop(stageHeight * 0.01f).padBottom(stageHeight * 0.03f);

Expand All @@ -200,7 +189,7 @@ private void renderExitButton() {
float buttonWidth = stageWidth * 0.15f; // 5% of stage width
float buttonHeight = stageHeight * 0.24f; // 8% of stage height

TextButton.TextButtonStyle exitButtonStyle = createCustomButtonStyle(buttonBackGround[3]);
TextButton.TextButtonStyle exitButtonStyle = createCustomButtonStyle(buttonBackGround[5]);
TextButton exitButton = new TextButton("", exitButtonStyle);
exitButton.getLabel().setColor(Color.WHITE);

Expand Down Expand Up @@ -233,21 +222,29 @@ private TextButton.TextButtonStyle createCustomButtonStyle(String backGround) {

style.font = skin.getFont("segoe_ui");

Texture buttonTexture = ServiceLocator.getResourceService()
.getAsset(backGround, Texture.class);
TextureRegion buttonRegion = new TextureRegion(buttonTexture);
try {
Texture buttonTexture = ServiceLocator.getResourceService()
.getAsset(backGround, Texture.class);
TextureRegion buttonRegion = new TextureRegion(buttonTexture);

NinePatch buttonPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);
NinePatch buttonPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);

NinePatch pressedPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);
pressedPatch.setColor(new Color(0.8f, 0.8f, 0.8f, 1f));
NinePatch pressedPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);
pressedPatch.setColor(new Color(0.8f, 0.8f, 0.8f, 1f));

NinePatch hoverPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);
hoverPatch.setColor(new Color(1.1f, 1.1f, 1.1f, 1f));
NinePatch hoverPatch = new NinePatch(buttonRegion, 10, 10, 10, 10);
hoverPatch.setColor(new Color(1.1f, 1.1f, 1.1f, 1f));

style.up = new NinePatchDrawable(buttonPatch);
style.down = new NinePatchDrawable(pressedPatch);
style.over = new NinePatchDrawable(hoverPatch);
style.up = new NinePatchDrawable(buttonPatch);
style.down = new NinePatchDrawable(pressedPatch);
style.over = new NinePatchDrawable(hoverPatch);
} catch (Exception e) {
logger.error("Failed to load button texture: {}", backGround, e);
// 使用默认样式作为后备
style.up = skin.getDrawable("default");
style.down = skin.getDrawable("default");
style.over = skin.getDrawable("default");
}

style.fontColor = Color.WHITE;
style.downFontColor = Color.LIGHT_GRAY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public void create() {
entity.getEvents().addListener("goToCurrency", this::goToCurrency);
entity.getEvents().addListener("goToEnemy", this::goToEnemy);
entity.getEvents().addListener("goToTower", this::goToTower);
entity.getEvents().addListener("goToAchievement", this::goToAchievement);
entity.getEvents().addListener("goToHero", this::goToHero);
}

Expand Down Expand Up @@ -88,6 +89,16 @@ private void goToTower() {
playCurrencySound(openBookSoundPath);
}

/**
* Event handler for navigating to the achievement book page and
* playing the open book sound effect.
*/
private void goToAchievement() {
logger.info("Go to achievement page");
game.setScreen(GdxGame.ScreenType.ACHIEVEMENT_BOOK);
playCurrencySound(openBookSoundPath);
}

/**
* Plays the collection sound associated with the given currency type.
*
Expand Down
Loading
Loading