Add achievement system with unlock and UI popup functionality (#8)
This commit is contained in:
105
Autoloads/AchievementManager.cs
Normal file
105
Autoloads/AchievementManager.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class AchievementManager : Node
|
||||
{
|
||||
[Export] private string AchievementsFolderPath = "res://achievements/";
|
||||
[Export] private PackedScene AchievementPopupScene { get; set; }
|
||||
|
||||
private System.Collections.Generic.Dictionary<string, AchievementResource> _achievements = new();
|
||||
private Array<string> _unlockedAchievementIds = [];
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
LoadAchievementsFromFolder();
|
||||
LoadUnlockedAchievements();
|
||||
}
|
||||
|
||||
private void LoadAchievementsFromFolder()
|
||||
{
|
||||
using var dir = DirAccess.Open(AchievementsFolderPath);
|
||||
if (dir == null)
|
||||
{
|
||||
GD.PrintErr($"AchievementManager: Could not open achievements folder at '{AchievementsFolderPath}'");
|
||||
return;
|
||||
}
|
||||
|
||||
dir.ListDirBegin();
|
||||
var fileName = dir.GetNext();
|
||||
while (fileName != "")
|
||||
{
|
||||
if (!dir.CurrentIsDir() && fileName.EndsWith(".tres"))
|
||||
{
|
||||
var achievement = GD.Load<AchievementResource>(AchievementsFolderPath + fileName);
|
||||
if (achievement != null)
|
||||
{
|
||||
_achievements.TryAdd(achievement.Id, achievement);
|
||||
}
|
||||
}
|
||||
fileName = dir.GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnlockAchievement(string achievementId)
|
||||
{
|
||||
if (!_achievements.TryGetValue(achievementId, out var achievement))
|
||||
{
|
||||
GD.PrintErr($"Attempted to unlock non-existent achievement: '{achievementId}'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_unlockedAchievementIds.Contains(achievementId))
|
||||
{
|
||||
return; // Already unlocked
|
||||
}
|
||||
|
||||
// 1. Mark as unlocked internally
|
||||
_unlockedAchievementIds.Add(achievementId);
|
||||
GD.Print($"Achievement Unlocked: {achievement.DisplayName}");
|
||||
|
||||
// 2. Show the UI popup
|
||||
if (AchievementPopupScene != null)
|
||||
{
|
||||
var popup = AchievementPopupScene.Instantiate<scripts.UI.AchievementPopup>();
|
||||
GetTree().Root.AddChild(popup);
|
||||
_ = popup.ShowAchievement(achievement);
|
||||
}
|
||||
|
||||
// 3. Call SteamManager if it's available
|
||||
if (SteamManager.IsSteamInitialized)
|
||||
{
|
||||
SteamManager.UnlockAchievement(achievement.Id);
|
||||
}
|
||||
|
||||
// 4. Save progress
|
||||
SaveUnlockedAchievements();
|
||||
}
|
||||
|
||||
public void LockAchievement(string achievementId)
|
||||
{
|
||||
if (_unlockedAchievementIds.Contains(achievementId))
|
||||
{
|
||||
_unlockedAchievementIds.Remove(achievementId);
|
||||
SaveUnlockedAchievements();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveUnlockedAchievements()
|
||||
{
|
||||
_gameManager.PlayerState["unlocked_achievements"] = _unlockedAchievementIds;
|
||||
// You might want to trigger a save game here, depending on your SaveSystem
|
||||
}
|
||||
|
||||
private void LoadUnlockedAchievements()
|
||||
{
|
||||
if (_gameManager.PlayerState.TryGetValue("unlocked_achievements", out var unlocked))
|
||||
{
|
||||
_unlockedAchievementIds = (Array<string>)unlocked;
|
||||
}
|
||||
}
|
||||
}
|
1
Autoloads/AchievementManager.cs.uid
Normal file
1
Autoloads/AchievementManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c4vvuqnx5y33u
|
@@ -10,10 +10,12 @@ public partial class ConsoleManager : Node
|
||||
private GameManager _gameManager;
|
||||
private SkillManager _skillManager;
|
||||
private SkillUnlockerComponent _skillUnlockerComponent;
|
||||
private AchievementManager _achievementManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_achievementManager = GetNode<AchievementManager>("/root/AchievementManager");
|
||||
|
||||
RegisterConsoleCommands();
|
||||
}
|
||||
@@ -154,5 +156,18 @@ public partial class ConsoleManager : Node
|
||||
{
|
||||
_gameManager.OnLevelComplete();
|
||||
}
|
||||
|
||||
[ConsoleCommand("unlock_achievement", "Unlocks an achievement by its ID.")]
|
||||
private void UnlockAchievementCommand(string achievementId)
|
||||
{
|
||||
_achievementManager.UnlockAchievement(achievementId);
|
||||
LimboConsole.Info($"Attempted to unlock achievement '{achievementId}'.");
|
||||
}
|
||||
|
||||
[ConsoleCommand("reset_achievement", "Resets (locks) an achievement by its ID.")]
|
||||
private void ResetAchievementCommand(string achievementId)
|
||||
{
|
||||
_achievementManager.LockAchievement(achievementId);
|
||||
}
|
||||
|
||||
}
|
77
Autoloads/SteamManager.cs
Normal file
77
Autoloads/SteamManager.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using Godot;
|
||||
using Steamworks;
|
||||
using Steamworks.Data;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class SteamManager : Node
|
||||
{
|
||||
private const uint AppId = 3575090;
|
||||
|
||||
public static string PlayerName { get; private set; } = "Player";
|
||||
public static bool IsSteamInitialized { get; private set; } = false;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
try
|
||||
{
|
||||
SteamClient.Init(AppId);
|
||||
IsSteamInitialized = true;
|
||||
|
||||
PlayerName = SteamClient.Name;
|
||||
|
||||
GD.Print($"Steam initialized successfully for user: {PlayerName}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PushError("Failed to initialize Steamworks. Is Steam running?");
|
||||
GD.PushError(e.Message);
|
||||
IsSteamInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (IsSteamInitialized) SteamClient.RunCallbacks();
|
||||
}
|
||||
|
||||
public override void _Notification(int what)
|
||||
{
|
||||
if (what == NotificationWMCloseRequest)
|
||||
{
|
||||
if (IsSteamInitialized)
|
||||
{
|
||||
SteamClient.Shutdown();
|
||||
}
|
||||
GetTree().Quit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void UnlockAchievement(string achievementId)
|
||||
{
|
||||
if (!IsSteamInitialized)
|
||||
{
|
||||
GD.Print($"Steam not initialized. Cannot unlock achievement '{achievementId}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
var ach = new Achievement(achievementId);
|
||||
|
||||
if (ach.State)
|
||||
{
|
||||
GD.Print($"Achievement '{achievementId}' is already unlocked.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ach.Trigger())
|
||||
{
|
||||
SteamUserStats.StoreStats();
|
||||
GD.Print($"Successfully triggered achievement: {ach.Name} ({ach.Identifier})");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr($"Failed to trigger achievement: {achievementId}");
|
||||
}
|
||||
}
|
||||
}
|
1
Autoloads/SteamManager.cs.uid
Normal file
1
Autoloads/SteamManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b5abjlnbia63q
|
Reference in New Issue
Block a user