Compare commits
6 Commits
75b668176b
...
clean-code
Author | SHA1 | Date | |
---|---|---|---|
817bd96433 | |||
2cc54f7b37 | |||
406036504a | |||
173f0e5703 | |||
d84f7d1740 | |||
2ad0fe26d2 |
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>
|
@@ -1,4 +1,4 @@
|
|||||||
# 🧱 Przygody Pana Cegły
|
# Przygody Pana Cegły
|
||||||
|
|
||||||
[](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/)
|
[](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/)
|
||||||
|
|
||||||
@@ -7,8 +7,6 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
# Przygody Pana Cegły
|
|
||||||
|
|
||||||
*"The world’s only brick-throwing dad simulator (probably)."*
|
*"The world’s only brick-throwing dad simulator (probably)."*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
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"]
|
[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="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"]
|
[ext_resource type="FontFile" uid="uid://xm0vbusjr7b7" path="res://fonts/PressStart2P-Regular.ttf" id="1_ygmwt"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mmcdi"]
|
[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"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_22dp1"]
|
||||||
bg_color = Color(0.858824, 0.254902, 0.380392, 1)
|
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
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@@ -25,10 +25,7 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
size_flags_vertical = 4
|
size_flags_vertical = 4
|
||||||
script = ExtResource("1_ueofj")
|
script = ExtResource("1_m4pq7")
|
||||||
coins_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Coins label")
|
|
||||||
health_progressbar = NodePath("PanelContainer/MarginContainer/HBoxContainer/ProgressBar")
|
|
||||||
lives_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Lives")
|
|
||||||
|
|
||||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
@@ -57,7 +54,8 @@ text = "HEALTH_LABEL"
|
|||||||
label_settings = ExtResource("1_4dsh5")
|
label_settings = ExtResource("1_4dsh5")
|
||||||
uppercase = true
|
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
|
visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
@@ -69,7 +67,8 @@ step = 0.1
|
|||||||
value = 60.0
|
value = 60.0
|
||||||
show_percentage = false
|
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
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
text = "LIVES_LABEL"
|
text = "LIVES_LABEL"
|
||||||
@@ -77,7 +76,8 @@ label_settings = ExtResource("1_4dsh5")
|
|||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
uppercase = true
|
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
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
text = "COINS_LABEL"
|
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"]
|
[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"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qv2q0"]
|
||||||
bg_color = Color(0, 0, 0, 1)
|
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
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1_epxpl")
|
script = ExtResource("1_q8hru")
|
||||||
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")
|
|
||||||
|
|
||||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
@@ -53,31 +46,37 @@ layout_mode = 2
|
|||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="ContinueButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
[node name="ContinueButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "CONTINUE_BUTTON"
|
text = "CONTINUE_BUTTON"
|
||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
[node name="NewGameButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
[node name="NewGameButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "NEW_GAME_BUTTON"
|
text = "NEW_GAME_BUTTON"
|
||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
[node name="SettingsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
[node name="SettingsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "SETTINGS_BUTTON"
|
text = "SETTINGS_BUTTON"
|
||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
[node name="CreditsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
[node name="CreditsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "CREDITS_BUTTON"
|
text = "CREDITS_BUTTON"
|
||||||
flat = true
|
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
|
layout_mode = 2
|
||||||
text = "QUIT_BUTTON"
|
text = "QUIT_BUTTON"
|
||||||
flat = true
|
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
|
layout_mode = 2
|
||||||
size_flags_horizontal = 0
|
size_flags_horizontal = 0
|
||||||
size_flags_vertical = 8
|
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://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="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://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="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="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"]
|
[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="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")]
|
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
|
||||||
current_level = ExtResource("4_c2yv5")
|
current_level = ExtResource("4_c2yv5")
|
||||||
nodes_to_disable = [NodePath("../../Brick Player")]
|
nodes_to_disable = [NodePath("../../Brick Player")]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=11 format=3 uid="uid://6foggu31cu14"]
|
[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="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="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"]
|
[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
|
offset_top = 32.0
|
||||||
components_to_disable = [null]
|
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
|
visible = false
|
||||||
settings_menu = NodePath("../Settings menu")
|
|
||||||
|
|
||||||
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("7_hkjav")]
|
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("7_hkjav")]
|
||||||
visible = false
|
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="Script" uid="uid://bwgs02wcfnm8u" path="res://features/ui/menus/PauseMenu.cs" id="1_ljtns"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cl00e2ocomk3m" path="res://scenes/main_menu.tscn" id="2_h4pd5"]
|
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4ivv"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4ivv"]
|
||||||
bg_color = Color(0, 0, 0, 1)
|
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
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@@ -15,13 +14,10 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
size_flags_horizontal = 6
|
size_flags_horizontal = 6
|
||||||
size_flags_vertical = 6
|
size_flags_vertical = 6
|
||||||
script = ExtResource("1_aktha")
|
script = ExtResource("1_ljtns")
|
||||||
pause_menu_control = NodePath(".")
|
ResumeButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
|
||||||
resume_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
|
RestartButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
|
||||||
quit_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Quit game Button")
|
MainMenuButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Exit to menu 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")
|
|
||||||
|
|
||||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
@@ -19,7 +19,7 @@ config/version="in-dev"
|
|||||||
run/main_scene="uid://cl00e2ocomk3m"
|
run/main_scene="uid://cl00e2ocomk3m"
|
||||||
config/use_custom_user_dir=true
|
config/use_custom_user_dir=true
|
||||||
config/custom_user_dir_name="MrBrickAdventures"
|
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
|
run/max_fps=180
|
||||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||||
boot_splash/show_image=false
|
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="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")]
|
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
|
||||||
current_level = ExtResource("4_onnch")
|
current_level = ExtResource("4_onnch")
|
||||||
nodes_to_disable = [NodePath("../../Brick Player")]
|
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://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://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://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://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")]
|
[node name="Main menu" type="CanvasLayer" parent="."]
|
||||||
settings_control = NodePath("../Settings menu")
|
|
||||||
credits_control = NodePath("../Credits")
|
|
||||||
|
|
||||||
[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
|
visible = false
|
||||||
input_settings = NodePath("../Input Settings")
|
input_settings = NodePath("../Input Settings")
|
||||||
audio_settings = NodePath("../Audio 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
|
visible = false
|
||||||
|
|
||||||
[node name="Audio settings" parent="." instance=ExtResource("4_8ln24")]
|
[node name="Audio settings" parent="Main menu" instance=ExtResource("4_8ln24")]
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
[node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")]
|
[node name="Input Settings" parent="Main menu" instance=ExtResource("5_rtw2f")]
|
||||||
visible = false
|
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