Compare commits
9 Commits
58eeef60dc
...
clean-code
Author | SHA1 | Date | |
---|---|---|---|
817bd96433 | |||
2cc54f7b37 | |||
406036504a | |||
173f0e5703 | |||
d84f7d1740 | |||
2ad0fe26d2 | |||
c4f7be1b10 | |||
b957b56567 | |||
cce93286be |
27
Autoloads/ConfigFileHandler.cs
Normal file
27
Autoloads/ConfigFileHandler.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class ConfigFileHandler : Node
|
||||
{
|
||||
private ConfigFile _settingsConfig = new();
|
||||
public const string SettingsPath = "user://settings.ini";
|
||||
|
||||
public ConfigFile SettingsConfig => _settingsConfig;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (!FileAccess.FileExists(SettingsPath))
|
||||
{
|
||||
var err = _settingsConfig.Save(SettingsPath);
|
||||
if (err != Error.Ok)
|
||||
GD.PushError($"Failed to create settings file at {SettingsPath}: {err}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var err = _settingsConfig.Load(SettingsPath);
|
||||
if (err != Error.Ok)
|
||||
GD.PushError($"Failed to load settings file at {SettingsPath}: {err}");
|
||||
}
|
||||
}
|
||||
}
|
1
Autoloads/ConfigFileHandler.cs.uid
Normal file
1
Autoloads/ConfigFileHandler.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://8cyvbeyd13cj
|
241
Autoloads/GameManager.cs
Normal file
241
Autoloads/GameManager.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class GameManager : Node
|
||||
{
|
||||
[Export] public Array<PackedScene> LevelScenes { get; set; } = new();
|
||||
|
||||
public PlayerController Player { get; set; }
|
||||
|
||||
private List<Node> _sceneNodes = new();
|
||||
|
||||
public Dictionary PlayerState { get; set; } = new()
|
||||
{
|
||||
{ "coins", 0 },
|
||||
{ "lives", 3 },
|
||||
{ "current_level", 0 },
|
||||
{ "completed_levels", new Array<int>() },
|
||||
{ "unlocked_levels", new Array<int>() {0}},
|
||||
{ "unlocked_skills", new Array<SkillData>() }
|
||||
};
|
||||
|
||||
public Dictionary CurrentSessionState { get; private set; } = new()
|
||||
{
|
||||
{ "coins_collected", 0 },
|
||||
{ "skills_unlocked", new Array<SkillData>() }
|
||||
};
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
GetTree().NodeAdded += OnNodeAdded;
|
||||
GetTree().NodeRemoved += OnNodeRemoved;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
GetTree().NodeAdded -= OnNodeAdded;
|
||||
GetTree().NodeRemoved -= OnNodeRemoved;
|
||||
_sceneNodes.Clear();
|
||||
}
|
||||
|
||||
private void OnNodeAdded(Node node)
|
||||
{
|
||||
_sceneNodes.Add(node);
|
||||
}
|
||||
|
||||
private void OnNodeRemoved(Node node)
|
||||
{
|
||||
_sceneNodes.Remove(node);
|
||||
}
|
||||
|
||||
public void AddCoins(int amount)
|
||||
{
|
||||
PlayerState["coins"] = Mathf.Max(0, (int)PlayerState["coins"] + amount);
|
||||
}
|
||||
|
||||
public void SetCoins(int amount) => PlayerState["coins"] = Mathf.Max(0, amount);
|
||||
|
||||
public int GetCoins() => (int)PlayerState["coins"] + (int)CurrentSessionState["coins_collected"];
|
||||
|
||||
public void RemoveCoins(int amount)
|
||||
{
|
||||
var sessionCoins = (int)CurrentSessionState["coins_collected"];
|
||||
if (amount <= sessionCoins)
|
||||
{
|
||||
CurrentSessionState["coins_collected"] = sessionCoins - amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
var remaining = amount - sessionCoins;
|
||||
CurrentSessionState["coins_collected"] = 0;
|
||||
PlayerState["coins"] = Mathf.Max(0, (int)PlayerState["coins"] - remaining);
|
||||
}
|
||||
PlayerState["coins"] = Mathf.Max(0, (int)PlayerState["coins"]);
|
||||
}
|
||||
|
||||
public void AddLives(int amount) => PlayerState["lives"] = (int)PlayerState["lives"] + amount;
|
||||
public void RemoveLives(int amount) => PlayerState["lives"] = (int)PlayerState["lives"] - amount;
|
||||
public void SetLives(int amount) => PlayerState["lives"] = amount;
|
||||
public int GetLives() => (int)PlayerState["lives"];
|
||||
|
||||
public bool IsSkillUnlocked(SkillData skill)
|
||||
{
|
||||
return ((Array)PlayerState["unlocked_skills"]).Contains(skill)
|
||||
|| ((Array)CurrentSessionState["skills_unlocked"]).Contains(skill);
|
||||
}
|
||||
|
||||
public void UnlockSkill(SkillData skill)
|
||||
{
|
||||
if (!IsSkillUnlocked(skill))
|
||||
((Array)PlayerState["unlocked_skills"]).Add(skill);
|
||||
}
|
||||
|
||||
public void RemoveSkill(string skillName)
|
||||
{
|
||||
var arr = (Array)PlayerState["unlocked_skills"];
|
||||
foreach (SkillData s in arr)
|
||||
{
|
||||
if (s.Name != skillName) continue;
|
||||
|
||||
arr.Remove(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void UnlockSkills(Array<SkillData> skills)
|
||||
{
|
||||
foreach (var s in skills)
|
||||
UnlockSkill(s);
|
||||
}
|
||||
|
||||
public void ResetPlayerState()
|
||||
{
|
||||
PlayerState = new Dictionary
|
||||
{
|
||||
{ "coins", 0 },
|
||||
{ "lives", 3 },
|
||||
{ "current_level", 0 },
|
||||
{ "completed_levels", new Array<int>() },
|
||||
{ "unlocked_levels", new Array<int>() {0}},
|
||||
{ "unlocked_skills", new Array<SkillData>() }
|
||||
};
|
||||
}
|
||||
|
||||
public void UnlockLevel(int levelIndex)
|
||||
{
|
||||
var unlocked = (Array)PlayerState["unlocked_levels"];
|
||||
if (!unlocked.Contains(levelIndex)) unlocked.Add(levelIndex);
|
||||
}
|
||||
|
||||
public void TryToGoToNextLevel()
|
||||
{
|
||||
var next = (int)PlayerState["current_level"] + 1;
|
||||
var unlocked = (Array)PlayerState["unlocked_levels"];
|
||||
if (next < LevelScenes.Count && unlocked.Contains(next))
|
||||
{
|
||||
PlayerState["current_level"] = next;
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[next]);
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkLevelComplete(int levelIndex)
|
||||
{
|
||||
UnlockLevel(levelIndex + 1);
|
||||
var completed = (Array)PlayerState["completed_levels"];
|
||||
if (!completed.Contains(levelIndex)) completed.Add(levelIndex);
|
||||
}
|
||||
|
||||
public void ResetCurrentSessionState()
|
||||
{
|
||||
CurrentSessionState = new Dictionary
|
||||
{
|
||||
{ "coins_collected", 0 },
|
||||
{ "skills_unlocked", new Array<SkillData>() }
|
||||
};
|
||||
}
|
||||
|
||||
public void RestartGame()
|
||||
{
|
||||
ResetPlayerState();
|
||||
ResetCurrentSessionState();
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[0]);
|
||||
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
|
||||
}
|
||||
|
||||
public void QuitGame() => GetTree().Quit();
|
||||
|
||||
public void PauseGame() => Engine.TimeScale = 0;
|
||||
public void ResumeGame() => Engine.TimeScale = 1;
|
||||
|
||||
public void StartNewGame()
|
||||
{
|
||||
ResetPlayerState();
|
||||
ResetCurrentSessionState();
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[0]);
|
||||
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
|
||||
}
|
||||
|
||||
public void ContinueGame()
|
||||
{
|
||||
var save = GetNode<SaveSystem>("/root/SaveSystem");
|
||||
if (!save.LoadGame())
|
||||
{
|
||||
GD.PrintErr("Failed to load game. Starting a new game instead.");
|
||||
StartNewGame();
|
||||
return;
|
||||
}
|
||||
|
||||
var idx = (int)PlayerState["current_level"];
|
||||
if (idx < LevelScenes.Count)
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[idx]);
|
||||
else
|
||||
GD.PrintErr("No levels unlocked to continue.");
|
||||
}
|
||||
|
||||
public void OnLevelComplete()
|
||||
{
|
||||
var levelIndex = (int)PlayerState["current_level"];
|
||||
MarkLevelComplete(levelIndex);
|
||||
AddCoins((int)CurrentSessionState["coins_collected"]);
|
||||
foreach (var s in (Array)CurrentSessionState["skills_unlocked"])
|
||||
UnlockSkill((SkillData)s);
|
||||
|
||||
ResetCurrentSessionState();
|
||||
TryToGoToNextLevel();
|
||||
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
|
||||
}
|
||||
|
||||
public Array<SkillData> GetUnlockedSkills()
|
||||
{
|
||||
var unlocked = (Array<SkillData>)PlayerState["unlocked_skills"];
|
||||
var session = (Array<SkillData>)CurrentSessionState["skills_unlocked"];
|
||||
if (session!.Count == 0) return unlocked;
|
||||
if (unlocked!.Count == 0) return session;
|
||||
var joined = new Array<SkillData>();
|
||||
joined.AddRange(unlocked);
|
||||
joined.AddRange(session);
|
||||
return joined;
|
||||
}
|
||||
|
||||
public PlayerController GetPlayer()
|
||||
{
|
||||
if (Player != null) return Player;
|
||||
|
||||
foreach (var node in _sceneNodes)
|
||||
{
|
||||
if (node is not PlayerController player) continue;
|
||||
|
||||
Player = player;
|
||||
return Player;
|
||||
}
|
||||
|
||||
GD.PrintErr("PlayerController not found in the scene tree.");
|
||||
return null;
|
||||
}
|
||||
}
|
1
Autoloads/GameManager.cs.uid
Normal file
1
Autoloads/GameManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c6eoi3ymefc0x
|
61
Autoloads/SaveSystem.cs
Normal file
61
Autoloads/SaveSystem.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class SaveSystem : Node
|
||||
{
|
||||
[Export] public string SavePath { get; set; } = "user://savegame.save";
|
||||
[Export] public int Version { get; set; } = 1;
|
||||
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
}
|
||||
|
||||
public void SaveGame()
|
||||
{
|
||||
var saveData = new Dictionary
|
||||
{
|
||||
{ "player_state", _gameManager.PlayerState},
|
||||
{ "version", Version}
|
||||
};
|
||||
|
||||
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Write);
|
||||
file.StoreVar(saveData);
|
||||
GD.Print("Game state saved to: ", SavePath);
|
||||
}
|
||||
|
||||
public bool LoadGame()
|
||||
{
|
||||
if (!FileAccess.FileExists(SavePath))
|
||||
return false;
|
||||
|
||||
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Read);
|
||||
var saveDataObj = (Dictionary)file.GetVar();
|
||||
|
||||
if (saveDataObj.ContainsKey("version") && (int)saveDataObj["version"] != Version)
|
||||
{
|
||||
GD.Print($"Save file version mismatch. Expected: {Version}, Found: {saveDataObj["version"]}");
|
||||
return false;
|
||||
}
|
||||
|
||||
GD.Print("Game state loaded from: ", SavePath);
|
||||
GD.Print("Player state: ", saveDataObj["player_state"]);
|
||||
_gameManager.PlayerState = (Dictionary)saveDataObj["player_state"];
|
||||
|
||||
var skills = new Array<SkillData>();
|
||||
foreach (var skill in (Array<SkillData>)_gameManager.PlayerState["unlocked_skills"])
|
||||
{
|
||||
skills.Add(skill);
|
||||
}
|
||||
|
||||
_gameManager.UnlockSkills(skills);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CheckSaveExists() => FileAccess.FileExists(SavePath);
|
||||
}
|
1
Autoloads/SaveSystem.cs.uid
Normal file
1
Autoloads/SaveSystem.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bh20fqbyifidc
|
65
Autoloads/UIManager.cs
Normal file
65
Autoloads/UIManager.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class UIManager : Node
|
||||
{
|
||||
[Export] public Array<Control> UiStack { get; set; } = new();
|
||||
|
||||
[Signal] public delegate void ScreenPushedEventHandler(Control screen);
|
||||
[Signal] public delegate void ScreenPoppedEventHandler(Control screen);
|
||||
|
||||
public void PushScreen(Control screen)
|
||||
{
|
||||
if (screen == null)
|
||||
{
|
||||
GD.PushError($"Cannot push a null screen.");
|
||||
return;
|
||||
}
|
||||
|
||||
UiStack.Add(screen);
|
||||
screen.Show();
|
||||
screen.SetProcessInput(true);
|
||||
screen.SetFocusMode(Control.FocusModeEnum.All);
|
||||
screen.GrabFocus();
|
||||
EmitSignalScreenPushed(screen);
|
||||
}
|
||||
|
||||
public void PopScreen()
|
||||
{
|
||||
if (UiStack.Count == 0)
|
||||
{
|
||||
GD.PushError($"Cannot pop screen from an empty stack.");
|
||||
return;
|
||||
}
|
||||
|
||||
var top = (Control)UiStack[^1];
|
||||
UiStack.RemoveAt(UiStack.Count - 1);
|
||||
top.Hide();
|
||||
top.SetProcessInput(false);
|
||||
EmitSignalScreenPopped(top);
|
||||
top.AcceptEvent();
|
||||
|
||||
if (UiStack.Count > 0) ((Control)UiStack[^1]).GrabFocus();
|
||||
}
|
||||
|
||||
public Control TopScreen() => UiStack.Count > 0 ? (Control)UiStack[^1] : null;
|
||||
|
||||
public bool IsScreenOnTop(Control screen) => UiStack.Count > 0 && (Control)UiStack[^1] == screen;
|
||||
|
||||
public bool IsVisibleOnStack(Control screen) => UiStack.Contains(screen) && screen.Visible;
|
||||
|
||||
public void CloseAll()
|
||||
{
|
||||
while (UiStack.Count > 0)
|
||||
PopScreen();
|
||||
}
|
||||
|
||||
public static void HideAndDisable(Control screen)
|
||||
{
|
||||
screen.Hide();
|
||||
screen.SetProcessInput(false);
|
||||
}
|
||||
|
||||
}
|
1
Autoloads/UIManager.cs.uid
Normal file
1
Autoloads/UIManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c3ldmnrwperr4
|
13
Mr. Brick Adventures.csproj
Normal file
13
Mr. Brick Adventures.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Godot.NET.Sdk/4.4.1">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<RootNamespace>Mr.BrickAdventures</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Chickensoft.AutoInject" Version="2.8.21" />
|
||||
<PackageReference Include="Chickensoft.GodotNodeInterfaces" Version="2.4.31" />
|
||||
<PackageReference Include="Chickensoft.Introspection" Version="3.0.2" />
|
||||
<PackageReference Include="Chickensoft.Introspection.Generator" Version="3.0.2" PrivateAssets="all" OutputItemType="analyzer" />
|
||||
</ItemGroup>
|
||||
</Project>
|
19
Mr. Brick Adventures.sln
Normal file
19
Mr. Brick Adventures.sln
Normal file
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mr. Brick Adventures", "Mr. Brick Adventures.csproj", "{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
|
||||
{A1D482B9-207B-4D6C-A0A0-D9E6D1AE2356}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
6
Mr. Brick Adventures.sln.DotSettings.user
Normal file
6
Mr. Brick Adventures.sln.DotSettings.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACanvasItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fef7b819b226fab796d1dfe66d415dd7510bcac87675020ddb8f03a828e763_003FCanvasItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACollisionShape2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F2ca9b7334678f5c97c7c2a9fbe4837be71cae11b6a30408dd4791b18f997e4a_003FCollisionShape2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F86db9cd834346aad02d74c1b66dd9c64d6ef3147435dd9c9c9477b48f7_003FNode2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARectangleShape2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fa1cc98873548652da0c14ecefa4737431426fcbb24a7f0641e3d9c266c3_003FRectangleShape2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AShape2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F3671dbbd9b17cdf2bf9075b468b6bd7e3ab13fc3be7a116484085d3b6cc9fe_003FShape2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
72
README.md
Normal file
72
README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Przygody Pana Cegły
|
||||
|
||||
[](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
*"The world’s only brick-throwing dad simulator (probably)."*
|
||||
|
||||
---
|
||||
|
||||
## The Story
|
||||
|
||||
Disaster has struck!
|
||||
Mr. Brick’s kids have gone missing, scattered across mysterious lands filled with treacherous traps, cranky critters, and more collapsing bridges than an OSHA nightmare.
|
||||
|
||||
Armed with nothing but his legs, his wits, and an infinite supply of throwable bricks (don’t ask where he keeps them), Mr. Brick will stop at nothing to bring his children home.
|
||||
|
||||
---
|
||||
|
||||
## The Mission
|
||||
|
||||
Run, jump, and hurl bricks with pinpoint accuracy as you navigate dangerous worlds. Smash enemies, trigger ancient mechanisms, and uncover hidden treasures, all while dodging hazards that seem designed specifically to ruin your day.
|
||||
|
||||
---
|
||||
|
||||
## Features That’ll Knock Your Bricks Off
|
||||
|
||||
* **Tight, Classic Platforming**
|
||||
Leap over pits, time your jumps, and try not to land in something unpleasant.
|
||||
|
||||
* **Brick-Fu Combat**
|
||||
Toss bricks to flatten foes, flip switches, and solve puzzles in the most dad-like way possible.
|
||||
|
||||
* **Secrets & Collectibles**
|
||||
Hunt for coins, discover hidden rooms, and find upgrades to make you just a *little* less fragile.
|
||||
|
||||
* **NES-Inspired Pixel Art**
|
||||
All the charm of an 8-bit classic, no cartridge blowing required.
|
||||
|
||||
---
|
||||
|
||||
## Play It Here
|
||||
|
||||
[**Wishlist on Steam**](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/) so you’re ready for launch day.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Project Stats
|
||||
📦 **Lines of Code:**
|
||||

|
||||
|
||||
📈 **Repo Activity:**
|
||||

|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Check the [LICENSE](./LICENSE) for the legal stuff.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Not open to code contributions right now but you *can* help by:
|
||||
|
||||
* Reporting bugs
|
||||
* Suggesting evil new trap ideas
|
||||
* Spreading the word so Mr. Brick can find his kids faster
|
10
app/IGameScenes.cs
Normal file
10
app/IGameScenes.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.app;
|
||||
|
||||
public interface IGameScenes
|
||||
{
|
||||
void Load(PackedScene scene);
|
||||
void Restart();
|
||||
void ReturnToMain(PackedScene mainMenu);
|
||||
}
|
1
app/IGameScenes.cs.uid
Normal file
1
app/IGameScenes.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b7d1ospa5p4nx
|
11
app/ILevelCatalog.cs
Normal file
11
app/ILevelCatalog.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.app;
|
||||
|
||||
public interface ILevelCatalog
|
||||
{
|
||||
int Count { get; }
|
||||
PackedScene? Get(int index);
|
||||
PackedScene First { get; }
|
||||
PackedScene MainMenu { get; }
|
||||
}
|
1
app/ILevelCatalog.cs.uid
Normal file
1
app/ILevelCatalog.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b2sxttgvk6nuq
|
70
common/AppRoot.cs
Normal file
70
common/AppRoot.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.app;
|
||||
using Mr.BrickAdventures.data;
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
using Mr.BrickAdventures.game.services;
|
||||
|
||||
namespace Mr.BrickAdventures.common;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class AppRoot : Node2D,
|
||||
IProvide<PlayerRepository>,
|
||||
IProvide<LevelRepository>,
|
||||
IProvide<SaveClient>,
|
||||
IProvide<SaveService>,
|
||||
IProvide<LevelService>,
|
||||
IProvide<IGameScenes>,
|
||||
IProvide<ILevelCatalog>,
|
||||
IGameScenes
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Export] private Array<PackedScene> _levels = [];
|
||||
[Export] private PackedScene _mainMenu = null!;
|
||||
|
||||
private readonly SaveClient _save = new("user://savegame.save", version: 2);
|
||||
private readonly PlayerRepository _players = new();
|
||||
private readonly LevelRepository _levelsRepo = new();
|
||||
private SaveService _saveService = null!;
|
||||
private LevelService _levelService = null!;
|
||||
private ILevelCatalog _catalog = null!;
|
||||
|
||||
PlayerRepository IProvide<PlayerRepository>.Value() => _players;
|
||||
LevelRepository IProvide<LevelRepository>.Value() => _levelsRepo;
|
||||
SaveClient IProvide<SaveClient>.Value() => _save;
|
||||
SaveService IProvide<SaveService>.Value() => _saveService;
|
||||
LevelService IProvide<LevelService>.Value() => _levelService;
|
||||
ILevelCatalog IProvide<ILevelCatalog>.Value() => _catalog;
|
||||
IGameScenes IProvide<IGameScenes>.Value() => this;
|
||||
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
_saveService = new SaveService(_players, _levelsRepo, _save);
|
||||
_levelService = new LevelService(_levelsRepo);
|
||||
|
||||
_catalog = new ExportedLevelCatalog(_levels, _mainMenu);
|
||||
|
||||
_saveService.TryLoad();
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
public void Load(PackedScene scene) => GetTree().ChangeSceneToPacked(scene);
|
||||
public void Restart() => GetTree().ReloadCurrentScene();
|
||||
public void ReturnToMain(PackedScene mainMenu) => GetTree().ChangeSceneToPacked(mainMenu);
|
||||
|
||||
private sealed class ExportedLevelCatalog : ILevelCatalog
|
||||
{
|
||||
private readonly Array<PackedScene> _levels;
|
||||
public PackedScene MainMenu { get; }
|
||||
public ExportedLevelCatalog(Array<PackedScene> levels, PackedScene mainMenu) {
|
||||
_levels = levels; MainMenu = mainMenu;
|
||||
}
|
||||
public int Count => _levels.Count;
|
||||
public PackedScene? Get(int index) => (index >= 0 && index < _levels.Count) ? _levels[index] : null;
|
||||
public PackedScene First => _levels.Count > 0 ? _levels[0] : MainMenu;
|
||||
}
|
||||
}
|
1
common/AppRoot.cs.uid
Normal file
1
common/AppRoot.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dg2l7cw6da4vb
|
6
data/ConfigClient.cs
Normal file
6
data/ConfigClient.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.data;
|
||||
|
||||
public class ConfigClient
|
||||
{
|
||||
|
||||
}
|
1
data/ConfigClient.cs.uid
Normal file
1
data/ConfigClient.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d3s774lnoljcu
|
103
data/SaveClient.cs
Normal file
103
data/SaveClient.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
|
||||
namespace Mr.BrickAdventures.data;
|
||||
|
||||
public sealed class SaveClient
|
||||
{
|
||||
private readonly string _path;
|
||||
private readonly int _version;
|
||||
|
||||
public SaveClient(string path, int version) { _path = path; _version = version; }
|
||||
|
||||
public bool Exists() => FileAccess.FileExists(_path);
|
||||
|
||||
public bool TryLoad(out PlayerState player, out LevelState level) {
|
||||
player = null!; level = null!;
|
||||
if (!Exists()) return false;
|
||||
|
||||
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Read);
|
||||
var dict = (Dictionary)f.GetVar();
|
||||
|
||||
if ((int)dict.GetValueOrDefault("version", -1) != _version) return false;
|
||||
|
||||
player = ToPlayer((Dictionary)dict["player"]);
|
||||
level = ToLevel((Dictionary)dict["level"]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Strict load: requires version + player_state + level_state.
|
||||
// If anything is off, delete the file and act as "no save".
|
||||
public bool TryLoadStrict(out PlayerState player, out LevelState level) {
|
||||
player = default!;
|
||||
level = default!;
|
||||
|
||||
if (!Exists()) return false;
|
||||
|
||||
try {
|
||||
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Read);
|
||||
if (f == null) { Delete(); return false; }
|
||||
|
||||
var dictionary = (Dictionary)f.GetVar();
|
||||
|
||||
|
||||
if (!dictionary.TryGetValue("version", out var v) || (int)v != _version) { Delete(); return false; }
|
||||
|
||||
if (!dictionary.TryGetValue("player_state", out var pObj) || (Dictionary)pObj is not { } p) { Delete(); return false; }
|
||||
if (!dictionary.TryGetValue("level_state", out var lObj) || (Dictionary)lObj is not { } l) { Delete(); return false; }
|
||||
|
||||
player = ToPlayer(p);
|
||||
level = ToLevel(l);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
GD.PushWarning($"SaveClient: load failed — deleting bad save. {e.GetType().Name}: {e.Message}");
|
||||
Delete();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(PlayerState player, LevelState level) {
|
||||
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Write);
|
||||
var dict = new Dictionary {
|
||||
{ "version", _version },
|
||||
{ "player", FromPlayer(player) },
|
||||
{ "level", FromLevel(level) }
|
||||
};
|
||||
f.StoreVar(dict);
|
||||
}
|
||||
|
||||
public void Delete() {
|
||||
if (!Exists()) return;
|
||||
var abs = ProjectSettings.GlobalizePath(_path);
|
||||
var ok = DirAccess.RemoveAbsolute(abs);
|
||||
if (ok != Error.Ok) GD.PushWarning($"SaveClient: failed to delete {_path}: {ok}");
|
||||
}
|
||||
|
||||
private static Dictionary FromPlayer(PlayerState s) => new() { { "coins", s.Coins }, { "lives", s.Lives } };
|
||||
private static PlayerState ToPlayer(Dictionary d) => new() {
|
||||
Coins = d.TryGetValue("coins", out var c) ? (int)c : 0,
|
||||
Lives = d.TryGetValue("lives", out var l) ? (int)l : 3
|
||||
};
|
||||
|
||||
private static Dictionary FromLevel(LevelState s) => new() {
|
||||
{ "current", s.Current },
|
||||
{ "unlocked", new Array<int>(s.Unlocked) },
|
||||
{ "completed", new Array<int>(s.Completed) },
|
||||
};
|
||||
|
||||
private static LevelState ToLevel(Dictionary d) => new() {
|
||||
Current = d.TryGetValue("current", out var cur) ? (int)cur : 0,
|
||||
Unlocked = d.TryGetValue("unlocked", out var ul) && (Array<int>)ul is { } a1 ? a1.ToArray() : [0],
|
||||
Completed = d.TryGetValue("completed", out var cl) && (Array<int>)cl is { } a2 ? a2.ToArray() : [],
|
||||
};
|
||||
}
|
||||
|
||||
public record SaveSnapshot {
|
||||
public required PlayerState PlayerState { get; init; }
|
||||
public required LevelState LevelState { get; init; }
|
||||
}
|
1
data/SaveClient.cs.uid
Normal file
1
data/SaveClient.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bsf45t7m2wa07
|
40
features/level/ExitDoorComponent.cs
Normal file
40
features/level/ExitDoorComponent.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.app;
|
||||
using Mr.BrickAdventures.game.services;
|
||||
|
||||
namespace Mr.BrickAdventures.features.level;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ExitDoorComponent : Area2D
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Export] public CollisionShape2D UnlockIndicator { get; set; } = null!;
|
||||
[Export] public bool Unlocked { get; set; } = false;
|
||||
|
||||
[Dependency] public LevelService Levels => this.DependOn<LevelService>();
|
||||
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
|
||||
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
|
||||
|
||||
public void OnReady() {
|
||||
BodyEntered += OnBodyEntered;
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
private void OnBodyEntered(Node body) {
|
||||
if (!Unlocked) return;
|
||||
if (body is not CharacterBody2D) return;
|
||||
|
||||
var nextIdx = Levels.CompleteAndAdvance();
|
||||
var next = Catalog.Get(nextIdx);
|
||||
if (next != null) Scenes.Load(next); else Scenes.ReturnToMain(Catalog.MainMenu);
|
||||
}
|
||||
|
||||
private void UpdateVisuals() {
|
||||
if (UnlockIndicator != null) UnlockIndicator.Disabled = !Unlocked;
|
||||
}
|
||||
|
||||
public void SetUnlocked(bool value) { Unlocked = value; UpdateVisuals(); }
|
||||
}
|
1
features/level/ExitDoorComponent.cs.uid
Normal file
1
features/level/ExitDoorComponent.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddh0jm0heqtc3
|
34
features/ui/hud/Hud.cs
Normal file
34
features/ui/hud/Hud.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
|
||||
namespace Mr.BrickAdventures.features.ui.hud;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Hud : Node
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Export] public HealthComponent Health { get; set; } = null!;
|
||||
[Node] public Label CoinsLabel { get; set; } = null!;
|
||||
[Node] public ProgressBar HealthBar { get; set; } = null!;
|
||||
[Node] public Label LivesLabel { get; set; } = null!;
|
||||
|
||||
[Dependency] public PlayerRepository Player => this.DependOn<PlayerRepository>();
|
||||
|
||||
public void OnResolved() {
|
||||
CoinsLabel.Text = $"{Tr("COINS_LABEL")}: {Player.Coins}";
|
||||
LivesLabel.Text = $"{Tr("LIVES_LABEL")}: {Player.Lives}";
|
||||
|
||||
Player.CoinsChanged += c => CoinsLabel.Text = $"{Tr("COINS_LABEL")}: {c}";
|
||||
Player.LivesChanged += l => LivesLabel.Text = $"{Tr("LIVES_LABEL")}: {l}";
|
||||
|
||||
if (Health != null) {
|
||||
HealthBar.MaxValue = Health.MaxHealth;
|
||||
HealthBar.Value = Health.Health;
|
||||
Health.HealthChanged += (_, total) => { HealthBar.Value = total; };
|
||||
}
|
||||
}
|
||||
}
|
1
features/ui/hud/Hud.cs.uid
Normal file
1
features/ui/hud/Hud.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c1uwe5e1cfdxl
|
@@ -1,7 +1,7 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://byxf45ukq82pe"]
|
||||
|
||||
[ext_resource type="LabelSettings" uid="uid://rvn5ivivfvv6" path="res://resources/ui/hud_label_settings.tres" id="1_4dsh5"]
|
||||
[ext_resource type="Script" uid="uid://c3pde84b3kdco" path="res://scripts/ui/hud.gd" id="1_ueofj"]
|
||||
[ext_resource type="Script" uid="uid://c1uwe5e1cfdxl" path="res://features/ui/hud/Hud.cs" id="1_m4pq7"]
|
||||
[ext_resource type="FontFile" uid="uid://xm0vbusjr7b7" path="res://fonts/PressStart2P-Regular.ttf" id="1_ygmwt"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mmcdi"]
|
||||
@@ -16,7 +16,7 @@ bg_color = Color(0.47451, 0.47451, 0.47451, 1)
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_22dp1"]
|
||||
bg_color = Color(0.858824, 0.254902, 0.380392, 1)
|
||||
|
||||
[node name="HUD" type="Control" node_paths=PackedStringArray("coins_label", "health_progressbar", "lives_label")]
|
||||
[node name="HUD" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -25,10 +25,7 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
script = ExtResource("1_ueofj")
|
||||
coins_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Coins label")
|
||||
health_progressbar = NodePath("PanelContainer/MarginContainer/HBoxContainer/ProgressBar")
|
||||
lives_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Lives")
|
||||
script = ExtResource("1_m4pq7")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
@@ -57,7 +54,8 @@ text = "HEALTH_LABEL"
|
||||
label_settings = ExtResource("1_4dsh5")
|
||||
uppercase = true
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
[node name="HealthBar" type="ProgressBar" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
@@ -69,7 +67,8 @@ step = 0.1
|
||||
value = 60.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="Lives" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
[node name="LivesLabel" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "LIVES_LABEL"
|
||||
@@ -77,7 +76,8 @@ label_settings = ExtResource("1_4dsh5")
|
||||
horizontal_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Coins label" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
[node name="CoinsLabel" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "COINS_LABEL"
|
26
features/ui/menus/GameOverScreen.cs
Normal file
26
features/ui/menus/GameOverScreen.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.app;
|
||||
|
||||
namespace Mr.BrickAdventures.features.ui.menus;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class GameOverScreen : Control
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Export] public Button RestartButton { get; set; } = null!;
|
||||
[Export] public Button MainMenuButton { get; set; } = null!;
|
||||
[Export] public PackedScene MainMenuScene { get; set; } = null!;
|
||||
|
||||
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
|
||||
|
||||
public void OnReady() {
|
||||
Visible = false;
|
||||
RestartButton.Pressed += () => Scenes.Restart();
|
||||
MainMenuButton.Pressed += () => Scenes.ReturnToMain(MainMenuScene);
|
||||
}
|
||||
|
||||
public void ShowGameOver() => Show();
|
||||
}
|
1
features/ui/menus/GameOverScreen.cs.uid
Normal file
1
features/ui/menus/GameOverScreen.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b36jv878751ta
|
57
features/ui/menus/MainMenu.cs
Normal file
57
features/ui/menus/MainMenu.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.app;
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
using Mr.BrickAdventures.game.services;
|
||||
|
||||
namespace Mr.BrickAdventures.features.ui.menus;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class MainMenu : Control
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Node] public Button NewGameButton { get; set; } = null!;
|
||||
[Node] public Button ContinueButton { get; set; } = null!;
|
||||
[Node] public Button SettingsButton { get; set; } = null!;
|
||||
[Node] public Button CreditsButton { get; set; } = null!;
|
||||
[Node] public Button ExitButton { get; set; } = null!;
|
||||
[Node] public Label VersionLabel { get; set; } = null!;
|
||||
[Export] public Control SettingsControl { get; set; } = null!;
|
||||
[Export] public Control CreditsControl { get; set; } = null!;
|
||||
|
||||
[Dependency] public SaveService Save => this.DependOn<SaveService>();
|
||||
[Dependency] public LevelRepository Levels => this.DependOn<LevelRepository>();
|
||||
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
|
||||
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
|
||||
|
||||
public void OnReady() {
|
||||
VersionLabel.Text = $"v. {ProjectSettings.GetSetting("application/config/version")}";
|
||||
|
||||
NewGameButton.Pressed += OnNewGamePressed;
|
||||
ContinueButton.Pressed += OnContinuePressed;
|
||||
SettingsButton.Pressed += () => SettingsControl.Show();
|
||||
CreditsButton.Pressed += () => CreditsControl.Show();
|
||||
ExitButton.Pressed += () => GetTree().Quit();
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
ContinueButton.Disabled = !Save.Exists();
|
||||
(ContinueButton.Disabled ? NewGameButton : ContinueButton).GrabFocus();
|
||||
}
|
||||
|
||||
private void OnNewGamePressed() {
|
||||
Save.NewGame();
|
||||
Levels.SetCurrent(0);
|
||||
var first = Catalog.First;
|
||||
Scenes.Load(first);
|
||||
}
|
||||
|
||||
private void OnContinuePressed() {
|
||||
if (!Save.TryLoad()) { OnNewGamePressed(); return; }
|
||||
var scene = Catalog.Get(Levels.Current) ?? Catalog.First;
|
||||
Scenes.Load(scene);
|
||||
}
|
||||
}
|
1
features/ui/menus/MainMenu.cs.uid
Normal file
1
features/ui/menus/MainMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://fcsg0e8s36in
|
33
features/ui/menus/PauseMenu.cs
Normal file
33
features/ui/menus/PauseMenu.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.app;
|
||||
using Mr.BrickAdventures.game.services;
|
||||
|
||||
namespace Mr.BrickAdventures.features.ui.menus;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class PauseMenu : Control
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Export] public Button ResumeButton { get; set; } = null!;
|
||||
[Export] public Button RestartButton { get; set; } = null!;
|
||||
[Export] public Button MainMenuButton { get; set; } = null!;
|
||||
|
||||
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
|
||||
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
|
||||
[Dependency] public LevelService Levels => this.DependOn<LevelService>();
|
||||
|
||||
public void OnReady() {
|
||||
Visible = false;
|
||||
ResumeButton.Pressed += () => { GetTree().Paused = false; Hide(); };
|
||||
RestartButton.Pressed += () => { GetTree().Paused = false; Scenes.Restart(); };
|
||||
MainMenuButton.Pressed += () => { GetTree().Paused = false; Scenes.ReturnToMain(Catalog.MainMenu); };
|
||||
}
|
||||
|
||||
public void Toggle() {
|
||||
if (Visible) { GetTree().Paused = false; Hide(); }
|
||||
else { Show(); GetTree().Paused = true; }
|
||||
}
|
||||
}
|
1
features/ui/menus/PauseMenu.cs.uid
Normal file
1
features/ui/menus/PauseMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bwgs02wcfnm8u
|
@@ -1,25 +1,18 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://8b6ol5sssbgo"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://hyfvthdbgjbc" path="res://scripts/ui/main_menu.gd" id="1_epxpl"]
|
||||
[ext_resource type="Script" uid="uid://fcsg0e8s36in" path="res://features/ui/menus/MainMenu.cs" id="1_q8hru"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qv2q0"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="MainMenu" type="Control" node_paths=PackedStringArray("main_menu_control", "new_game_button", "continue_button", "settings_button", "credits_button", "exit_button", "version_label")]
|
||||
[node name="MainMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_epxpl")
|
||||
main_menu_control = NodePath(".")
|
||||
new_game_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/NewGameButton")
|
||||
continue_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/ContinueButton")
|
||||
settings_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/SettingsButton")
|
||||
credits_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/CreditsButton")
|
||||
exit_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/QuitButton")
|
||||
version_label = NodePath("PanelContainer/MarginContainer/VBoxContainer/version")
|
||||
script = ExtResource("1_q8hru")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
@@ -53,31 +46,37 @@ layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ContinueButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "CONTINUE_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="NewGameButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "NEW_GAME_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="SettingsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "SETTINGS_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="CreditsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "CREDITS_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="QuitButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
[node name="ExitButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "QUIT_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="version" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
[node name="VersionLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 8
|
6
features/ui/settings/AudioSettings.cs
Normal file
6
features/ui/settings/AudioSettings.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.features.ui.settings;
|
||||
|
||||
public class AudioSettings
|
||||
{
|
||||
|
||||
}
|
1
features/ui/settings/AudioSettings.cs.uid
Normal file
1
features/ui/settings/AudioSettings.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bnj36dhskiem
|
34
game/repositories/LevelRepository.cs
Normal file
34
game/repositories/LevelRepository.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Mr.BrickAdventures.game.repositories;
|
||||
|
||||
public sealed class LevelRepository
|
||||
{
|
||||
public int Current { get; private set; } = 0;
|
||||
public HashSet<int> Unlocked { get; } = new() { 0 };
|
||||
public HashSet<int> Completed { get; } = new();
|
||||
|
||||
public event Action<int>? CurrentChanged;
|
||||
|
||||
public void SetCurrent(int idx) { Current = idx; CurrentChanged?.Invoke(Current); }
|
||||
public void Unlock(int idx) => Unlocked.Add(idx);
|
||||
public void Complete(int idx) { Completed.Add(idx); Unlock(idx + 1); }
|
||||
|
||||
public LevelState Export() => new() {
|
||||
Current = Current, Unlocked = [..Unlocked], Completed = [..Completed]
|
||||
};
|
||||
public void Load(LevelState s) {
|
||||
Current = s.Current;
|
||||
Unlocked.Clear(); foreach (var i in s.Unlocked) Unlocked.Add(i);
|
||||
Completed.Clear(); foreach (var i in s.Completed) Completed.Add(i);
|
||||
CurrentChanged?.Invoke(Current);
|
||||
}
|
||||
}
|
||||
|
||||
public record LevelState {
|
||||
public int Current;
|
||||
public int[] Unlocked = [];
|
||||
public int[] Completed = [];
|
||||
}
|
1
game/repositories/LevelRepository.cs.uid
Normal file
1
game/repositories/LevelRepository.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d0604lmwpadt5
|
25
game/repositories/PlayerRepository.cs
Normal file
25
game/repositories/PlayerRepository.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Mr.BrickAdventures.game.repositories;
|
||||
|
||||
public sealed class PlayerRepository
|
||||
{
|
||||
public int Coins { get; private set; } = 0;
|
||||
public int Lives { get; private set; } = 3;
|
||||
|
||||
public event Action<int>? CoinsChanged;
|
||||
public event Action<int>? LivesChanged;
|
||||
|
||||
public void SetCoins(int value) { Coins = Math.Max(0, value); CoinsChanged?.Invoke(Coins); }
|
||||
public void AddCoins(int amount) { SetCoins(Coins + amount); }
|
||||
public void RemoveCoins(int amount){ SetCoins(Coins - amount); }
|
||||
|
||||
public void SetLives(int value) { Lives = value; LivesChanged?.Invoke(Lives); }
|
||||
public void AddLives(int amount) { SetLives(Lives + amount); }
|
||||
public void RemoveLives(int amount){ SetLives(Lives - amount); }
|
||||
|
||||
public PlayerState Export() => new() { Coins = Coins, Lives = Lives };
|
||||
public void Load(PlayerState s) { SetCoins(s.Coins); SetLives(s.Lives); }
|
||||
}
|
||||
|
||||
public record PlayerState { public int Coins; public int Lives; }
|
1
game/repositories/PlayerRepository.cs.uid
Normal file
1
game/repositories/PlayerRepository.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d1dijkt574x4b
|
6
game/repositories/SessionRepository.cs
Normal file
6
game/repositories/SessionRepository.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.game.repositories;
|
||||
|
||||
public sealed class SessionRepository
|
||||
{
|
||||
|
||||
}
|
1
game/repositories/SessionRepository.cs.uid
Normal file
1
game/repositories/SessionRepository.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b550hcqugygv0
|
6
game/repositories/SettingsRepository.cs
Normal file
6
game/repositories/SettingsRepository.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.game.repositories;
|
||||
|
||||
public class SettingsRepository
|
||||
{
|
||||
|
||||
}
|
1
game/repositories/SettingsRepository.cs.uid
Normal file
1
game/repositories/SettingsRepository.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bk11iduo7bg2h
|
6
game/repositories/SkillsRepository.cs
Normal file
6
game/repositories/SkillsRepository.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.game.repositories;
|
||||
|
||||
public class SkillsRepository
|
||||
{
|
||||
|
||||
}
|
1
game/repositories/SkillsRepository.cs.uid
Normal file
1
game/repositories/SkillsRepository.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cymx7mtmdblun
|
21
game/services/LevelService.cs
Normal file
21
game/services/LevelService.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
|
||||
namespace Mr.BrickAdventures.game.services;
|
||||
|
||||
public sealed class LevelService
|
||||
{
|
||||
private readonly LevelRepository _levels;
|
||||
public LevelService(LevelRepository levels) => _levels = levels;
|
||||
|
||||
public int CompleteAndAdvance() {
|
||||
var cur = _levels.Current;
|
||||
_levels.Complete(cur);
|
||||
var next = cur + 1;
|
||||
_levels.SetCurrent(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
public void StartNew() {
|
||||
_levels.Load(new LevelState { Current = 0, Unlocked = new [] { 0 }, Completed = [] });
|
||||
}
|
||||
}
|
1
game/services/LevelService.cs.uid
Normal file
1
game/services/LevelService.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b2tsi3cjnh5xq
|
32
game/services/SaveService.cs
Normal file
32
game/services/SaveService.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Mr.BrickAdventures.data;
|
||||
using Mr.BrickAdventures.game.repositories;
|
||||
|
||||
namespace Mr.BrickAdventures.game.services;
|
||||
|
||||
public sealed class SaveService
|
||||
{
|
||||
private readonly PlayerRepository _players;
|
||||
private readonly LevelRepository _levels;
|
||||
private readonly SaveClient _save;
|
||||
|
||||
public SaveService(PlayerRepository players, LevelRepository levels, SaveClient save) {
|
||||
_players = players; _levels = levels; _save = save;
|
||||
}
|
||||
|
||||
|
||||
public bool TryLoad() {
|
||||
if (!_save.TryLoad(out var p, out var l)) return false;
|
||||
_players.Load(p);
|
||||
_levels.Load(l);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Save() => _save.Save(_players.Export(), _levels.Export());
|
||||
public bool Exists() => _save.Exists();
|
||||
|
||||
public void NewGame() {
|
||||
_players.Load(new PlayerState { Coins = 0, Lives = 3 });
|
||||
_levels.Load(new LevelState { Current = 0, Unlocked = [0], Completed = [] });
|
||||
Save();
|
||||
}
|
||||
}
|
1
game/services/SaveService.cs.uid
Normal file
1
game/services/SaveService.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dxqkxlkkivxog
|
6
game/services/SkillService.cs
Normal file
6
game/services/SkillService.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Mr.BrickAdventures.game.services;
|
||||
|
||||
public sealed class SkillService
|
||||
{
|
||||
|
||||
}
|
1
game/services/SkillService.cs.uid
Normal file
1
game/services/SkillService.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dim21hs12wdi5
|
@@ -32,7 +32,7 @@
|
||||
[ext_resource type="PackedScene" uid="uid://bg76mtpcmfm2j" path="res://objects/ui/charging_bar_layer.tscn" id="28_3f5nm"]
|
||||
[ext_resource type="PackedScene" uid="uid://b12tppjkkqpt4" path="res://objects/fxs/hit_particles.tscn" id="28_jh5m0"]
|
||||
[ext_resource type="Script" uid="uid://ceq8n7yw7qxpi" path="res://scripts/components/hit_component.gd" id="29_jh5m0"]
|
||||
[ext_resource type="Script" uid="uid://c1wtrgw0x77xo" path="res://scripts/components/platform_movement.gd" id="31_xoue7"]
|
||||
[ext_resource type="Script" uid="uid://cflncpa377l8l" path="res://scripts/components/platform_movement.gd" id="31_xoue7"]
|
||||
[ext_resource type="AudioStream" uid="uid://dyev46uqusimi" path="res://sfx/shoot.wav" id="32_x2b7c"]
|
||||
[ext_resource type="Script" uid="uid://d1ctdx52gskv1" path="res://scripts/components/ship_shooter.gd" id="34_gwc8i"]
|
||||
[ext_resource type="PackedScene" uid="uid://dtem8jgcyoqar" path="res://objects/entities/green_laser.tscn" id="36_oxudy"]
|
||||
|
@@ -62,9 +62,6 @@ process_material = SubResource("ParticleProcessMaterial_lgb3u")
|
||||
|
||||
[node name="UI Layer" parent="." instance=ExtResource("2_lbnsn")]
|
||||
|
||||
[node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("player_health")]
|
||||
player_health = NodePath("../../Brick Player/HealthComponent")
|
||||
|
||||
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
|
||||
current_level = ExtResource("4_c2yv5")
|
||||
nodes_to_disable = [NodePath("../../Brick Player")]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=11 format=3 uid="uid://6foggu31cu14"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://byxf45ukq82pe" path="res://objects/ui/hud.tscn" id="1_tgtfe"]
|
||||
[ext_resource type="PackedScene" uid="uid://byxf45ukq82pe" path="res://features/ui/hud/hud.tscn" id="1_tgtfe"]
|
||||
[ext_resource type="PackedScene" uid="uid://dulkm3ah4tm0u" path="res://objects/ui/death_screen.tscn" id="2_ln68j"]
|
||||
[ext_resource type="Script" uid="uid://cp68km8bykymb" path="res://scripts/resources/level_resource.gd" id="3_5kt5k"]
|
||||
[ext_resource type="PackedScene" uid="uid://wmw6gaisyrvx" path="res://objects/ui/game_over_screen.tscn" id="4_11xmk"]
|
||||
@@ -34,9 +34,8 @@ visible = false
|
||||
offset_top = 32.0
|
||||
components_to_disable = [null]
|
||||
|
||||
[node name="Pause menu" parent="." node_paths=PackedStringArray("settings_menu") instance=ExtResource("6_1q4vn")]
|
||||
[node name="Pause menu" parent="." instance=ExtResource("6_1q4vn")]
|
||||
visible = false
|
||||
settings_menu = NodePath("../Settings menu")
|
||||
|
||||
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("7_hkjav")]
|
||||
visible = false
|
||||
|
@@ -1,12 +1,11 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://i6mnjbjcoqe5"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://i6mnjbjcoqe5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cugifchx6jhuk" path="res://scripts/ui/pause_menu.gd" id="1_aktha"]
|
||||
[ext_resource type="PackedScene" uid="uid://cl00e2ocomk3m" path="res://scenes/main_menu.tscn" id="2_h4pd5"]
|
||||
[ext_resource type="Script" uid="uid://bwgs02wcfnm8u" path="res://features/ui/menus/PauseMenu.cs" id="1_ljtns"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4ivv"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="Pause menu" type="Control" node_paths=PackedStringArray("pause_menu_control", "resume_button", "quit_button", "settings_button", "exit_to_menu_button")]
|
||||
[node name="Pause menu" type="Control" node_paths=PackedStringArray("ResumeButton", "RestartButton", "MainMenuButton")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -15,13 +14,10 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 6
|
||||
size_flags_vertical = 6
|
||||
script = ExtResource("1_aktha")
|
||||
pause_menu_control = NodePath(".")
|
||||
resume_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
|
||||
quit_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Quit game Button")
|
||||
settings_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
|
||||
exit_to_menu_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Exit to menu Button")
|
||||
exit_to_menu_scene = ExtResource("2_h4pd5")
|
||||
script = ExtResource("1_ljtns")
|
||||
ResumeButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
|
||||
RestartButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
|
||||
MainMenuButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Exit to menu Button")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
|
@@ -19,7 +19,7 @@ config/version="in-dev"
|
||||
run/main_scene="uid://cl00e2ocomk3m"
|
||||
config/use_custom_user_dir=true
|
||||
config/custom_user_dir_name="MrBrickAdventures"
|
||||
config/features=PackedStringArray("4.4", "GL Compatibility")
|
||||
config/features=PackedStringArray("4.4", "C#", "GL Compatibility")
|
||||
run/max_fps=180
|
||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||
boot_splash/show_image=false
|
||||
|
@@ -66,9 +66,6 @@ process_material = SubResource("ParticleProcessMaterial_lgb3u")
|
||||
|
||||
[node name="UI Layer" parent="." instance=ExtResource("3_4fsls")]
|
||||
|
||||
[node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("player_health")]
|
||||
player_health = NodePath("../../Brick Player/HealthComponent")
|
||||
|
||||
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
|
||||
current_level = ExtResource("4_onnch")
|
||||
nodes_to_disable = [NodePath("../../Brick Player")]
|
||||
|
@@ -1,27 +1,38 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://cl00e2ocomk3m"]
|
||||
[gd_scene load_steps=12 format=3 uid="uid://cl00e2ocomk3m"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://objects/ui/main_menu.tscn" id="1_ekxnf"]
|
||||
[ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://features/ui/menus/main_menu.tscn" id="1_ekxnf"]
|
||||
[ext_resource type="Script" uid="uid://dg2l7cw6da4vb" path="res://common/AppRoot.cs" id="1_rtw2f"]
|
||||
[ext_resource type="PackedScene" uid="uid://y0ae6e7t70fj" path="res://objects/ui/settings_menu.tscn" id="2_bqqt6"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwgmrcyj4mvu" path="res://objects/ui/credits.tscn" id="3_bqqt6"]
|
||||
[ext_resource type="PackedScene" uid="uid://chqb11pfoqmeb" path="res://scenes/level_village_2.tscn" id="3_lgwnu"]
|
||||
[ext_resource type="PackedScene" uid="uid://bol7g83v2accs" path="res://scenes/level_village_1.tscn" id="3_oa1go"]
|
||||
[ext_resource type="PackedScene" uid="uid://b5fx1vdfky307" path="res://objects/ui/audio_settings.tscn" id="4_8ln24"]
|
||||
[ext_resource type="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/level_village_3.tscn" id="4_flqon"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhad760x3vvco" path="res://scenes/level_village_4.tscn" id="5_rcqid"]
|
||||
[ext_resource type="PackedScene" uid="uid://cvfsbiy5ggrpg" path="res://objects/ui/input_settings.tscn" id="5_rtw2f"]
|
||||
[ext_resource type="PackedScene" uid="uid://dagpmlgvr262d" path="res://scenes/level_forest_5.tscn" id="6_1ajci"]
|
||||
|
||||
[node name="Main menu" type="CanvasLayer"]
|
||||
[node name="AppRoot" type="Node2D"]
|
||||
script = ExtResource("1_rtw2f")
|
||||
_levels = Array[PackedScene]([ExtResource("3_oa1go"), ExtResource("3_lgwnu"), ExtResource("4_flqon"), ExtResource("5_rcqid"), ExtResource("6_1ajci")])
|
||||
_mainMenu = null
|
||||
|
||||
[node name="MainMenu" parent="." node_paths=PackedStringArray("settings_control", "credits_control") instance=ExtResource("1_ekxnf")]
|
||||
settings_control = NodePath("../Settings menu")
|
||||
credits_control = NodePath("../Credits")
|
||||
[node name="Main menu" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("2_bqqt6")]
|
||||
[node name="MainMenu" parent="Main menu" node_paths=PackedStringArray("SettingsControl", "CreditsControl") instance=ExtResource("1_ekxnf")]
|
||||
SettingsControl = NodePath("../Settings menu")
|
||||
CreditsControl = NodePath("../Credits")
|
||||
|
||||
[node name="Settings menu" parent="Main menu" node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("2_bqqt6")]
|
||||
visible = false
|
||||
input_settings = NodePath("../Input Settings")
|
||||
audio_settings = NodePath("../Audio settings")
|
||||
|
||||
[node name="Credits" parent="." instance=ExtResource("3_bqqt6")]
|
||||
[node name="Credits" parent="Main menu" instance=ExtResource("3_bqqt6")]
|
||||
visible = false
|
||||
|
||||
[node name="Audio settings" parent="." instance=ExtResource("4_8ln24")]
|
||||
[node name="Audio settings" parent="Main menu" instance=ExtResource("4_8ln24")]
|
||||
visible = false
|
||||
|
||||
[node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")]
|
||||
[node name="Input Settings" parent="Main menu" instance=ExtResource("5_rtw2f")]
|
||||
visible = false
|
||||
|
70
scripts/Resources/ChargeThrowInputResource.cs
Normal file
70
scripts/Resources/ChargeThrowInputResource.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public partial class ChargeThrowInputResource : ThrowInputResource
|
||||
{
|
||||
[Export] public float MinPower { get; set; } = 0.5f;
|
||||
[Export] public float MaxPower { get; set; } = 2.0f;
|
||||
[Export] public float MaxChargeTime { get; set; } = 2.0f;
|
||||
[Export] public float MinChargeDuration { get; set; } = 0.1f;
|
||||
|
||||
private bool _isCharging = false;
|
||||
private float _chargeStartTime = 0f;
|
||||
|
||||
[Signal] public delegate void ChargeStartedEventHandler();
|
||||
[Signal] public delegate void ChargeUpdatedEventHandler(float chargeRatio);
|
||||
[Signal] public delegate void ChargeStoppedEventHandler();
|
||||
|
||||
public override void ProcessInput(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed("attack"))
|
||||
{
|
||||
_isCharging = true;
|
||||
_chargeStartTime = Time.GetTicksMsec() / 1000f;
|
||||
EmitSignalChargeStarted();
|
||||
}
|
||||
|
||||
if (@event.IsActionReleased("attack") && _isCharging)
|
||||
{
|
||||
var power = CalculatePower();
|
||||
_isCharging = false;
|
||||
EmitSignalThrowRequested(power);
|
||||
EmitSignalChargeStopped();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(double delta)
|
||||
{
|
||||
if (!_isCharging) return;
|
||||
|
||||
var t = Mathf.Clamp(GetChargeRatio(), MinPower, MaxPower);
|
||||
EmitSignalChargeUpdated(t);
|
||||
}
|
||||
|
||||
public override bool SupportsCharging()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private float CalculatePower()
|
||||
{
|
||||
var now = Time.GetTicksMsec() / 1000f;
|
||||
var heldTime = now - _chargeStartTime;
|
||||
if (heldTime < MinChargeDuration)
|
||||
return MinPower;
|
||||
|
||||
var t = Mathf.Clamp(heldTime / MaxChargeTime, 0f, 1f);
|
||||
return Mathf.Lerp(MinPower, MaxPower, t);
|
||||
}
|
||||
|
||||
private float GetChargeRatio()
|
||||
{
|
||||
if (!_isCharging) return MinPower;
|
||||
|
||||
var now = Time.GetTicksMsec() / 1000f;
|
||||
var heldTime = now - _chargeStartTime;
|
||||
var t = Mathf.Clamp(heldTime / MaxChargeTime, 0f, 1f);
|
||||
return Mathf.Lerp(MinPower, MaxPower, t);
|
||||
}
|
||||
}
|
1
scripts/Resources/ChargeThrowInputResource.cs.uid
Normal file
1
scripts/Resources/ChargeThrowInputResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dtpdh4jp51jis
|
9
scripts/Resources/CollectableResource.cs
Normal file
9
scripts/Resources/CollectableResource.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public partial class CollectableResource : Resource
|
||||
{
|
||||
[Export] public Variant Amount { get; set; } = 0.0;
|
||||
[Export] public CollectableType Type { get; set; }
|
||||
}
|
1
scripts/Resources/CollectableResource.cs.uid
Normal file
1
scripts/Resources/CollectableResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://gptsgaw3agkf
|
8
scripts/Resources/CollectableType.cs
Normal file
8
scripts/Resources/CollectableType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public enum CollectableType
|
||||
{
|
||||
Coin,
|
||||
Kid,
|
||||
Health,
|
||||
}
|
1
scripts/Resources/CollectableType.cs.uid
Normal file
1
scripts/Resources/CollectableType.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2ql8wj3vfeke
|
19
scripts/Resources/SkillData.cs
Normal file
19
scripts/Resources/SkillData.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public partial class SkillData : Resource
|
||||
{
|
||||
[Export] public string Name { get; set; } = "New Skill";
|
||||
[Export] public string Description { get; set; } = "New Skill";
|
||||
[Export] public Dictionary<string, Variant> Config { get; set; } = new();
|
||||
[Export] public int Cost { get; set; } = 0;
|
||||
[Export] public Texture2D Icon { get; set; }
|
||||
[Export] public bool IsActive { get; set; } = false;
|
||||
[Export] public int Level { get; set; } = 1;
|
||||
[Export] public int MaxLevel { get; set; } = 1;
|
||||
[Export] public SkillType Type { get; set; } = SkillType.Throw;
|
||||
[Export] public PackedScene Node { get; set; }
|
||||
}
|
1
scripts/Resources/SkillData.cs.uid
Normal file
1
scripts/Resources/SkillData.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d4crrfmbgxnqf
|
8
scripts/Resources/SkillType.cs
Normal file
8
scripts/Resources/SkillType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public enum SkillType
|
||||
{
|
||||
Attack,
|
||||
Throw,
|
||||
Misc,
|
||||
}
|
1
scripts/Resources/SkillType.cs.uid
Normal file
1
scripts/Resources/SkillType.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://sma20qug2r0q
|
10
scripts/Resources/StatusEffectDataResource.cs
Normal file
10
scripts/Resources/StatusEffectDataResource.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public partial class StatusEffectDataResource : Resource
|
||||
{
|
||||
[Export] public float Duration { get; set; } = 1f;
|
||||
[Export] public float DamagePerSecond { get; set; } = 0.25f;
|
||||
[Export] public StatusEffectType Type { get; set; }
|
||||
}
|
1
scripts/Resources/StatusEffectDataResource.cs.uid
Normal file
1
scripts/Resources/StatusEffectDataResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://pw0pu6gb21y2
|
8
scripts/Resources/StatusEffectType.cs
Normal file
8
scripts/Resources/StatusEffectType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public enum StatusEffectType
|
||||
{
|
||||
None,
|
||||
Fire,
|
||||
Ice
|
||||
}
|
1
scripts/Resources/StatusEffectType.cs.uid
Normal file
1
scripts/Resources/StatusEffectType.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b0a7k7mse3l68
|
20
scripts/Resources/TapThrowInputResource.cs
Normal file
20
scripts/Resources/TapThrowInputResource.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.interfaces;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public partial class TapThrowInputResource : ThrowInputResource
|
||||
{
|
||||
public override void Update(double delta)
|
||||
{
|
||||
if (Input.IsActionPressed("attack"))
|
||||
{
|
||||
EmitSignalThrowRequested(1f);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsCharging()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
1
scripts/Resources/TapThrowInputResource.cs.uid
Normal file
1
scripts/Resources/TapThrowInputResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cx7ryqxemgs56
|
24
scripts/Resources/ThrowInputResource.cs
Normal file
24
scripts/Resources/ThrowInputResource.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.interfaces;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
public abstract partial class ThrowInputResource : Resource, IThrowInput
|
||||
{
|
||||
[Signal] public delegate void ThrowRequestedEventHandler(float powerMultiplier = 1f);
|
||||
|
||||
public virtual void ProcessInput(InputEvent @event)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual void Update(double delta)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool SupportsCharging()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
1
scripts/Resources/ThrowInputResource.cs.uid
Normal file
1
scripts/Resources/ThrowInputResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://mnn5wy5cyr4m
|
15
scripts/Screenshot.cs
Normal file
15
scripts/Screenshot.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts;
|
||||
|
||||
public partial class Screenshot : Node
|
||||
{
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!OS.IsDebugBuild() || !Input.IsActionJustPressed("screenshot")) return;
|
||||
var img = GetViewport().GetTexture().GetImage();
|
||||
var id = OS.GetUniqueId() + "_" + Time.GetDatetimeStringFromSystem();
|
||||
var path = "user://screenshots/screenshot_" + id + ".png";
|
||||
img.SavePng(path);
|
||||
}
|
||||
}
|
1
scripts/Screenshot.cs.uid
Normal file
1
scripts/Screenshot.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://chrhjch4ymfvr
|
144
scripts/SkillManager.cs
Normal file
144
scripts/SkillManager.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts;
|
||||
|
||||
public partial class SkillManager : Node
|
||||
{
|
||||
private GameManager _gameManager;
|
||||
[Export] public Array<SkillData> AvailableSkills { get; set; } = [];
|
||||
|
||||
public Dictionary ActiveComponents { get; private set; } = new();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
ApplyUnlockedSkills();
|
||||
}
|
||||
|
||||
public void AddSkill(SkillData skillData)
|
||||
{
|
||||
if (ActiveComponents.ContainsKey(skillData.Name))
|
||||
return;
|
||||
|
||||
if (skillData.Type == SkillType.Throw)
|
||||
{
|
||||
var unlocked = _gameManager.GetUnlockedSkills();
|
||||
foreach (var skill in unlocked)
|
||||
{
|
||||
SkillData data = null;
|
||||
foreach (var s in AvailableSkills)
|
||||
{
|
||||
if (s == (SkillData)skill)
|
||||
{
|
||||
data = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data != null && data.Type == SkillType.Throw)
|
||||
RemoveSkill(data.Name);
|
||||
}
|
||||
}
|
||||
|
||||
var instance = skillData.Node.Instantiate();
|
||||
foreach (var key in skillData.Config.Keys)
|
||||
{
|
||||
if (instance.HasMethod("get")) // rough presence check
|
||||
{
|
||||
var value = skillData.Config[key];
|
||||
var parent = GetParent();
|
||||
|
||||
if (value.VariantType == Variant.Type.NodePath)
|
||||
{
|
||||
var np = (NodePath)value;
|
||||
if (parent.HasNode(np))
|
||||
value = parent.GetNode(np);
|
||||
else if (instance.HasNode(np))
|
||||
value = instance.GetNode(np);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set via property if exists
|
||||
instance.Set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
Owner.AddChild(instance);
|
||||
ActiveComponents[skillData.Name] = instance;
|
||||
}
|
||||
|
||||
public void RemoveSkill(string skillName)
|
||||
{
|
||||
if (!ActiveComponents.TryGetValue(skillName, out var component))
|
||||
return;
|
||||
|
||||
var inst = (Node)component;
|
||||
if (IsInstanceValid(inst))
|
||||
inst.QueueFree();
|
||||
|
||||
var skills = _gameManager.GetUnlockedSkills();
|
||||
foreach (SkillData s in skills)
|
||||
{
|
||||
if (s.Name == skillName)
|
||||
{
|
||||
s.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ActiveComponents.Remove(skillName);
|
||||
}
|
||||
|
||||
public void ApplyUnlockedSkills()
|
||||
{
|
||||
foreach (var sd in AvailableSkills)
|
||||
{
|
||||
if (_gameManager.IsSkillUnlocked(sd))
|
||||
{
|
||||
GD.Print("Applying skill: ", sd.Name);
|
||||
CallDeferred(MethodName.AddSkill, sd);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveSkill(sd.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SkillData GetSkillByName(string skillName)
|
||||
{
|
||||
foreach (var sd in AvailableSkills)
|
||||
if (sd.Name == skillName) return sd;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ActivateSkill(SkillData skill)
|
||||
{
|
||||
if (!ActiveComponents.ContainsKey(skill.Name))
|
||||
{
|
||||
AddSkill(skill);
|
||||
skill.IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void DeactivateSkill(SkillData skill)
|
||||
{
|
||||
if (ActiveComponents.ContainsKey(skill.Name))
|
||||
{
|
||||
RemoveSkill(skill.Name);
|
||||
skill.IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleSkillActivation(SkillData skill)
|
||||
{
|
||||
if (skill == null) return;
|
||||
|
||||
if (ActiveComponents.ContainsKey(skill.Name))
|
||||
DeactivateSkill(skill);
|
||||
else
|
||||
ActivateSkill(skill);
|
||||
}
|
||||
}
|
1
scripts/SkillManager.cs.uid
Normal file
1
scripts/SkillManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://di572axt0c3s8
|
102
scripts/UI/AudioSettings.cs
Normal file
102
scripts/UI/AudioSettings.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class AudioSettings : Node
|
||||
{
|
||||
[Export] public Slider MasterVolumeSlider { get; set; }
|
||||
[Export] public Slider MusicVolumeSlider { get; set; }
|
||||
[Export] public Slider SfxVolumeSlider { get; set; }
|
||||
[Export] public Control AudioSettingsControl { get; set; }
|
||||
[Export] public float MuteThreshold { get; set; } = -20f;
|
||||
|
||||
private UIManager _uiManager;
|
||||
private ConfigFileHandler _configFileHandler;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_uiManager = GetNode<UIManager>("/root/UIManager");
|
||||
_configFileHandler = GetNode<ConfigFileHandler>("/root/ConfigFileHandler");
|
||||
Initialize();
|
||||
MasterVolumeSlider.ValueChanged += OnMasterVolumeChanged;
|
||||
MusicVolumeSlider.ValueChanged += OnMusicVolumeChanged;
|
||||
SfxVolumeSlider.ValueChanged += OnSfxVolumeChanged;
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (!@event.IsActionReleased("ui_cancel")) return;
|
||||
if (!_uiManager.IsScreenOnTop(AudioSettingsControl)) return;
|
||||
|
||||
SaveSettings();
|
||||
_uiManager.PopScreen();
|
||||
}
|
||||
|
||||
private void OnSfxVolumeChanged(double value)
|
||||
{
|
||||
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("sfx"), (float)value);
|
||||
HandleMute(AudioServer.GetBusIndex("sfx"), (float)value);
|
||||
}
|
||||
|
||||
private void OnMusicVolumeChanged(double value)
|
||||
{
|
||||
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("music"), (float)value);
|
||||
HandleMute(AudioServer.GetBusIndex("music"), (float)value);
|
||||
}
|
||||
|
||||
private void OnMasterVolumeChanged(double value)
|
||||
{
|
||||
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), (float)value);
|
||||
HandleMute(AudioServer.GetBusIndex("Master"), (float)value);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var volumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("Master"));
|
||||
MasterVolumeSlider.Value = volumeDb;
|
||||
MasterVolumeSlider.MinValue = MuteThreshold;
|
||||
MasterVolumeSlider.MaxValue = 0f;
|
||||
|
||||
var musicVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("music"));
|
||||
MusicVolumeSlider.Value = musicVolumeDb;
|
||||
MusicVolumeSlider.MinValue = MuteThreshold;
|
||||
MusicVolumeSlider.MaxValue = 0f;
|
||||
|
||||
var sfxVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("sfx"));
|
||||
SfxVolumeSlider.Value = sfxVolumeDb;
|
||||
SfxVolumeSlider.MinValue = MuteThreshold;
|
||||
SfxVolumeSlider.MaxValue = 0f;
|
||||
}
|
||||
|
||||
private void HandleMute(int busIndex, float value)
|
||||
{
|
||||
AudioServer.SetBusMute(busIndex, value <= MuteThreshold);
|
||||
}
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
var settingsConfig = _configFileHandler.SettingsConfig;
|
||||
settingsConfig.SetValue("audio_settings", "master_volume", MasterVolumeSlider.Value);
|
||||
settingsConfig.SetValue("audio_settings", "music_volume", MusicVolumeSlider.Value);
|
||||
settingsConfig.SetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value);
|
||||
settingsConfig.SetValue("audio_settings", "mute_threshold", MuteThreshold);
|
||||
settingsConfig.Save(ConfigFileHandler.SettingsPath);
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
var settingsConfig = _configFileHandler.SettingsConfig;
|
||||
if (!settingsConfig.HasSection("audio_settings")) return;
|
||||
|
||||
var masterVolume = (float)settingsConfig.GetValue("audio_settings", "master_volume", MasterVolumeSlider.Value);
|
||||
var musicVolume = (float)settingsConfig.GetValue("audio_settings", "music_volume", MusicVolumeSlider.Value);
|
||||
var sfxVolume = (float)settingsConfig.GetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value);
|
||||
var muteThreshold = (float)settingsConfig.GetValue("audio_settings", "mute_threshold", MuteThreshold);
|
||||
|
||||
MasterVolumeSlider.Value = masterVolume;
|
||||
MusicVolumeSlider.Value = musicVolume;
|
||||
SfxVolumeSlider.Value = sfxVolume;
|
||||
MuteThreshold = muteThreshold;
|
||||
}
|
||||
}
|
1
scripts/UI/AudioSettings.cs.uid
Normal file
1
scripts/UI/AudioSettings.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://g61qqsymqfxd
|
81
scripts/UI/ChargeProgressBar.cs
Normal file
81
scripts/UI/ChargeProgressBar.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class ChargeProgressBar : Node
|
||||
{
|
||||
[Export] public ProgressBar ProgressBar { get; set; }
|
||||
[Export] public BrickThrowComponent ThrowComponent { get; set; }
|
||||
|
||||
private ChargeThrowInputResource _throwInput;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Owner.ChildEnteredTree += OnNodeEntered;
|
||||
ProgressBar.Hide();
|
||||
SetupDependencies();
|
||||
}
|
||||
|
||||
private void OnNodeEntered(Node node)
|
||||
{
|
||||
if (node is not BrickThrowComponent throwComponent || ThrowComponent != null) return;
|
||||
ThrowComponent = throwComponent;
|
||||
SetupDependencies();
|
||||
}
|
||||
|
||||
private void SetupDependencies()
|
||||
{
|
||||
if (ThrowComponent.ThrowInputBehavior is ChargeThrowInputResource throwInput)
|
||||
{
|
||||
_throwInput = throwInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
_throwInput = null;
|
||||
}
|
||||
|
||||
if (_throwInput == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_throwInput.SupportsCharging())
|
||||
{
|
||||
ProgressBar.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
SetupProgressBar();
|
||||
|
||||
_throwInput.ChargeStarted += OnChargeStarted;
|
||||
_throwInput.ChargeStopped += OnChargeStopped;
|
||||
_throwInput.ChargeUpdated += OnChargeUpdated;
|
||||
}
|
||||
|
||||
private void SetupProgressBar()
|
||||
{
|
||||
ProgressBar.MinValue = _throwInput.MinPower;
|
||||
ProgressBar.MaxValue = _throwInput.MaxPower;
|
||||
ProgressBar.Value = _throwInput.MinPower;
|
||||
ProgressBar.Step = 0.01f;
|
||||
ProgressBar.Hide();
|
||||
}
|
||||
|
||||
private void OnChargeStarted()
|
||||
{
|
||||
ProgressBar.Show();
|
||||
}
|
||||
|
||||
private void OnChargeStopped()
|
||||
{
|
||||
ProgressBar.Hide();
|
||||
}
|
||||
|
||||
private void OnChargeUpdated(float chargeRatio)
|
||||
{
|
||||
ProgressBar.Value = chargeRatio;
|
||||
ProgressBar.Show();
|
||||
}
|
||||
}
|
1
scripts/UI/ChargeProgressBar.cs.uid
Normal file
1
scripts/UI/ChargeProgressBar.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dev2q1228otm2
|
23
scripts/UI/Credits.cs
Normal file
23
scripts/UI/Credits.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class Credits : Control
|
||||
{
|
||||
private UIManager _uiManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_uiManager = GetNode<UIManager>("/root/UIManager");
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (!@event.IsActionPressed("ui_cancel")) return;
|
||||
if (_uiManager != null && _uiManager.IsScreenOnTop(this))
|
||||
{
|
||||
_uiManager.PopScreen();
|
||||
}
|
||||
}
|
||||
}
|
1
scripts/UI/Credits.cs.uid
Normal file
1
scripts/UI/Credits.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://daevj4uootmcw
|
39
scripts/UI/GameOverScreen.cs
Normal file
39
scripts/UI/GameOverScreen.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class GameOverScreen : Node
|
||||
{
|
||||
[Export] public Control GameOverPanel { get; set; }
|
||||
[Export] public Button RestartButton { get; set; }
|
||||
[Export] public Button MainMenuButton { get; set; }
|
||||
[Export] public PackedScene MainMenuScene { get; set; }
|
||||
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
RestartButton.Pressed += OnRestartClicked;
|
||||
MainMenuButton.Pressed += OnMainMenuClicked;
|
||||
}
|
||||
|
||||
private void OnMainMenuClicked()
|
||||
{
|
||||
_gameManager.ResetPlayerState();
|
||||
GetTree().ChangeSceneToPacked(MainMenuScene);
|
||||
}
|
||||
|
||||
private void OnRestartClicked()
|
||||
{
|
||||
_gameManager.RestartGame();
|
||||
}
|
||||
|
||||
public void OnPlayerDeath()
|
||||
{
|
||||
if (_gameManager == null || _gameManager.GetLives() != 0) return;
|
||||
|
||||
GameOverPanel.Show();
|
||||
}
|
||||
}
|
1
scripts/UI/GameOverScreen.cs.uid
Normal file
1
scripts/UI/GameOverScreen.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://u4qfsx4w72dv
|
67
scripts/UI/MainMenu.cs
Normal file
67
scripts/UI/MainMenu.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class MainMenu : Node
|
||||
{
|
||||
[Export] public Control MainMenuControl { get; set; }
|
||||
[Export] public Button NewGameButton { get; set; }
|
||||
[Export] public Button ContinueButton { get; set; }
|
||||
[Export] public Button SettingsButton { get; set; }
|
||||
[Export] public Button CreditsButton { get; set; }
|
||||
[Export] public Button ExitButton { get; set; }
|
||||
[Export] public Label VersionLabel { get; set; }
|
||||
[Export] public Control SettingsControl { get; set; }
|
||||
[Export] public Control CreditsControl { get; set; }
|
||||
|
||||
private SaveSystem _saveSystem;
|
||||
private GameManager _gameManager;
|
||||
private UIManager _uiManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_saveSystem = GetNode<SaveSystem>("/root/SaveSystem");
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_uiManager = GetNode<UIManager>("/root/UIManager");
|
||||
|
||||
NewGameButton.Pressed += OnNewGamePressed;
|
||||
ContinueButton.Pressed += OnContinuePressed;
|
||||
SettingsButton.Pressed += OnSettingsPressed;
|
||||
CreditsButton.Pressed += OnCreditsPressed;
|
||||
ExitButton.Pressed += OnExitPressed;
|
||||
|
||||
VersionLabel.Text = $"v. {ProjectSettings.GetSetting("application/config/version")}";
|
||||
ContinueButton.Disabled = !_saveSystem.CheckSaveExists();
|
||||
|
||||
if (_saveSystem.CheckSaveExists())
|
||||
ContinueButton.GrabFocus();
|
||||
else
|
||||
NewGameButton.GrabFocus();
|
||||
}
|
||||
|
||||
private void OnExitPressed()
|
||||
{
|
||||
_gameManager.QuitGame();
|
||||
}
|
||||
|
||||
private void OnCreditsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(CreditsControl);
|
||||
}
|
||||
|
||||
private void OnSettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(SettingsControl);
|
||||
}
|
||||
|
||||
private void OnContinuePressed()
|
||||
{
|
||||
_gameManager.ContinueGame();
|
||||
}
|
||||
|
||||
private void OnNewGamePressed()
|
||||
{
|
||||
_gameManager.StartNewGame();
|
||||
}
|
||||
}
|
1
scripts/UI/MainMenu.cs.uid
Normal file
1
scripts/UI/MainMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bna3ggr6n7ycr
|
142
scripts/UI/Marketplace.cs
Normal file
142
scripts/UI/Marketplace.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class Marketplace : Node
|
||||
{
|
||||
[Export] public Array<SkillData> Skills { get; set; } = [];
|
||||
[Export] public GridContainer ToUnlockGrid { get; set; }
|
||||
[Export] public GridContainer UnlockedGrid { get; set; }
|
||||
[Export] public Font Font { get; set; }
|
||||
[Export] public SkillUnlockedComponent SkillUnlockedComponent { get; set; }
|
||||
[Export] public Array<Node> ComponentsToDisable { get; set; } = [];
|
||||
[Export] public PackedScene MarketplaceButtonScene { get; set; }
|
||||
[Export] public PackedScene SkillButtonScene { get; set; }
|
||||
|
||||
private GameManager _gameManager;
|
||||
private readonly List<Button> _unlockButtons = [];
|
||||
private readonly List<SkillButton> _skillButtons = [];
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
var skillsToUnlock = new List<SkillData>();
|
||||
|
||||
foreach (var skill in Skills) skillsToUnlock.Add(skill);
|
||||
|
||||
foreach (var skill in skillsToUnlock) CreateUpgradeButton(skill);
|
||||
|
||||
var unlockedSkills = _gameManager.GetUnlockedSkills();
|
||||
foreach (var skill in unlockedSkills) CreateSkillButton(skill);
|
||||
|
||||
SkillUnlockedComponent.SkillUnlocked += OnSkillUnlocked;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
SkillUnlockedComponent.SkillUnlocked -= OnSkillUnlocked;
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
var root = Owner as Control;
|
||||
|
||||
if (!@event.IsActionPressed("show_marketplace")) return;
|
||||
|
||||
if (root != null && root.IsVisible())
|
||||
{
|
||||
root.Hide();
|
||||
foreach (var c in ComponentsToDisable) c.ProcessMode = ProcessModeEnum.Inherit;
|
||||
}
|
||||
else
|
||||
{
|
||||
root?.Show();
|
||||
foreach (var c in ComponentsToDisable) c.ProcessMode = ProcessModeEnum.Disabled;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetButtonText(SkillData skill)
|
||||
{
|
||||
return $"{Tr(skill.Name)} {skill.Cost}";
|
||||
}
|
||||
|
||||
private void OnSkillUnlocked(SkillData skill)
|
||||
{
|
||||
if (_skillButtons.Count == 0) CreateSkillButton(skill);
|
||||
|
||||
foreach (var btn in _skillButtons)
|
||||
{
|
||||
if (btn.Data.IsActive)
|
||||
btn.Activate();
|
||||
else
|
||||
btn.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSkillButton(SkillData skill)
|
||||
{
|
||||
var button = SkillButtonScene.Instantiate<SkillButton>();
|
||||
button.Data = skill;
|
||||
button.Setup();
|
||||
button.Pressed += () => OnSkillButtonPressed(button);
|
||||
button.Activate();
|
||||
|
||||
_skillButtons.Add(button);
|
||||
UnlockedGrid.AddChild(button);
|
||||
UnlockedGrid.QueueSort();
|
||||
}
|
||||
|
||||
private void CreateUpgradeButton(SkillData skill)
|
||||
{
|
||||
var button = MarketplaceButtonScene.Instantiate<MarketplaceButton>();
|
||||
button.Text = GetButtonText(skill);
|
||||
button.Data = skill;
|
||||
button.Icon = skill.Icon;
|
||||
button.Pressed += () => OnUpgradeButtonPressed(skill);
|
||||
|
||||
_unlockButtons.Add(button);
|
||||
UnlockedGrid.AddChild(button);
|
||||
UnlockedGrid.QueueSort();
|
||||
}
|
||||
|
||||
private void OnUpgradeButtonPressed(SkillData skill)
|
||||
{
|
||||
if (_gameManager.IsSkillUnlocked(skill))
|
||||
{
|
||||
if (skill.Level < skill.MaxLevel)
|
||||
{
|
||||
SkillUnlockedComponent.TryUpgradeSkill(skill);
|
||||
if (!skill.IsActive) SkillUnlockedComponent.SkillManager.ToggleSkillActivation(skill);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkillUnlockedComponent.SkillManager.ToggleSkillActivation(skill);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SkillUnlockedComponent.TryUnlockSkill(skill);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveButton(SkillData skill)
|
||||
{
|
||||
foreach (var node in ToUnlockGrid.GetChildren())
|
||||
{
|
||||
var child = (Button)node;
|
||||
if (child.Text != GetButtonText(skill)) continue;
|
||||
|
||||
child.QueueFree();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSkillButtonPressed(SkillButton button)
|
||||
{
|
||||
SkillUnlockedComponent.SkillManager.ToggleSkillActivation(button.Data);
|
||||
}
|
||||
}
|
1
scripts/UI/Marketplace.cs.uid
Normal file
1
scripts/UI/Marketplace.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bnc16gndpl87i
|
62
scripts/UI/MarketplaceButton.cs
Normal file
62
scripts/UI/MarketplaceButton.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class MarketplaceButton : Button
|
||||
{
|
||||
[Export] public SkillData Data { get; set; }
|
||||
[Export] public Texture2D UnlockedSkillIcon { get; set; }
|
||||
[Export] public Texture2D LockedSkillIcon { get; set; }
|
||||
[Export] public Container SkillLevelContainer { get; set; }
|
||||
|
||||
private GameManager _gameManager;
|
||||
private SkillUnlockedComponent _skillUnlockedComponent;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
|
||||
Setup();
|
||||
var player = _gameManager.Player;
|
||||
|
||||
var skillUnlockerComponent = player?.GetNodeOrNull<SkillUnlockedComponent>("SkillUnlockerComponent");
|
||||
if (skillUnlockerComponent == null) return;
|
||||
|
||||
skillUnlockerComponent.SkillUnlocked += OnSkillUnlock;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
_skillUnlockedComponent.SkillUnlocked -= OnSkillUnlock;
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
if (Data == null) return;
|
||||
|
||||
for (var i = 0; i < Data.MaxLevel; i++)
|
||||
{
|
||||
var icon = new TextureRect()
|
||||
{
|
||||
Texture = i < Data.Level ? UnlockedSkillIcon : LockedSkillIcon,
|
||||
};
|
||||
SkillLevelContainer.AddChild(icon);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSkillUnlock(SkillData skill)
|
||||
{
|
||||
if (skill.Name != Data.Name) return;
|
||||
|
||||
for (var i = 0; i < Data.MaxLevel; i++)
|
||||
{
|
||||
var icon = SkillLevelContainer.GetChildOrNull<TextureRect>(i);
|
||||
if (icon == null) continue;
|
||||
icon.Texture = i < Data.Level ? UnlockedSkillIcon : LockedSkillIcon;
|
||||
Disabled = i >= Data.Level;
|
||||
}
|
||||
}
|
||||
}
|
1
scripts/UI/MarketplaceButton.cs.uid
Normal file
1
scripts/UI/MarketplaceButton.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://vokgv56bjpf1
|
67
scripts/UI/PauseMenu.cs
Normal file
67
scripts/UI/PauseMenu.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class PauseMenu : Node
|
||||
{
|
||||
[Export] public Control PauseMenuControl { get; set; }
|
||||
[Export] public Control SettingsControl { get; set; }
|
||||
[Export] public Button ResumeButton { get; set; }
|
||||
[Export] public Button MainMenuButton { get; set; }
|
||||
[Export] public Button QuitButton { get; set; }
|
||||
[Export] public Button SettingsButton { get; set; }
|
||||
[Export] public PackedScene MainMenuScene { get; set; }
|
||||
|
||||
private GameManager _gameManager;
|
||||
private UIManager _uiManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_uiManager = GetNode<UIManager>("/root/UIManager");
|
||||
|
||||
ResumeButton.Pressed += OnResumePressed;
|
||||
MainMenuButton.Pressed += OnMainMenuPressed;
|
||||
QuitButton.Pressed += OnQuitPressed;
|
||||
SettingsButton.Pressed += OnSettingsPressed;
|
||||
|
||||
PauseMenuControl.Hide();
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (!@event.IsActionPressed("pause")) return;
|
||||
if (_uiManager.IsVisibleOnStack(PauseMenuControl))
|
||||
OnResumePressed();
|
||||
else
|
||||
{
|
||||
_uiManager.PushScreen(PauseMenuControl);
|
||||
_gameManager.PauseGame();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(SettingsControl);
|
||||
_gameManager.PauseGame();
|
||||
}
|
||||
|
||||
private void OnQuitPressed()
|
||||
{
|
||||
_gameManager.QuitGame();
|
||||
}
|
||||
|
||||
private void OnMainMenuPressed()
|
||||
{
|
||||
_gameManager.ResumeGame();
|
||||
_gameManager.ResetCurrentSessionState();
|
||||
GetTree().ChangeSceneToPacked(MainMenuScene);
|
||||
}
|
||||
|
||||
private void OnResumePressed()
|
||||
{
|
||||
_uiManager.PopScreen();
|
||||
_gameManager.ResumeGame();
|
||||
}
|
||||
}
|
1
scripts/UI/PauseMenu.cs.uid
Normal file
1
scripts/UI/PauseMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cakgxndurgfa3
|
60
scripts/UI/SettingsMenu.cs
Normal file
60
scripts/UI/SettingsMenu.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class SettingsMenu : Node
|
||||
{
|
||||
[Export] public Control InputSettingsControl { get; set; }
|
||||
[Export] public Control AudioSettingsControl { get; set; }
|
||||
[Export] public Control DisplaySettingsControl { get; set; }
|
||||
[Export] public Control GameplaySettingsControl { get; set; }
|
||||
[Export] public Control SettingsMenuControl { get; set; }
|
||||
[Export] public Button InputSettingsButton { get; set; }
|
||||
[Export] public Button AudioSettingsButton { get; set; }
|
||||
[Export] public Button DisplaySettingsButton { get; set; }
|
||||
[Export] public Button GameplaySettingsButton { get; set; }
|
||||
|
||||
private UIManager _uiManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_uiManager = GetNode<UIManager>("/root/UIManager");
|
||||
|
||||
InputSettingsButton.Pressed += OnInputSettingsPressed;
|
||||
AudioSettingsButton.Pressed += OnAudioSettingsPressed;
|
||||
DisplaySettingsButton.Pressed += OnDisplaySettingsPressed;
|
||||
GameplaySettingsButton.Pressed += OnGameplaySettingsPressed;
|
||||
|
||||
InputSettingsControl.Hide();
|
||||
AudioSettingsControl.Hide();
|
||||
DisplaySettingsControl.Hide();
|
||||
GameplaySettingsControl.Hide();
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (!@event.IsActionPressed("ui_cancel")) return;
|
||||
if (_uiManager.IsScreenOnTop(SettingsMenuControl)) _uiManager.PopScreen();
|
||||
}
|
||||
|
||||
private void OnInputSettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(InputSettingsControl);
|
||||
}
|
||||
|
||||
private void OnAudioSettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(AudioSettingsControl);
|
||||
}
|
||||
|
||||
private void OnDisplaySettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(DisplaySettingsControl);
|
||||
}
|
||||
|
||||
private void OnGameplaySettingsPressed()
|
||||
{
|
||||
_uiManager.PushScreen(GameplaySettingsControl);
|
||||
}
|
||||
}
|
1
scripts/UI/SettingsMenu.cs.uid
Normal file
1
scripts/UI/SettingsMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://i8j47qnrytuo
|
25
scripts/UI/SkillButton.cs
Normal file
25
scripts/UI/SkillButton.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
public partial class SkillButton : Button
|
||||
{
|
||||
[Export] public SkillData Data { get; set; }
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
Icon = Data?.Icon;
|
||||
Text = Tr(Data?.Name) ?? string.Empty;
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
Set("theme_override_colors/font_color", new Color("#49aa10"));
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
Set("theme_override_colors/font_color", new Color("#ffffff"));
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user