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
|
@@ -5,6 +5,9 @@
|
||||
<RootNamespace>Mr.BrickAdventures</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Facepunch.Steamworks" Version="2.3.3" />
|
||||
<PackageReference Include="Facepunch.Steamworks.Dlls" Version="2.3.2" />
|
||||
<PackageReference Include="Facepunch.Steamworks.Library" Version="2.3.3" />
|
||||
<PackageReference Include="LimboConsole.Sharp" Version="0.0.1-beta-008" />
|
||||
</ItemGroup>
|
||||
</Project>
|
13
achievements/level_complete_1.tres
Normal file
13
achievements/level_complete_1.tres
Normal file
@@ -0,0 +1,13 @@
|
||||
[gd_resource type="Resource" script_class="AchievementResource" load_steps=3 format=3 uid="uid://3odfkm1ig5"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cebeyr4wnibvk" path="res://sprites/achievement.png" id="1_usw25"]
|
||||
[ext_resource type="Script" uid="uid://duib5phrmpro5" path="res://scripts/Resources/AchievementResource.cs" id="2_n7ktn"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_n7ktn")
|
||||
Id = "level_complete_1"
|
||||
DisplayName = "Complete level 1"
|
||||
Description = ""
|
||||
Icon = ExtResource("1_usw25")
|
||||
IsSecret = false
|
||||
metadata/_custom_type_script = "uid://duib5phrmpro5"
|
@@ -1,22 +0,0 @@
|
||||
[configuration]
|
||||
entry_symbol = "godotsteam_init"
|
||||
compatibility_minimum = "4.4"
|
||||
|
||||
[libraries]
|
||||
macos.debug = "res://addons/godotsteam/osx/libgodotsteam.macos.template_debug.framework"
|
||||
macos.release = "res://addons/godotsteam/osx/libgodotsteam.macos.template_release.framework"
|
||||
windows.debug.x86_64 = "res://addons/godotsteam/win64/libgodotsteam.windows.template_debug.x86_64.dll"
|
||||
windows.debug.x86_32 = "res://addons/godotsteam/win32/libgodotsteam.windows.template_debug.x86_32.dll"
|
||||
windows.release.x86_64 = "res://addons/godotsteam/win64/libgodotsteam.windows.template_release.x86_64.dll"
|
||||
windows.release.x86_32 = "res://addons/godotsteam/win32/libgodotsteam.windows.template_release.x86_32.dll"
|
||||
linux.debug.x86_64 = "res://addons/godotsteam/linux64/libgodotsteam.linux.template_debug.x86_64.so"
|
||||
linux.debug.x86_32 = "res://addons/godotsteam/linux32/libgodotsteam.linux.template_debug.x86_32.so"
|
||||
linux.release.x86_64 = "res://addons/godotsteam/linux64/libgodotsteam.linux.template_release.x86_64.so"
|
||||
linux.release.x86_32 = "res://addons/godotsteam/linux32/libgodotsteam.linux.template_release.x86_32.so"
|
||||
|
||||
[dependencies]
|
||||
macos.universal = { "res://addons/godotsteam/osx/libsteam_api.dylib": "" }
|
||||
windows.x86_64 = { "res://addons/godotsteam/win64/steam_api64.dll": "" }
|
||||
windows.x86_32 = { "res://addons/godotsteam/win32/steam_api.dll": "" }
|
||||
linux.x86_64 = { "res://addons/godotsteam/linux64/libsteam_api.so": "" }
|
||||
linux.x86_32 = { "res://addons/godotsteam/linux32/libsteam_api.so": "" }
|
@@ -1 +0,0 @@
|
||||
uid://cbt61wgh4qe5l
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>libgodotsteam.debug</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.godotsteam.godotsteam</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>libgodotsteam.debug</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.15</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.15</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.12</string>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>libgodotsteam</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.godotsteam.godotsteam</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>libgodotsteam</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.15</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.15</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.12</string>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,11 +6,10 @@ runnable=true
|
||||
advanced_options=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="scenes"
|
||||
export_files=PackedStringArray("res://scenes/test.tscn", "res://objects/game_manager.tscn")
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="builds/optimized_for_size/Mr. Brick Adventures.exe"
|
||||
export_path="builds/windows/Mr. Brick Adventures.exe"
|
||||
patches=PackedStringArray()
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
@@ -22,7 +21,7 @@ script_export_mode=2
|
||||
[preset.0.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release="D:/Dev/godot/bin/godot.windows.template_release.x86_64.exe"
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=1
|
||||
binary_format/embed_pck=true
|
||||
texture_format/s3tc_bptc=true
|
||||
@@ -65,6 +64,9 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
|
||||
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
|
||||
Remove-Item -Recurse -Force '{temp_dir}'"
|
||||
dotnet/include_scripts_content=false
|
||||
dotnet/include_debug_symbols=true
|
||||
dotnet/embed_build_outputs=false
|
||||
|
||||
[preset.1]
|
||||
|
||||
@@ -109,13 +111,16 @@ progressive_web_app/icon_144x144=""
|
||||
progressive_web_app/icon_180x180=""
|
||||
progressive_web_app/icon_512x512=""
|
||||
progressive_web_app/background_color=Color(0, 0, 0, 1)
|
||||
dotnet/include_scripts_content=false
|
||||
dotnet/include_debug_symbols=true
|
||||
dotnet/embed_build_outputs=false
|
||||
|
||||
[preset.2]
|
||||
|
||||
name="Linux"
|
||||
platform="Linux"
|
||||
runnable=true
|
||||
advanced_options=false
|
||||
advanced_options=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
@@ -151,3 +156,6 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
|
||||
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
|
||||
rm -rf \"{temp_dir}\""
|
||||
dotnet/include_scripts_content=false
|
||||
dotnet/include_debug_symbols=true
|
||||
dotnet/embed_build_outputs=false
|
||||
|
8
objects/achievement_manager.tscn
Normal file
8
objects/achievement_manager.tscn
Normal file
@@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bjdhgdolcxxbq"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c4vvuqnx5y33u" path="res://Autoloads/AchievementManager.cs" id="1_lomle"]
|
||||
[ext_resource type="PackedScene" uid="uid://tgaadui3lvdc" path="res://objects/ui/achievement_popup.tscn" id="2_k3wdv"]
|
||||
|
||||
[node name="AchievementManager" type="Node"]
|
||||
script = ExtResource("1_lomle")
|
||||
AchievementPopupScene = ExtResource("2_k3wdv")
|
@@ -1,6 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://rnpsa2u74nio"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://deguukal87gcb" path="res://scripts/achievements.gd" id="1_1itsx"]
|
||||
|
||||
[node name="Achievements" type="Node"]
|
||||
script = ExtResource("1_1itsx")
|
@@ -8,9 +8,12 @@
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_yfu6m"]
|
||||
size = Vector2(28, 32)
|
||||
|
||||
[node name="ExitLevel" type="Area2D"]
|
||||
[node name="ExitLevel" type="Area2D" node_paths=PackedStringArray("DoorSprite")]
|
||||
collision_layer = 0
|
||||
collision_mask = 4
|
||||
script = ExtResource("4_06sog")
|
||||
DoorSprite = NodePath("Sprite2D")
|
||||
OpenedDoorFrame = 88
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
position = Vector2(0, -8)
|
||||
@@ -27,17 +30,8 @@ shape = SubResource("RectangleShape2D_yfu6m")
|
||||
[node name="RequirementComponent" type="Node" parent="."]
|
||||
script = ExtResource("2_ed7mh")
|
||||
RequirementType = 1
|
||||
metadata/_custom_type_script = "uid://cmh8k0rdsyh7j"
|
||||
|
||||
[node name="UnlockOnRequirementComponent" type="Node" parent="." node_paths=PackedStringArray("RequirementComponent", "UnlockTarget")]
|
||||
script = ExtResource("3_ed7mh")
|
||||
RequirementComponent = NodePath("../RequirementComponent")
|
||||
UnlockTarget = NodePath("../ExitDoorComponent")
|
||||
metadata/_custom_type_script = "uid://c8xhgkg8gcqu6"
|
||||
|
||||
[node name="ExitDoorComponent" type="Node" parent="." node_paths=PackedStringArray("ExitArea", "DoorSprite")]
|
||||
script = ExtResource("4_06sog")
|
||||
ExitArea = NodePath("..")
|
||||
DoorSprite = NodePath("../Sprite2D")
|
||||
OpenedDoorFrame = 88
|
||||
metadata/_custom_type_script = "uid://bwamqffvpa452"
|
||||
UnlockTarget = NodePath("..")
|
||||
|
@@ -1,6 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cyvcg2re4qifd"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://f4y8evisxgnc" path="res://scripts/steam_integration.gd" id="1_ds8p3"]
|
||||
|
||||
[node name="SteamIntegration" type="Node"]
|
||||
script = ExtResource("1_ds8p3")
|
80
objects/ui/achievement_popup.tscn
Normal file
80
objects/ui/achievement_popup.tscn
Normal file
@@ -0,0 +1,80 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://tgaadui3lvdc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cejjan582nhfn" path="res://scripts/UI/AchievementPopup.cs" id="1_8pd1y"]
|
||||
[ext_resource type="Texture2D" uid="uid://cebeyr4wnibvk" path="res://sprites/achievement.png" id="2_1wq1d"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_enx8n"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="AchievementPopup" type="CanvasLayer" node_paths=PackedStringArray("TitleLabel", "DescriptionLabel", "IconRect")]
|
||||
script = ExtResource("1_8pd1y")
|
||||
TitleLabel = NodePath("Container/Panel/MarginContainer/VBoxContainer/Title")
|
||||
DescriptionLabel = NodePath("Container/Panel/MarginContainer/VBoxContainer/Description")
|
||||
IconRect = NodePath("Container/Panel/MarginContainer/VBoxContainer/TextureRect")
|
||||
metadata/_custom_type_script = "uid://cejjan582nhfn"
|
||||
|
||||
[node name="Container" type="Control" parent="."]
|
||||
custom_minimum_size = Vector2(200, 120)
|
||||
layout_mode = 3
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -200.0
|
||||
offset_top = -120.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
|
||||
[node name="Panel" type="Panel" parent="Container"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_enx8n")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="Container/Panel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 4
|
||||
theme_override_constants/margin_top = 4
|
||||
theme_override_constants/margin_right = 4
|
||||
theme_override_constants/margin_bottom = 4
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Container/Panel/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Container/Panel/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(120, 30)
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "saaaaaaaaaaaaaaaaaaa"
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="Description" type="Label" parent="Container/Panel/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(120, 40)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.7, 0.7, 0.7, 1)
|
||||
text = "aaaaaaaaaaaaaaaaa"
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="Control" type="Control" parent="Container/Panel/MarginContainer/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="Container/Panel/MarginContainer/VBoxContainer"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(128, 32)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 8
|
||||
texture = ExtResource("2_1wq1d")
|
||||
expand_mode = 4
|
||||
stretch_mode = 5
|
@@ -38,6 +38,8 @@ SaveSystem="*res://Autoloads/SaveSystem.cs"
|
||||
ConsoleManager="*res://Autoloads/ConsoleManager.cs"
|
||||
LimboConsole="*res://addons/limbo_console/limbo_console.gd"
|
||||
DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
||||
SteamManager="*res://Autoloads/SteamManager.cs"
|
||||
AchievementManager="*res://objects/achievement_manager.tscn"
|
||||
|
||||
[debug]
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
13
scripts/Resources/AchievementResource.cs
Normal file
13
scripts/Resources/AchievementResource.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class AchievementResource : Resource
|
||||
{
|
||||
[Export] public string Id { get; set; } = ""; // e.g., "level_1_complete"
|
||||
[Export] public string DisplayName { get; set; } = "New Achievement";
|
||||
[Export(PropertyHint.MultilineText)] public string Description { get; set; } = "";
|
||||
[Export] public Texture2D Icon { get; set; }
|
||||
[Export] public bool IsSecret { get; set; } = false;
|
||||
}
|
1
scripts/Resources/AchievementResource.cs.uid
Normal file
1
scripts/Resources/AchievementResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://duib5phrmpro5
|
52
scripts/UI/AchievementPopup.cs
Normal file
52
scripts/UI/AchievementPopup.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Threading.Tasks;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class AchievementPopup : CanvasLayer
|
||||
{
|
||||
[Export] public Label TitleLabel { get; set; }
|
||||
[Export] public Label DescriptionLabel { get; set; }
|
||||
[Export] public TextureRect IconRect { get; set; }
|
||||
[Export] public float DisplayDuration { get; set; } = 3.0f;
|
||||
|
||||
private Control _container;
|
||||
private Vector2 _startPosition;
|
||||
private Vector2 _onScreenPosition;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_container = GetNode<Control>("Container");
|
||||
|
||||
_startPosition = new Vector2(_container.Position.X, -_container.Size.Y - 50);
|
||||
_onScreenPosition = _container.Position;
|
||||
_container.Position = _startPosition;
|
||||
}
|
||||
|
||||
public async Task ShowAchievement(AchievementResource achievement)
|
||||
{
|
||||
TitleLabel.Text = achievement.DisplayName;
|
||||
DescriptionLabel.Text = achievement.Description;
|
||||
IconRect.Texture = achievement.Icon;
|
||||
|
||||
var tween = CreateTween();
|
||||
tween.TweenProperty(_container, "position", _onScreenPosition, 0.5f)
|
||||
.SetTrans(Tween.TransitionType.Cubic)
|
||||
.SetEase(Tween.EaseType.Out);
|
||||
|
||||
await ToSignal(tween, Tween.SignalName.Finished);
|
||||
|
||||
await ToSignal(GetTree().CreateTimer(DisplayDuration), Timer.SignalName.Timeout);
|
||||
|
||||
tween = CreateTween();
|
||||
tween.TweenProperty(_container, "position", _startPosition, 0.5f)
|
||||
.SetTrans(Tween.TransitionType.Cubic)
|
||||
.SetEase(Tween.EaseType.In);
|
||||
|
||||
await ToSignal(tween, Tween.SignalName.Finished);
|
||||
|
||||
QueueFree();
|
||||
}
|
||||
}
|
1
scripts/UI/AchievementPopup.cs.uid
Normal file
1
scripts/UI/AchievementPopup.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cejjan582nhfn
|
@@ -4,29 +4,25 @@ using Mr.BrickAdventures.scripts.interfaces;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.components;
|
||||
|
||||
public partial class ExitDoorComponent : Node, IUnlockable
|
||||
public partial class ExitDoorComponent : Area2D, IUnlockable
|
||||
{
|
||||
[Export] public bool Locked { get; set; } = true;
|
||||
[Export] public Area2D ExitArea { get; set; }
|
||||
[Export] public Sprite2D DoorSprite { get; set; }
|
||||
[Export] public AudioStreamPlayer2D OpenDoorSfx { get; set; }
|
||||
[Export] public int OpenedDoorFrame { get; set; } = 0;
|
||||
[Export] public string AchievementId = "level_complete_1";
|
||||
|
||||
[Signal] public delegate void ExitTriggeredEventHandler();
|
||||
|
||||
private GameManager _gameManager;
|
||||
private AchievementManager _achievementManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_achievementManager = GetNode<AchievementManager>("/root/AchievementManager");
|
||||
|
||||
if (ExitArea == null)
|
||||
{
|
||||
GD.PushError("ExitDoorComponent: ExitArea is not set.");
|
||||
return;
|
||||
}
|
||||
|
||||
ExitArea.BodyEntered += OnExitAreaBodyEntered;
|
||||
BodyEntered += OnExitAreaBodyEntered;
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +31,7 @@ public partial class ExitDoorComponent : Node, IUnlockable
|
||||
if (Locked) return;
|
||||
|
||||
EmitSignalExitTriggered();
|
||||
_achievementManager.UnlockAchievement(AchievementId);
|
||||
_gameManager.UnlockLevel((int)_gameManager.PlayerState["current_level"] + 1);
|
||||
CallDeferred(nameof(GoToNextLevel));
|
||||
}
|
||||
|
BIN
sprites/achievement.png
Normal file
BIN
sprites/achievement.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
34
sprites/achievement.png.import
Normal file
34
sprites/achievement.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cebeyr4wnibvk"
|
||||
path="res://.godot/imported/achievement.png-6dc4e0e28c2cf29a2febc21fd42d98fb.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sprites/achievement.png"
|
||||
dest_files=["res://.godot/imported/achievement.png-6dc4e0e28c2cf29a2febc21fd42d98fb.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
sprites/achievement.psd
Normal file
BIN
sprites/achievement.psd
Normal file
Binary file not shown.
BIN
sprites/locked_achievement.png
Normal file
BIN
sprites/locked_achievement.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
34
sprites/locked_achievement.png.import
Normal file
34
sprites/locked_achievement.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://d1p2g3mv76ksv"
|
||||
path="res://.godot/imported/locked_achievement.png-53164620812ca9339207b2e63190ee57.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sprites/locked_achievement.png"
|
||||
dest_files=["res://.godot/imported/locked_achievement.png-53164620812ca9339207b2e63190ee57.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
Reference in New Issue
Block a user