Compare commits
2 Commits
master
...
00772b6330
| Author | SHA1 | Date | |
|---|---|---|---|
| 00772b6330 | |||
| 3d8694377a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
/android/
|
||||
builds/
|
||||
.worktrees/
|
||||
builds/
|
||||
@@ -1,30 +1,23 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Mr.BrickAdventures.scripts.State;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
/// <summary>
|
||||
/// Manages achievements using GameStateStore.
|
||||
/// </summary>
|
||||
public partial class AchievementManager : Node
|
||||
{
|
||||
public static AchievementManager Instance { get; private set; }
|
||||
|
||||
[Export] private string AchievementsFolderPath = "res://achievements/";
|
||||
[Export] private PackedScene AchievementPopupScene { get; set; }
|
||||
|
||||
|
||||
private System.Collections.Generic.Dictionary<string, AchievementResource> _achievements = new();
|
||||
|
||||
private Array<string> _unlockedAchievementIds = [];
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
LoadAchievementsFromFolder();
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
LoadUnlockedAchievements();
|
||||
}
|
||||
|
||||
private void LoadAchievementsFromFolder()
|
||||
@@ -51,15 +44,7 @@ public partial class AchievementManager : Node
|
||||
fileName = dir.GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of unlocked achievement IDs from the store.
|
||||
/// </summary>
|
||||
private System.Collections.Generic.List<string> GetUnlockedIds()
|
||||
{
|
||||
return GameStateStore.Instance?.Player.UnlockedAchievements ?? new System.Collections.Generic.List<string>();
|
||||
}
|
||||
|
||||
|
||||
public void UnlockAchievement(string achievementId)
|
||||
{
|
||||
if (!_achievements.TryGetValue(achievementId, out var achievement))
|
||||
@@ -68,16 +53,14 @@ public partial class AchievementManager : Node
|
||||
return;
|
||||
}
|
||||
|
||||
var unlockedIds = GetUnlockedIds();
|
||||
if (unlockedIds.Contains(achievementId))
|
||||
if (_unlockedAchievementIds.Contains(achievementId))
|
||||
{
|
||||
return; // Already unlocked
|
||||
}
|
||||
|
||||
// 1. Mark as unlocked
|
||||
unlockedIds.Add(achievementId);
|
||||
// 1. Mark as unlocked internally
|
||||
_unlockedAchievementIds.Add(achievementId);
|
||||
GD.Print($"Achievement Unlocked: {achievement.DisplayName}");
|
||||
EventBus.EmitAchievementUnlocked(achievementId);
|
||||
|
||||
// 2. Show the UI popup
|
||||
if (AchievementPopupScene != null)
|
||||
@@ -92,19 +75,31 @@ public partial class AchievementManager : Node
|
||||
{
|
||||
SteamManager.UnlockAchievement(achievement.Id);
|
||||
}
|
||||
|
||||
// 4. Save progress
|
||||
SaveUnlockedAchievements();
|
||||
}
|
||||
|
||||
|
||||
public void LockAchievement(string achievementId)
|
||||
{
|
||||
var unlockedIds = GetUnlockedIds();
|
||||
if (unlockedIds.Contains(achievementId))
|
||||
if (_unlockedAchievementIds.Contains(achievementId))
|
||||
{
|
||||
unlockedIds.Remove(achievementId);
|
||||
_unlockedAchievementIds.Remove(achievementId);
|
||||
SaveUnlockedAchievements();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAchievementUnlocked(string achievementId)
|
||||
|
||||
private void SaveUnlockedAchievements()
|
||||
{
|
||||
return GetUnlockedIds().Contains(achievementId);
|
||||
_gameManager.PlayerState["unlocked_achievements"] = _unlockedAchievementIds;
|
||||
// You might want to trigger a save game here, depending on your SaveSystem
|
||||
}
|
||||
|
||||
private void LoadUnlockedAchievements()
|
||||
{
|
||||
if (_gameManager.PlayerState.TryGetValue("unlocked_achievements", out var unlocked))
|
||||
{
|
||||
_unlockedAchievementIds = (Array<string>)unlocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,13 @@ namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class ConfigFileHandler : Node
|
||||
{
|
||||
public static ConfigFileHandler Instance { get; private set; }
|
||||
|
||||
private ConfigFile _settingsConfig = new();
|
||||
public const string SettingsPath = "user://settings.ini";
|
||||
|
||||
|
||||
public ConfigFile SettingsConfig => _settingsConfig;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
if (!FileAccess.FileExists(SettingsPath))
|
||||
{
|
||||
var err = _settingsConfig.Save(SettingsPath);
|
||||
@@ -27,9 +24,4 @@ public partial class ConfigFileHandler : Node
|
||||
GD.PushError($"Failed to load settings file at {SettingsPath}: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
}
|
||||
@@ -5,116 +5,128 @@ namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class ConsoleManager : Node
|
||||
{
|
||||
private GameStateStore Store => GameStateStore.Instance;
|
||||
private GameManager GameManager => GameManager.Instance;
|
||||
private AchievementManager AchievementManager => AchievementManager.Instance;
|
||||
private GameManager _gameManager;
|
||||
private SkillManager _skillManager;
|
||||
private SkillUnlockerComponent _skillUnlockerComponent;
|
||||
private AchievementManager _achievementManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_skillManager = SkillManager.Instance;
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_achievementManager = GetNode<AchievementManager>("/root/AchievementManager");
|
||||
_skillManager = GetNode<SkillManager>("/root/SkillManager");
|
||||
}
|
||||
|
||||
private void AddCoinsCommand(int amount)
|
||||
{
|
||||
if (Store == null) return;
|
||||
Store.Player.Coins += amount;
|
||||
EventBus.EmitCoinsChanged(Store.GetTotalCoins());
|
||||
_gameManager.AddCoins(amount);
|
||||
}
|
||||
|
||||
private void SetCoinsCommand(int amount)
|
||||
{
|
||||
if (Store == null) return;
|
||||
Store.Player.Coins = Mathf.Max(0, amount);
|
||||
EventBus.EmitCoinsChanged(Store.GetTotalCoins());
|
||||
_gameManager.SetCoins(amount);
|
||||
}
|
||||
|
||||
private void SetLivesCommand(int amount)
|
||||
{
|
||||
if (Store == null) return;
|
||||
Store.Player.Lives = amount;
|
||||
EventBus.EmitLivesChanged(amount);
|
||||
_gameManager.SetLives(amount);
|
||||
}
|
||||
|
||||
private void AddLivesCommand(int amount)
|
||||
{
|
||||
Store?.AddLives(amount);
|
||||
_gameManager.AddLives(amount);
|
||||
}
|
||||
|
||||
private void SetHealthCommand(float amount)
|
||||
{
|
||||
var playerHealthComponent = GameManager?.Player?.GetNode<HealthComponent>("HealthComponent");
|
||||
var playerHealthComponent = _gameManager.Player.GetNode<HealthComponent>("HealthComponent");
|
||||
if (playerHealthComponent != null)
|
||||
{
|
||||
playerHealthComponent.Health = amount;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetSessionCommand()
|
||||
{
|
||||
Store?.ResetSession();
|
||||
_gameManager.ResetCurrentSessionState();
|
||||
}
|
||||
|
||||
private void UnlockSkillCommand(string skillName)
|
||||
{
|
||||
if (!EnsureSkillManagement()) return;
|
||||
if (!GetSkillManagement()) return;
|
||||
|
||||
var skill = _skillManager.GetSkillByName(skillName);
|
||||
if (skill == null) return;
|
||||
if (skill == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Store?.UnlockSkillPermanently(skill);
|
||||
_gameManager.UnlockSkill(skill);
|
||||
_skillManager.ActivateSkill(skill);
|
||||
_skillUnlockerComponent.EmitSignal(SkillUnlockerComponent.SignalName.SkillUnlocked, skill);
|
||||
}
|
||||
|
||||
private bool GetSkillManagement()
|
||||
{
|
||||
var player = _gameManager.Player;
|
||||
if (player == null || !IsInstanceValid(player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_skillUnlockerComponent ??= player.GetNode<SkillUnlockerComponent>("SkillUnlockerComponent");
|
||||
|
||||
if (_skillManager != null && _skillUnlockerComponent != null) return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private void UnlockAllSkillsCommand()
|
||||
{
|
||||
if (!EnsureSkillManagement()) return;
|
||||
if (!GetSkillManagement()) return;
|
||||
|
||||
_skillUnlockerComponent.UnlockAllSkills();
|
||||
}
|
||||
|
||||
|
||||
private void RemoveSkillCommand(string skillName)
|
||||
{
|
||||
if (!EnsureSkillManagement()) return;
|
||||
if (!GetSkillManagement()) return;
|
||||
|
||||
var skill = _skillManager.GetSkillByName(skillName);
|
||||
if (skill == null) return;
|
||||
if (skill == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Store?.RemoveUnlockedSkill(skill.Name);
|
||||
_gameManager.RemoveSkill(skill.Name);
|
||||
_skillManager.DeactivateSkill(skill);
|
||||
}
|
||||
|
||||
|
||||
private void RemoveAllSkillsCommand()
|
||||
{
|
||||
if (!EnsureSkillManagement()) return;
|
||||
|
||||
if (!GetSkillManagement()) return;
|
||||
|
||||
foreach (var skill in _skillManager.AvailableSkills)
|
||||
{
|
||||
Store?.RemoveUnlockedSkill(skill.Name);
|
||||
_gameManager.RemoveSkill(skill.Name);
|
||||
_skillManager.DeactivateSkill(skill);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void GoToNextLevelCommand()
|
||||
{
|
||||
GameManager?.OnLevelComplete();
|
||||
_gameManager.OnLevelComplete();
|
||||
}
|
||||
|
||||
|
||||
private void UnlockAchievementCommand(string achievementId)
|
||||
{
|
||||
AchievementManager?.UnlockAchievement(achievementId);
|
||||
_achievementManager.UnlockAchievement(achievementId);
|
||||
}
|
||||
|
||||
|
||||
private void ResetAchievementCommand(string achievementId)
|
||||
{
|
||||
AchievementManager?.LockAchievement(achievementId);
|
||||
_achievementManager.LockAchievement(achievementId);
|
||||
}
|
||||
|
||||
private bool EnsureSkillManagement()
|
||||
{
|
||||
var player = GameManager?.Player;
|
||||
if (player == null || !IsInstanceValid(player)) return false;
|
||||
|
||||
_skillUnlockerComponent ??= player.GetNode<SkillUnlockerComponent>("SkillUnlockerComponent");
|
||||
return _skillManager != null && _skillUnlockerComponent != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +1,9 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
/// <summary>
|
||||
/// Global event bus for decoupled communication between game systems.
|
||||
/// Use the static Instance property for easy access from anywhere.
|
||||
/// </summary>
|
||||
public partial class EventBus : Node
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton instance. Available after the autoload is initialized.
|
||||
/// </summary>
|
||||
public static EventBus Instance { get; private set; }
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
#region Level Events
|
||||
|
||||
[Signal] public delegate void LevelStartedEventHandler(int levelIndex, Node currentScene);
|
||||
[Signal] public delegate void LevelCompletedEventHandler(int levelIndex, Node currentScene, double completionTime);
|
||||
[Signal] public delegate void LevelRestartedEventHandler(int levelIndex);
|
||||
|
||||
public static void EmitLevelStarted(int levelIndex, Node currentScene)
|
||||
=> Instance?.EmitSignal(SignalName.LevelStarted, levelIndex, currentScene);
|
||||
|
||||
public static void EmitLevelCompleted(int levelIndex, Node currentScene, double completionTime)
|
||||
=> Instance?.EmitSignal(SignalName.LevelCompleted, levelIndex, currentScene, completionTime);
|
||||
|
||||
public static void EmitLevelRestarted(int levelIndex)
|
||||
=> Instance?.EmitSignal(SignalName.LevelRestarted, levelIndex);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Player Events
|
||||
|
||||
[Signal] public delegate void PlayerSpawnedEventHandler(PlayerController player);
|
||||
[Signal] public delegate void PlayerDiedEventHandler(Vector2 position);
|
||||
[Signal] public delegate void PlayerDamagedEventHandler(float damage, float remainingHealth, Vector2 position);
|
||||
[Signal] public delegate void PlayerHealedEventHandler(float amount, float newHealth, Vector2 position);
|
||||
|
||||
public static void EmitPlayerSpawned(PlayerController player)
|
||||
=> Instance?.EmitSignal(SignalName.PlayerSpawned, player);
|
||||
|
||||
public static void EmitPlayerDied(Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.PlayerDied, position);
|
||||
|
||||
public static void EmitPlayerDamaged(float damage, float remainingHealth, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.PlayerDamaged, damage, remainingHealth, position);
|
||||
|
||||
public static void EmitPlayerHealed(float amount, float newHealth, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.PlayerHealed, amount, newHealth, position);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Combat Events
|
||||
|
||||
[Signal] public delegate void EnemyDefeatedEventHandler(Node enemy, Vector2 position);
|
||||
[Signal] public delegate void EnemyDamagedEventHandler(Node enemy, float damage, Vector2 position);
|
||||
|
||||
public static void EmitEnemyDefeated(Node enemy, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.EnemyDefeated, enemy, position);
|
||||
|
||||
public static void EmitEnemyDamaged(Node enemy, float damage, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.EnemyDamaged, enemy, damage, position);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collection Events
|
||||
|
||||
[Signal] public delegate void CoinCollectedEventHandler(int amount, Vector2 position);
|
||||
[Signal] public delegate void ItemCollectedEventHandler(CollectableType itemType, float amount, Vector2 position);
|
||||
[Signal] public delegate void ChildRescuedEventHandler(Vector2 position);
|
||||
[Signal] public delegate void SkillCollectedEventHandler(SkillData skill, Vector2 position);
|
||||
|
||||
public static void EmitCoinCollected(int amount, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.CoinCollected, amount, position);
|
||||
|
||||
public static void EmitItemCollected(CollectableType itemType, float amount, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.ItemCollected, (int)itemType, amount, position);
|
||||
|
||||
public static void EmitChildRescued(Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.ChildRescued, position);
|
||||
|
||||
public static void EmitSkillCollected(SkillData skill, Vector2 position)
|
||||
=> Instance?.EmitSignal(SignalName.SkillCollected, skill, position);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skill Events
|
||||
|
||||
[Signal] public delegate void SkillUnlockedEventHandler(string skillName, int level);
|
||||
[Signal] public delegate void SkillActivatedEventHandler(string skillName);
|
||||
[Signal] public delegate void SkillDeactivatedEventHandler(string skillName);
|
||||
|
||||
public static void EmitSkillUnlocked(string skillName, int level = 1)
|
||||
=> Instance?.EmitSignal(SignalName.SkillUnlocked, skillName, level);
|
||||
|
||||
public static void EmitSkillActivated(string skillName)
|
||||
=> Instance?.EmitSignal(SignalName.SkillActivated, skillName);
|
||||
|
||||
public static void EmitSkillDeactivated(string skillName)
|
||||
=> Instance?.EmitSignal(SignalName.SkillDeactivated, skillName);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Game State Events
|
||||
|
||||
[Signal] public delegate void GamePausedEventHandler();
|
||||
[Signal] public delegate void GameResumedEventHandler();
|
||||
[Signal] public delegate void GameSavedEventHandler();
|
||||
[Signal] public delegate void GameStartedEventHandler();
|
||||
[Signal] public delegate void GameContinuedEventHandler();
|
||||
|
||||
public static void EmitGamePaused()
|
||||
=> Instance?.EmitSignal(SignalName.GamePaused);
|
||||
|
||||
public static void EmitGameResumed()
|
||||
=> Instance?.EmitSignal(SignalName.GameResumed);
|
||||
|
||||
public static void EmitGameSaved()
|
||||
=> Instance?.EmitSignal(SignalName.GameSaved);
|
||||
|
||||
public static void EmitGameStarted()
|
||||
=> Instance?.EmitSignal(SignalName.GameStarted);
|
||||
|
||||
public static void EmitGameContinued()
|
||||
=> Instance?.EmitSignal(SignalName.GameContinued);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Achievement Events
|
||||
|
||||
[Signal] public delegate void AchievementUnlockedEventHandler(string achievementId);
|
||||
|
||||
public static void EmitAchievementUnlocked(string achievementId)
|
||||
=> Instance?.EmitSignal(SignalName.AchievementUnlocked, achievementId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Change Events
|
||||
|
||||
[Signal] public delegate void CoinsChangedEventHandler(int totalCoins);
|
||||
[Signal] public delegate void LivesChangedEventHandler(int lives);
|
||||
|
||||
public static void EmitCoinsChanged(int totalCoins)
|
||||
=> Instance?.EmitSignal(SignalName.CoinsChanged, totalCoins);
|
||||
|
||||
public static void EmitLivesChanged(int lives)
|
||||
=> Instance?.EmitSignal(SignalName.LivesChanged, lives);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
@@ -9,34 +7,22 @@ namespace Mr.BrickAdventures.Autoloads;
|
||||
public partial class FloatingTextManager : Node
|
||||
{
|
||||
[Export] public PackedScene FloatingTextScene { get; set; }
|
||||
|
||||
|
||||
[ExportGroup("Colors")]
|
||||
[Export] public Color DamageColor { get; set; } = new Color("#b21030"); // Red
|
||||
[Export] public Color HealColor { get; set; } = new Color("#71f341"); // Green
|
||||
[Export] public Color CoinColor { get; set; } = new Color("#ebd320"); // Gold
|
||||
[Export] public Color MessageColor { get; set; } = new Color("#ffffff"); // White
|
||||
|
||||
public static FloatingTextManager Instance { get; private set; }
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
|
||||
public void ShowDamage(float amount, Vector2 position)
|
||||
{
|
||||
var text = Mathf.Round(amount * 100f).ToString(CultureInfo.InvariantCulture);
|
||||
CreateFloatingText(text, position, DamageColor);
|
||||
}
|
||||
|
||||
|
||||
public void ShowHeal(float amount, Vector2 position)
|
||||
{
|
||||
var text = $"+{Mathf.Round(amount * 100f).ToString(CultureInfo.InvariantCulture)}";
|
||||
var text = $"+{Mathf.Round(amount)}";
|
||||
CreateFloatingText(text, position, HealColor);
|
||||
}
|
||||
|
||||
@@ -45,12 +31,12 @@ public partial class FloatingTextManager : Node
|
||||
var text = $"+{amount}";
|
||||
CreateFloatingText(text, position, CoinColor);
|
||||
}
|
||||
|
||||
|
||||
public void ShowMessage(string message, Vector2 position)
|
||||
{
|
||||
CreateFloatingText(message, position, MessageColor);
|
||||
}
|
||||
|
||||
|
||||
private void CreateFloatingText(string text, Vector2 position, Color color)
|
||||
{
|
||||
if (FloatingTextScene == null)
|
||||
|
||||
@@ -1,62 +1,212 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.components;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Double = System.Double;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
/// <summary>
|
||||
/// Game orchestrator - handles scene transitions and game flow.
|
||||
/// State lives in GameStateStore; query it directly for reads/writes.
|
||||
/// </summary>
|
||||
public partial class GameManager : Node
|
||||
{
|
||||
[Export] public Array<PackedScene> LevelScenes { get; set; } = [];
|
||||
|
||||
public PlayerController Player
|
||||
{
|
||||
|
||||
public PlayerController Player {
|
||||
get => GetPlayer();
|
||||
private set => _player = value;
|
||||
}
|
||||
|
||||
|
||||
private List<Node> _sceneNodes = [];
|
||||
private PlayerController _player;
|
||||
private SpeedRunManager SpeedRunManager => SpeedRunManager.Instance;
|
||||
private GameStateStore Store => GameStateStore.Instance;
|
||||
|
||||
public static GameManager Instance { get; private set; }
|
||||
|
||||
public override void _Ready()
|
||||
private SpeedRunManager _speedRunManager;
|
||||
private EventBus _eventBus;
|
||||
|
||||
[Export]
|
||||
public Dictionary PlayerState { get; set; } = new()
|
||||
{
|
||||
Instance = this;
|
||||
EventBus.Instance.PlayerSpawned += OnPlayerSpawned;
|
||||
{ "coins", 0 },
|
||||
{ "lives", 3 },
|
||||
{ "current_level", 0 },
|
||||
{ "completed_levels", new Array<int>() },
|
||||
{ "unlocked_levels", new Array<int>() {0}},
|
||||
{ "unlocked_skills", new Array<SkillData>() }
|
||||
};
|
||||
|
||||
[Export]
|
||||
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()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
if (EventBus.Instance != null)
|
||||
EventBus.Instance.PlayerSpawned -= OnPlayerSpawned;
|
||||
GetTree().NodeAdded -= OnNodeAdded;
|
||||
GetTree().NodeRemoved -= OnNodeRemoved;
|
||||
_sceneNodes.Clear();
|
||||
}
|
||||
|
||||
private void OnPlayerSpawned(PlayerController player)
|
||||
public override void _Ready()
|
||||
{
|
||||
_player = player;
|
||||
player.TreeExiting += () => { if (_player == player) _player = null; };
|
||||
_speedRunManager = GetNode<SpeedRunManager>("/root/SpeedRunManager");
|
||||
_eventBus = GetNode<EventBus>("/root/EventBus");
|
||||
}
|
||||
|
||||
#region Game Flow
|
||||
private void OnNodeAdded(Node node)
|
||||
{
|
||||
_sceneNodes.Add(node);
|
||||
}
|
||||
|
||||
private void OnNodeRemoved(Node node)
|
||||
{
|
||||
_sceneNodes.Remove(node);
|
||||
if (node == _player)
|
||||
{
|
||||
_player = null;
|
||||
}
|
||||
}
|
||||
|
||||
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>() },
|
||||
{ "statistics", new Godot.Collections.Dictionary<string, Variant>()}
|
||||
};
|
||||
}
|
||||
|
||||
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]);
|
||||
_eventBus.EmitSignal(EventBus.SignalName.LevelStarted, next, GetTree().CurrentScene);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Store?.ResetAll();
|
||||
SpeedRunManager?.StartTimer();
|
||||
ResetPlayerState();
|
||||
ResetCurrentSessionState();
|
||||
|
||||
_speedRunManager?.StartTimer();
|
||||
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[0]);
|
||||
SaveSystem.Instance.SaveGame();
|
||||
EventBus.EmitGameStarted();
|
||||
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
|
||||
}
|
||||
|
||||
public void ContinueGame()
|
||||
{
|
||||
var save = SaveSystem.Instance;
|
||||
var save = GetNode<SaveSystem>("/root/SaveSystem");
|
||||
if (!save.LoadGame())
|
||||
{
|
||||
GD.PrintErr("Failed to load game. Starting a new game instead.");
|
||||
@@ -64,79 +214,57 @@ public partial class GameManager : Node
|
||||
return;
|
||||
}
|
||||
|
||||
var idx = Store?.Player.CurrentLevel ?? 0;
|
||||
var idx = (int)PlayerState["current_level"];
|
||||
if (idx < LevelScenes.Count)
|
||||
{
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[idx]);
|
||||
EventBus.EmitGameContinued();
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr("No levels unlocked to continue.");
|
||||
}
|
||||
}
|
||||
|
||||
public void RestartGame()
|
||||
{
|
||||
Store?.ResetAll();
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[0]);
|
||||
SaveSystem.Instance.SaveGame();
|
||||
}
|
||||
|
||||
|
||||
public void OnLevelComplete()
|
||||
{
|
||||
if (Store == null) return;
|
||||
var levelIndex = (int)PlayerState["current_level"];
|
||||
MarkLevelComplete(levelIndex);
|
||||
|
||||
AddCoins((int)CurrentSessionState["coins_collected"]);
|
||||
foreach (var s in (Array)CurrentSessionState["skills_unlocked"])
|
||||
UnlockSkill((SkillData)s);
|
||||
|
||||
var levelIndex = Store.Player.CurrentLevel;
|
||||
Store.MarkLevelComplete(levelIndex);
|
||||
Store.CommitSessionCoins();
|
||||
Store.CommitSessionSkills();
|
||||
|
||||
var completionTime = SpeedRunManager?.GetCurrentLevelTime() ?? 0.0;
|
||||
EventBus.EmitLevelCompleted(levelIndex, GetTree().CurrentScene, completionTime);
|
||||
|
||||
Store.ResetSession();
|
||||
var completionTime = _speedRunManager?.GetCurrentLevelTime() ?? 0.0;
|
||||
_eventBus.EmitSignal(EventBus.SignalName.LevelCompleted, levelIndex, GetTree().CurrentScene, completionTime);
|
||||
|
||||
ResetCurrentSessionState();
|
||||
TryToGoToNextLevel();
|
||||
SaveSystem.Instance.SaveGame();
|
||||
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
|
||||
}
|
||||
|
||||
public void TryToGoToNextLevel()
|
||||
public Array<SkillData> GetUnlockedSkills()
|
||||
{
|
||||
if (Store == null) return;
|
||||
|
||||
var next = Store.Player.CurrentLevel + 1;
|
||||
if (next < LevelScenes.Count && Store.IsLevelUnlocked(next))
|
||||
{
|
||||
Store.Player.CurrentLevel = next;
|
||||
GetTree().ChangeSceneToPacked(LevelScenes[next]);
|
||||
EventBus.EmitLevelStarted(next, GetTree().CurrentScene);
|
||||
}
|
||||
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 void PauseGame()
|
||||
{
|
||||
Engine.TimeScale = 0;
|
||||
EventBus.EmitGamePaused();
|
||||
}
|
||||
|
||||
public void ResumeGame()
|
||||
{
|
||||
Engine.TimeScale = 1;
|
||||
EventBus.EmitGameResumed();
|
||||
}
|
||||
|
||||
public void QuitGame() => GetTree().Quit();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Player Lookup
|
||||
|
||||
public PlayerController GetPlayer()
|
||||
{
|
||||
if (_player != null && IsInstanceValid(_player)) return _player;
|
||||
|
||||
_player = null;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Mr.BrickAdventures.scripts.State;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
/// <summary>
|
||||
/// Central store for game state - single source of truth.
|
||||
/// Use the static Instance property for easy access.
|
||||
/// </summary>
|
||||
public partial class GameStateStore : Node
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton instance.
|
||||
/// </summary>
|
||||
public static GameStateStore Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Persistent player state (saved to disk).
|
||||
/// </summary>
|
||||
public PlayerState Player { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Current session state (transient, reset on death/level complete).
|
||||
/// </summary>
|
||||
public SessionState Session { get; set; } = new();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
#region Coin Operations
|
||||
|
||||
/// <summary>
|
||||
/// Gets total coins (saved + session).
|
||||
/// </summary>
|
||||
public int GetTotalCoins() => Player.Coins + Session.CoinsCollected;
|
||||
|
||||
/// <summary>
|
||||
/// Adds coins to the session (not saved until level complete).
|
||||
/// </summary>
|
||||
public void AddSessionCoins(int amount)
|
||||
{
|
||||
Session.CoinsCollected += amount;
|
||||
EventBus.EmitCoinsChanged(GetTotalCoins());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits session coins to player state.
|
||||
/// </summary>
|
||||
public void CommitSessionCoins()
|
||||
{
|
||||
Player.Coins += Session.CoinsCollected;
|
||||
Session.CoinsCollected = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes coins, first from session then from saved.
|
||||
/// </summary>
|
||||
public void RemoveCoins(int amount)
|
||||
{
|
||||
if (amount <= Session.CoinsCollected)
|
||||
{
|
||||
Session.CoinsCollected -= amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
var remaining = amount - Session.CoinsCollected;
|
||||
Session.CoinsCollected = 0;
|
||||
Player.Coins = Mathf.Max(0, Player.Coins - remaining);
|
||||
}
|
||||
EventBus.EmitCoinsChanged(GetTotalCoins());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lives Operations
|
||||
|
||||
/// <summary>
|
||||
/// Decrements lives by 1.
|
||||
/// </summary>
|
||||
public void RemoveLife()
|
||||
{
|
||||
Player.Lives = Mathf.Max(0, Player.Lives - 1);
|
||||
EventBus.EmitLivesChanged(Player.Lives);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds lives.
|
||||
/// </summary>
|
||||
public void AddLives(int amount)
|
||||
{
|
||||
Player.Lives += amount;
|
||||
EventBus.EmitLivesChanged(Player.Lives);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Level Operations
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks a level for access.
|
||||
/// </summary>
|
||||
public void UnlockLevel(int levelIndex)
|
||||
{
|
||||
if (!Player.UnlockedLevels.Contains(levelIndex))
|
||||
Player.UnlockedLevels.Add(levelIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks a level as completed and unlocks the next.
|
||||
/// </summary>
|
||||
public void MarkLevelComplete(int levelIndex)
|
||||
{
|
||||
if (!Player.CompletedLevels.Contains(levelIndex))
|
||||
Player.CompletedLevels.Add(levelIndex);
|
||||
UnlockLevel(levelIndex + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a level is unlocked.
|
||||
/// </summary>
|
||||
public bool IsLevelUnlocked(int levelIndex) => Player.UnlockedLevels.Contains(levelIndex);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Skill Operations
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a skill is unlocked (saved or session).
|
||||
/// </summary>
|
||||
public bool IsSkillUnlocked(SkillData skill)
|
||||
{
|
||||
return Player.UnlockedSkills.Contains(skill) || Session.SkillsUnlocked.Contains(skill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks a skill in the session (lost on death, committed on level complete).
|
||||
/// </summary>
|
||||
public void UnlockSkillInSession(SkillData skill)
|
||||
{
|
||||
if (!IsSkillUnlocked(skill))
|
||||
Session.SkillsUnlocked.Add(skill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Permanently unlocks a skill directly in player state (bypasses session, e.g. console commands).
|
||||
/// </summary>
|
||||
public void UnlockSkillPermanently(SkillData skill)
|
||||
{
|
||||
if (!Player.UnlockedSkills.Contains(skill))
|
||||
Player.UnlockedSkills.Add(skill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a permanently unlocked skill from player state by name.
|
||||
/// </summary>
|
||||
public void RemoveUnlockedSkill(string skillName)
|
||||
{
|
||||
for (int i = 0; i < Player.UnlockedSkills.Count; i++)
|
||||
{
|
||||
if (Player.UnlockedSkills[i].Name == skillName)
|
||||
{
|
||||
Player.UnlockedSkills.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits session skills to player state.
|
||||
/// </summary>
|
||||
public void CommitSessionSkills()
|
||||
{
|
||||
foreach (var skill in Session.SkillsUnlocked)
|
||||
{
|
||||
if (!Player.UnlockedSkills.Contains(skill))
|
||||
Player.UnlockedSkills.Add(skill);
|
||||
}
|
||||
Session.SkillsUnlocked.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all unlocked skills from player persistence and current session.
|
||||
/// </summary>
|
||||
public List<SkillData> GetAllUnlockedSkills()
|
||||
{
|
||||
var result = new List<SkillData>(Player.UnlockedSkills);
|
||||
foreach (var skill in Session.SkillsUnlocked)
|
||||
{
|
||||
if (!result.Contains(skill)) result.Add(skill);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Statistics Operations
|
||||
|
||||
public void IncrementStat(string name, int amount = 1)
|
||||
{
|
||||
if (Player.Statistics.TryGetValue(name, out var current))
|
||||
Player.Statistics[name] = current + amount;
|
||||
else
|
||||
Player.Statistics[name] = amount;
|
||||
}
|
||||
|
||||
public void SetStat(string name, int value) => Player.Statistics[name] = value;
|
||||
|
||||
public int GetStat(string name) =>
|
||||
Player.Statistics.TryGetValue(name, out var value) ? value : 0;
|
||||
|
||||
public System.Collections.Generic.Dictionary<string, int> GetAllStats() =>
|
||||
new(Player.Statistics);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reset Operations
|
||||
|
||||
/// <summary>
|
||||
/// Resets only the session state.
|
||||
/// </summary>
|
||||
public void ResetSession() => Session.Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Resets everything to defaults.
|
||||
/// </summary>
|
||||
public void ResetAll()
|
||||
{
|
||||
Player.Reset();
|
||||
Session.ResetAll();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://bwrhkipwecytk
|
||||
@@ -1,20 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts;
|
||||
using Mr.BrickAdventures.scripts.State;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class GhostManager : Node
|
||||
{
|
||||
public static GhostManager Instance { get; private set; }
|
||||
|
||||
[Export] private PackedScene GhostPlayerScene { get; set; }
|
||||
|
||||
public override void _Ready() => Instance = this;
|
||||
public override void _ExitTree() { if (Instance == this) Instance = null; }
|
||||
|
||||
|
||||
public bool IsRecording { get; private set; } = false;
|
||||
public bool IsPlaybackEnabled { get; private set; } = true;
|
||||
|
||||
@@ -25,14 +19,14 @@ public partial class GhostManager : Node
|
||||
public void StartRecording(int levelIndex)
|
||||
{
|
||||
if (!IsPlaybackEnabled) return;
|
||||
|
||||
|
||||
_currentLevelIndex = levelIndex;
|
||||
_currentRecording.Clear();
|
||||
_startTime = Time.GetTicksMsec() / 1000.0;
|
||||
IsRecording = true;
|
||||
GD.Print("Ghost recording started.");
|
||||
}
|
||||
|
||||
|
||||
public void StopRecording(bool levelCompleted, double finalTime)
|
||||
{
|
||||
if (!IsRecording) return;
|
||||
@@ -49,22 +43,23 @@ public partial class GhostManager : Node
|
||||
}
|
||||
_currentRecording.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void RecordFrame(Vector2 position)
|
||||
{
|
||||
if (!IsRecording) return;
|
||||
|
||||
_currentRecording.Add(new GhostFrame
|
||||
var frame = new GhostFrame
|
||||
{
|
||||
Timestamp = (Time.GetTicksMsec() / 1000.0) - _startTime,
|
||||
Position = position
|
||||
});
|
||||
};
|
||||
_currentRecording.Add(frame);
|
||||
}
|
||||
|
||||
|
||||
public void SpawnGhostPlayer(int levelIndex, Node parent)
|
||||
{
|
||||
if (!IsPlaybackEnabled || GhostPlayerScene == null) return;
|
||||
|
||||
|
||||
var ghostData = LoadGhostData(levelIndex);
|
||||
if (ghostData.Count > 0)
|
||||
{
|
||||
@@ -74,63 +69,44 @@ public partial class GhostManager : Node
|
||||
GD.Print($"Ghost player spawned for level {levelIndex}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SaveGhostData(int levelIndex, double time)
|
||||
{
|
||||
var path = $"user://ghost_level_{levelIndex}.json";
|
||||
var saveData = new GhostSaveData { BestTime = time };
|
||||
foreach (var frame in _currentRecording)
|
||||
saveData.Frames.Add(new GhostFrameDto { Timestamp = frame.Timestamp, X = frame.Position.X, Y = frame.Position.Y });
|
||||
|
||||
try
|
||||
var path = $"user://ghost_level_{levelIndex}.dat";
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
|
||||
|
||||
var dataToSave = new Godot.Collections.Dictionary
|
||||
{
|
||||
var json = JsonSerializer.Serialize(saveData, SaveSystem.JsonOptions);
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
|
||||
file.StoreString(json);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GD.PrintErr($"GhostManager: Failed to save ghost data: {e.Message}");
|
||||
}
|
||||
{ "time", time },
|
||||
{ "frames", _currentRecording.ToArray() }
|
||||
};
|
||||
file.StoreVar(dataToSave);
|
||||
}
|
||||
|
||||
|
||||
private List<GhostFrame> LoadGhostData(int levelIndex)
|
||||
{
|
||||
var path = $"user://ghost_level_{levelIndex}.json";
|
||||
var path = $"user://ghost_level_{levelIndex}.dat";
|
||||
if (!FileAccess.FileExists(path)) return [];
|
||||
|
||||
try
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
var savedData = (Dictionary)file.GetVar();
|
||||
var framesArray = (Array)savedData["frames"];
|
||||
|
||||
var frames = new List<GhostFrame>();
|
||||
foreach (var obj in framesArray)
|
||||
{
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
var saveData = JsonSerializer.Deserialize<GhostSaveData>(file.GetAsText(), SaveSystem.JsonOptions);
|
||||
if (saveData == null) return [];
|
||||
|
||||
var frames = new List<GhostFrame>();
|
||||
foreach (var dto in saveData.Frames)
|
||||
frames.Add(new GhostFrame { Timestamp = dto.Timestamp, Position = new Vector2(dto.X, dto.Y) });
|
||||
return frames;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GD.PrintErr($"GhostManager: Failed to load ghost data: {e.Message}");
|
||||
return [];
|
||||
frames.Add((GhostFrame)obj);
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
||||
private double LoadBestTime(int levelIndex)
|
||||
{
|
||||
var path = $"user://ghost_level_{levelIndex}.json";
|
||||
var path = $"user://ghost_level_{levelIndex}.dat";
|
||||
if (!FileAccess.FileExists(path)) return double.MaxValue;
|
||||
|
||||
try
|
||||
{
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
var saveData = JsonSerializer.Deserialize<GhostSaveData>(file.GetAsText(), SaveSystem.JsonOptions);
|
||||
return saveData?.BestTime ?? double.MaxValue;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return double.MaxValue;
|
||||
}
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
var data = (Dictionary)file.GetVar();
|
||||
return (double)data["time"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class InputDeviceManager : Node
|
||||
{
|
||||
public enum InputDevice { Mouse, Keyboard, Gamepad }
|
||||
public static InputDeviceManager Instance { get; private set; }
|
||||
|
||||
public InputDevice CurrentDevice { get; private set; } = InputDevice.Mouse;
|
||||
|
||||
public bool IsPointerless => CurrentDevice is InputDevice.Keyboard or InputDevice.Gamepad;
|
||||
|
||||
[Signal] public delegate void DeviceChangedEventHandler(int device);
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
Input.MouseMode = Input.MouseModeEnum.Visible;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
InputDevice detected;
|
||||
|
||||
if (@event is InputEventMouseMotion or InputEventMouseButton)
|
||||
detected = InputDevice.Mouse;
|
||||
else if (@event is InputEventKey)
|
||||
detected = InputDevice.Keyboard;
|
||||
else if (@event is InputEventJoypadButton)
|
||||
detected = InputDevice.Gamepad;
|
||||
else if (@event is InputEventJoypadMotion joyEvent)
|
||||
{
|
||||
if (Mathf.Abs(joyEvent.AxisValue) <= 0.15f) return;
|
||||
detected = InputDevice.Gamepad;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if (detected == CurrentDevice) return;
|
||||
|
||||
CurrentDevice = detected;
|
||||
Input.MouseMode = CurrentDevice == InputDevice.Mouse
|
||||
? Input.MouseModeEnum.Visible
|
||||
: Input.MouseModeEnum.Hidden;
|
||||
|
||||
EmitSignal(SignalName.DeviceChanged, (int)CurrentDevice);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://b81610g8fd6p1
|
||||
@@ -1,176 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Mr.BrickAdventures.scripts.State;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
/// <summary>
|
||||
/// Save system that serializes state to JSON using DTOs.
|
||||
/// </summary>
|
||||
public partial class SaveSystem : Node
|
||||
{
|
||||
[Export] public string SavePath { get; set; } = "user://savegame.json";
|
||||
[Export] public int Version { get; set; } = 2;
|
||||
[Export] public string SavePath { get; set; } = "user://savegame.save";
|
||||
[Export] public int Version { get; set; } = 1;
|
||||
|
||||
public static SaveSystem Instance { get; private set; }
|
||||
|
||||
internal static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
}
|
||||
|
||||
public void SaveGame()
|
||||
{
|
||||
var store = GameStateStore.Instance;
|
||||
if (store == null)
|
||||
var saveData = new Dictionary
|
||||
{
|
||||
GD.PrintErr("SaveSystem: GameStateStore not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to DTO (only serializable data)
|
||||
var saveData = new SaveDataDto
|
||||
{
|
||||
Version = Version,
|
||||
Coins = store.Player.Coins,
|
||||
Lives = store.Player.Lives,
|
||||
CurrentLevel = store.Player.CurrentLevel,
|
||||
CompletedLevels = [.. store.Player.CompletedLevels],
|
||||
UnlockedLevels = new List<int>(store.Player.UnlockedLevels),
|
||||
UnlockedSkillNames = GetSkillNames(store.Player.UnlockedSkills),
|
||||
UnlockedAchievements = new List<string>(store.Player.UnlockedAchievements),
|
||||
Statistics = new Dictionary<string, int>(store.Player.Statistics)
|
||||
{ "player_state", _gameManager.PlayerState},
|
||||
{ "version", Version}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(saveData, JsonOptions);
|
||||
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Write);
|
||||
file.StoreString(json);
|
||||
GD.Print("Game saved to: ", SavePath);
|
||||
EventBus.EmitGameSaved();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GD.PrintErr($"SaveSystem: Failed to save game: {e.Message}");
|
||||
}
|
||||
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("SaveSystem: No save file found.");
|
||||
GD.Print($"Save file version mismatch. Expected: {Version}, Found: {saveDataObj["version"]}");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
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"])
|
||||
{
|
||||
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Read);
|
||||
var json = file.GetAsText();
|
||||
var saveData = JsonSerializer.Deserialize<SaveDataDto>(json, JsonOptions);
|
||||
|
||||
if (saveData == null)
|
||||
{
|
||||
GD.PrintErr("SaveSystem: Failed to deserialize save data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (saveData.Version != Version)
|
||||
{
|
||||
GD.PrintErr($"SaveSystem: Version mismatch. Expected {Version}, found {saveData.Version}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var store = GameStateStore.Instance;
|
||||
if (store == null)
|
||||
{
|
||||
GD.PrintErr("SaveSystem: GameStateStore not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply loaded state
|
||||
store.Player.Coins = saveData.Coins;
|
||||
store.Player.Lives = saveData.Lives;
|
||||
store.Player.CurrentLevel = saveData.CurrentLevel;
|
||||
|
||||
store.Player.CompletedLevels = saveData.CompletedLevels ?? new List<int>();
|
||||
store.Player.UnlockedLevels = saveData.UnlockedLevels ?? new List<int> { 0 };
|
||||
store.Player.UnlockedAchievements = saveData.UnlockedAchievements ?? new List<string>();
|
||||
store.Player.Statistics = saveData.Statistics ?? new Dictionary<string, int>();
|
||||
|
||||
// Reload skills by name from SkillManager
|
||||
store.Player.UnlockedSkills = LoadSkillsByName(saveData.UnlockedSkillNames);
|
||||
|
||||
GD.Print("Game loaded from: ", SavePath);
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GD.PrintErr($"SaveSystem: Failed to load game: {e.Message}");
|
||||
return false;
|
||||
skills.Add(skill);
|
||||
}
|
||||
|
||||
_gameManager.UnlockSkills(skills);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static List<string> GetSkillNames(List<SkillData> skills)
|
||||
{
|
||||
var names = new List<string>();
|
||||
foreach (var skill in skills)
|
||||
{
|
||||
if (skill != null)
|
||||
names.Add(skill.Name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private List<SkillData> LoadSkillsByName(List<string> skillNames)
|
||||
{
|
||||
var skills = new List<SkillData>();
|
||||
if (skillNames == null) return skills;
|
||||
|
||||
var skillManager = SkillManager.Instance;
|
||||
if (skillManager == null)
|
||||
{
|
||||
GD.PrintErr("SaveSystem: SkillManager not available to resolve skill names.");
|
||||
return skills;
|
||||
}
|
||||
|
||||
foreach (var name in skillNames)
|
||||
{
|
||||
var skill = skillManager.GetSkillByName(name);
|
||||
if (skill != null)
|
||||
{
|
||||
skills.Add(skill);
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr($"SaveSystem: Skill '{name}' not found in SkillManager.");
|
||||
}
|
||||
}
|
||||
return skills;
|
||||
}
|
||||
|
||||
|
||||
public bool CheckSaveExists() => FileAccess.FileExists(SavePath);
|
||||
|
||||
public void DeleteSave()
|
||||
{
|
||||
if (FileAccess.FileExists(SavePath))
|
||||
{
|
||||
DirAccess.RemoveAbsolute(ProjectSettings.GlobalizePath(SavePath));
|
||||
GD.Print("Save file deleted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class SettingsManager : Node
|
||||
{
|
||||
public static SettingsManager Instance { get; private set; }
|
||||
|
||||
public float GamepadDeadzone { get; set; } = 0.2f;
|
||||
public float GamepadSensitivity { get; set; } = 1.0f;
|
||||
public string WindowMode { get; set; } = "fullscreen";
|
||||
public Vector2I Resolution { get; set; } = new Vector2I(1920, 1080);
|
||||
|
||||
private static readonly List<Vector2I> CuratedResolutions = new()
|
||||
{
|
||||
// 4:3
|
||||
new Vector2I(640, 480),
|
||||
new Vector2I(800, 600),
|
||||
new Vector2I(1024, 768),
|
||||
new Vector2I(1280, 960),
|
||||
new Vector2I(1600, 1200),
|
||||
// 16:9
|
||||
new Vector2I(1280, 720),
|
||||
new Vector2I(1366, 768),
|
||||
new Vector2I(1600, 900),
|
||||
new Vector2I(1920, 1080),
|
||||
new Vector2I(2560, 1440),
|
||||
new Vector2I(3840, 2160),
|
||||
// 16:10
|
||||
new Vector2I(1280, 800),
|
||||
new Vector2I(1440, 900),
|
||||
new Vector2I(1920, 1200),
|
||||
new Vector2I(2560, 1600),
|
||||
};
|
||||
|
||||
private readonly List<Vector2I> _customResolutions = new();
|
||||
|
||||
private static readonly string[] DeadzoneActions = { "left", "right", "up", "down" };
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
if (ConfigFileHandler.Instance == null)
|
||||
{
|
||||
GD.PushError("SettingsManager: ConfigFileHandler.Instance is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var cfg = ConfigFileHandler.Instance.SettingsConfig;
|
||||
|
||||
// --- display_settings ---
|
||||
WindowMode = cfg.GetValue("display_settings", "window_mode", Variant.From("fullscreen")).AsString();
|
||||
var resStr = cfg.GetValue("display_settings", "resolution", Variant.From("1920x1080")).AsString();
|
||||
Resolution = ParseResolution(resStr, new Vector2I(1920, 1080));
|
||||
|
||||
var customResStr = cfg.GetValue("display_settings", "custom_resolutions", Variant.From("")).AsString();
|
||||
if (!string.IsNullOrWhiteSpace(customResStr))
|
||||
{
|
||||
foreach (var part in customResStr.Split(','))
|
||||
{
|
||||
var r = ParseResolution(part.Trim(), Vector2I.Zero);
|
||||
if (r != Vector2I.Zero)
|
||||
_customResolutions.Add(r);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyDisplaySettings();
|
||||
|
||||
// --- gameplay_settings ---
|
||||
GamepadDeadzone = (float)cfg.GetValue("gameplay_settings", "gamepad_deadzone", Variant.From(0.2)).AsDouble();
|
||||
GamepadSensitivity = (float)cfg.GetValue("gameplay_settings", "gamepad_sensitivity", Variant.From(1.0)).AsDouble();
|
||||
|
||||
ApplyGamepadDeadzone();
|
||||
|
||||
// --- input_settings ---
|
||||
ApplyInputBindings(cfg);
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
// ── public API ───────────────────────────────────────────────────────────
|
||||
|
||||
public List<Vector2I> GetAllResolutions()
|
||||
{
|
||||
var all = new List<Vector2I>(CuratedResolutions);
|
||||
all.AddRange(_customResolutions);
|
||||
return all;
|
||||
}
|
||||
|
||||
public void SaveDisplaySettings()
|
||||
{
|
||||
var cfg = ConfigFileHandler.Instance.SettingsConfig;
|
||||
cfg.SetValue("display_settings", "window_mode", WindowMode);
|
||||
cfg.SetValue("display_settings", "resolution", $"{Resolution.X}x{Resolution.Y}");
|
||||
cfg.SetValue("display_settings", "custom_resolutions", BuildCustomResolutionsString());
|
||||
cfg.Save(ConfigFileHandler.SettingsPath);
|
||||
}
|
||||
|
||||
public void SaveGameplaySettings()
|
||||
{
|
||||
var cfg = ConfigFileHandler.Instance.SettingsConfig;
|
||||
cfg.SetValue("gameplay_settings", "gamepad_deadzone", (double)GamepadDeadzone);
|
||||
cfg.SetValue("gameplay_settings", "gamepad_sensitivity", (double)GamepadSensitivity);
|
||||
cfg.Save(ConfigFileHandler.SettingsPath);
|
||||
}
|
||||
|
||||
public void SaveInputSettings()
|
||||
{
|
||||
var cfg = ConfigFileHandler.Instance.SettingsConfig;
|
||||
foreach (var action in InputMap.GetActions())
|
||||
{
|
||||
if (action.ToString().StartsWith("ui_")) continue;
|
||||
foreach (var ev in InputMap.ActionGetEvents(action))
|
||||
{
|
||||
if (ev is InputEventKey key)
|
||||
{
|
||||
cfg.SetValue("input_settings", action, (long)key.PhysicalKeycode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cfg.Save(ConfigFileHandler.SettingsPath);
|
||||
}
|
||||
|
||||
// ── apply helpers ────────────────────────────────────────────────────────
|
||||
|
||||
public void ApplyDisplaySettings()
|
||||
{
|
||||
switch (WindowMode)
|
||||
{
|
||||
case "fullscreen":
|
||||
DisplayServer.WindowSetMode(DisplayServer.WindowMode.Fullscreen);
|
||||
break;
|
||||
case "borderless":
|
||||
DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed);
|
||||
DisplayServer.WindowSetFlag(DisplayServer.WindowFlags.Borderless, true);
|
||||
DisplayServer.WindowSetSize(Resolution);
|
||||
break;
|
||||
default: // "windowed"
|
||||
DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed);
|
||||
DisplayServer.WindowSetFlag(DisplayServer.WindowFlags.Borderless, false);
|
||||
DisplayServer.WindowSetSize(Resolution);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyGamepadDeadzone()
|
||||
{
|
||||
foreach (var action in DeadzoneActions)
|
||||
{
|
||||
if (InputMap.HasAction(action))
|
||||
InputMap.ActionSetDeadzone(action, GamepadDeadzone);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyInputBindings(ConfigFile cfg)
|
||||
{
|
||||
if (!cfg.HasSection("input_settings")) return;
|
||||
|
||||
foreach (var actionName in cfg.GetSectionKeys("input_settings"))
|
||||
{
|
||||
if (actionName.StartsWith("ui_")) continue;
|
||||
if (!InputMap.HasAction(actionName)) continue;
|
||||
|
||||
var scancode = (Key)(long)cfg.GetValue("input_settings", actionName);
|
||||
|
||||
// Remove existing keyboard events for this action
|
||||
var events = InputMap.ActionGetEvents(actionName);
|
||||
foreach (var ev in events)
|
||||
{
|
||||
if (ev is InputEventKey)
|
||||
InputMap.ActionEraseEvent(actionName, ev);
|
||||
}
|
||||
|
||||
// Add the saved key
|
||||
var newKey = new InputEventKey { PhysicalKeycode = scancode };
|
||||
InputMap.ActionAddEvent(actionName, newKey);
|
||||
}
|
||||
}
|
||||
|
||||
// ── util ─────────────────────────────────────────────────────────────────
|
||||
|
||||
private static Vector2I ParseResolution(string s, Vector2I fallback)
|
||||
{
|
||||
var parts = s.Split('x');
|
||||
if (parts.Length == 2 && int.TryParse(parts[0], out var w) && int.TryParse(parts[1], out var h))
|
||||
return new Vector2I(w, h);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private string BuildCustomResolutionsString()
|
||||
{
|
||||
var parts = new List<string>();
|
||||
foreach (var r in _customResolutions)
|
||||
parts.Add($"{r.X}x{r.Y}");
|
||||
return string.Join(",", parts);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://d4jyxtm4jgtka
|
||||
@@ -10,30 +10,23 @@ namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class SkillManager : Node
|
||||
{
|
||||
private GameManager _gameManager;
|
||||
private PlayerController _player;
|
||||
private GameStateStore Store => GameStateStore.Instance;
|
||||
|
||||
[Export] public Array<SkillData> AvailableSkills { get; set; } = [];
|
||||
|
||||
|
||||
public Dictionary ActiveComponents { get; private set; } = new();
|
||||
|
||||
public static SkillManager Instance { get; private set; }
|
||||
|
||||
[Signal]
|
||||
public delegate void ActiveThrowSkillChangedEventHandler(BrickThrowComponent throwComponent);
|
||||
[Signal]
|
||||
public delegate void SkillRemovedEventHandler(SkillData skillData);
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called by the PlayerController from its _Ready method to register itself with the manager.
|
||||
/// </summary>
|
||||
@@ -46,7 +39,7 @@ public partial class SkillManager : Node
|
||||
{
|
||||
UnregisterPlayer();
|
||||
}
|
||||
|
||||
|
||||
_player = player;
|
||||
if (_player != null)
|
||||
{
|
||||
@@ -68,7 +61,7 @@ public partial class SkillManager : Node
|
||||
}
|
||||
_player = null;
|
||||
}
|
||||
|
||||
|
||||
public void AddSkill(SkillData skillData)
|
||||
{
|
||||
// Ensure a valid player is registered before adding a skill.
|
||||
@@ -77,17 +70,27 @@ public partial class SkillManager : Node
|
||||
GD.Print("SkillManager: Player not available to add skill.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (ActiveComponents.ContainsKey(skillData.Name))
|
||||
return;
|
||||
|
||||
if (skillData.Type == SkillType.Throw)
|
||||
{
|
||||
// Remove any other active throw skill before adding the new one
|
||||
foreach (var sd in AvailableSkills)
|
||||
var unlocked = _gameManager.GetUnlockedSkills();
|
||||
foreach (var sd in unlocked)
|
||||
{
|
||||
if (sd != skillData && sd.Type == SkillType.Throw)
|
||||
RemoveSkill(sd.Name);
|
||||
SkillData data = null;
|
||||
foreach (var s in AvailableSkills)
|
||||
{
|
||||
if (s == sd)
|
||||
{
|
||||
data = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Remove other throw skills if a new one is added
|
||||
if (data is { Type: SkillType.Throw })
|
||||
RemoveSkill(data.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +98,9 @@ public partial class SkillManager : Node
|
||||
if (instance is ISkill skill)
|
||||
{
|
||||
// Initialize the skill with the registered player instance.
|
||||
skill.Initialize(_player, skillData);
|
||||
skill.Initialize(_player, skillData);
|
||||
skill.Activate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr($"Skill scene for '{skillData.Name}' does not implement ISkill!");
|
||||
@@ -108,18 +111,18 @@ public partial class SkillManager : Node
|
||||
// Add the skill node as a child of the player.
|
||||
_player.AddChild(instance);
|
||||
ActiveComponents[skillData.Name] = instance;
|
||||
|
||||
|
||||
if (instance is BrickThrowComponent btc)
|
||||
{
|
||||
EmitSignalActiveThrowSkillChanged(btc);
|
||||
EmitSignalActiveThrowSkillChanged(btc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RemoveSkill(string skillName)
|
||||
{
|
||||
if (!ActiveComponents.TryGetValue(skillName, out var component))
|
||||
return;
|
||||
|
||||
|
||||
if (component.AsGodotObject() is BrickThrowComponent)
|
||||
{
|
||||
EmitSignalActiveThrowSkillChanged(null);
|
||||
@@ -130,15 +133,24 @@ public partial class SkillManager : Node
|
||||
{
|
||||
skill.Deactivate();
|
||||
}
|
||||
|
||||
|
||||
if (IsInstanceValid(inst))
|
||||
inst.QueueFree();
|
||||
|
||||
var skills = _gameManager.GetUnlockedSkills();
|
||||
foreach (var s in skills)
|
||||
{
|
||||
if (s.Name == skillName)
|
||||
{
|
||||
s.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ActiveComponents.Remove(skillName);
|
||||
var sd = GetSkillByName(skillName);
|
||||
if (sd != null) EmitSignalSkillRemoved(sd);
|
||||
}
|
||||
|
||||
|
||||
private void RemoveAllActiveSkills()
|
||||
{
|
||||
// Create a copy of keys to avoid modification during iteration
|
||||
@@ -154,14 +166,17 @@ public partial class SkillManager : Node
|
||||
public void ApplyUnlockedSkills()
|
||||
{
|
||||
if (_player == null || !IsInstanceValid(_player)) return;
|
||||
if (Store == null) return;
|
||||
|
||||
foreach (var sd in AvailableSkills)
|
||||
{
|
||||
if (Store.IsSkillUnlocked(sd))
|
||||
if (_gameManager.IsSkillUnlocked(sd))
|
||||
{
|
||||
CallDeferred(MethodName.AddSkill, sd);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveSkill(sd.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,16 +187,12 @@ public partial class SkillManager : Node
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsSkillActive(SkillData skill)
|
||||
{
|
||||
return skill != null && ActiveComponents.ContainsKey(skill.Name);
|
||||
}
|
||||
|
||||
public void ActivateSkill(SkillData skill)
|
||||
{
|
||||
if (!ActiveComponents.ContainsKey(skill.Name))
|
||||
{
|
||||
AddSkill(skill);
|
||||
skill.IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +201,7 @@ public partial class SkillManager : Node
|
||||
if (ActiveComponents.ContainsKey(skill.Name))
|
||||
{
|
||||
RemoveSkill(skill.Name);
|
||||
skill.IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,9 @@ namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class SpeedRunManager : Node
|
||||
{
|
||||
public static SpeedRunManager Instance { get; private set; }
|
||||
|
||||
public override void _EnterTree() => Instance = this;
|
||||
public override void _ExitTree() { if (Instance == this) Instance = null; }
|
||||
|
||||
public bool IsRunning { get; private set; } = false;
|
||||
|
||||
public bool IsVisible { get; private set; } = false;
|
||||
|
||||
private double _startTime;
|
||||
private double _levelStartTime;
|
||||
private List<double> _splits = [];
|
||||
@@ -20,7 +16,7 @@ public partial class SpeedRunManager : Node
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!IsRunning) return;
|
||||
if (!IsRunning || !IsVisible) return;
|
||||
|
||||
EmitSignalTimeUpdated(GetCurrentTotalTime(), GetCurrentLevelTime());
|
||||
}
|
||||
|
||||
78
Autoloads/StatisticsManager.cs
Normal file
78
Autoloads/StatisticsManager.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class StatisticsManager : Node
|
||||
{
|
||||
private GameManager _gameManager;
|
||||
private AchievementManager _achievementManager;
|
||||
private Dictionary<string, Variant> _stats = new();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_gameManager = GetNode<GameManager>("/root/GameManager");
|
||||
_achievementManager = GetNode<AchievementManager>("/root/AchievementManager");
|
||||
LoadStatistics();
|
||||
}
|
||||
|
||||
private void LoadStatistics()
|
||||
{
|
||||
if (_gameManager.PlayerState.TryGetValue("statistics", out var statsObj))
|
||||
{
|
||||
_stats = (Dictionary<string, Variant>)statsObj;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stats = new Dictionary<string, Variant>();
|
||||
_gameManager.PlayerState["statistics"] = _stats;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increases a numerical statistic by a given amount.
|
||||
/// </summary>
|
||||
public void IncrementStat(string statName, int amount = 1)
|
||||
{
|
||||
if (_stats.TryGetValue(statName, out var currentValue))
|
||||
{
|
||||
_stats[statName] = (int)currentValue + amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stats[statName] = amount;
|
||||
}
|
||||
GD.Print($"Stat '{statName}' updated to: {_stats[statName]}");
|
||||
CheckAchievementsForStat(statName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a statistic.
|
||||
/// </summary>
|
||||
public Variant GetStat(string statName, Variant defaultValue = default)
|
||||
{
|
||||
return _stats.TryGetValue(statName, out var value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the updated stat meets the criteria for any achievements.
|
||||
/// </summary>
|
||||
private void CheckAchievementsForStat(string statName)
|
||||
{
|
||||
switch (statName)
|
||||
{
|
||||
case "enemies_defeated":
|
||||
if ((int)GetStat(statName, 0) >= 100)
|
||||
{
|
||||
_achievementManager.UnlockAchievement("slayer_100_enemies");
|
||||
}
|
||||
break;
|
||||
case "jumps_made":
|
||||
if ((int)GetStat(statName, 0) >= 1000)
|
||||
{
|
||||
_achievementManager.UnlockAchievement("super_jumper");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Autoloads/StatisticsManager.cs.uid
Normal file
1
Autoloads/StatisticsManager.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c5p3l2mhkw0p4
|
||||
@@ -1,22 +1,11 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.Autoloads;
|
||||
|
||||
public partial class UIManager : Node
|
||||
{
|
||||
public static UIManager Instance { get; private set; }
|
||||
|
||||
private readonly System.Collections.Generic.List<Control> UiStack = new();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
[Export] public Array<Control> UiStack { get; set; } = new();
|
||||
|
||||
[Signal] public delegate void ScreenPushedEventHandler(Control screen);
|
||||
[Signal] public delegate void ScreenPoppedEventHandler(Control screen);
|
||||
@@ -45,19 +34,19 @@ public partial class UIManager : Node
|
||||
return;
|
||||
}
|
||||
|
||||
var top = UiStack[^1];
|
||||
var top = (Control)UiStack[^1];
|
||||
UiStack.RemoveAt(UiStack.Count - 1);
|
||||
top.Hide();
|
||||
top.SetProcessInput(false);
|
||||
EmitSignalScreenPopped(top);
|
||||
top.AcceptEvent();
|
||||
|
||||
if (UiStack.Count > 0) UiStack[^1].GrabFocus();
|
||||
if (UiStack.Count > 0) ((Control)UiStack[^1]).GrabFocus();
|
||||
}
|
||||
|
||||
public Control TopScreen() => UiStack.Count > 0 ? UiStack[^1] : null;
|
||||
|
||||
public bool IsScreenOnTop(Control screen) => UiStack.Count > 0 && UiStack[^1] == screen;
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Godot.NET.Sdk/4.6.2">
|
||||
<Project Sdk="Godot.NET.Sdk/4.5.0">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public static class CaGenerator
|
||||
{
|
||||
public static bool[,] Generate(CaGeneratorSettings s)
|
||||
{
|
||||
var rng = new Random(s.Seed);
|
||||
return s.Mode switch
|
||||
{
|
||||
CaMode.Cave => GenerateCave(s, rng),
|
||||
CaMode.Platform => GeneratePlatform(s, rng),
|
||||
CaMode.Terrain => GenerateTerrain(s, rng),
|
||||
_ => GenerateCave(s, rng),
|
||||
};
|
||||
}
|
||||
|
||||
public static bool[,] Smooth(bool[,] grid) => SmoothPass(grid, 5);
|
||||
|
||||
// ── Cave ──────────────────────────────────────────────────────────────
|
||||
private static bool[,] GenerateCave(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
var grid = RandomFill(s.Width, s.Height, s.FillDensity, rng);
|
||||
if (s.BorderWalls) EnforceBorder(grid);
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
{
|
||||
grid = SmoothPass(grid, 5);
|
||||
if (s.BorderWalls) EnforceBorder(grid);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Platform ──────────────────────────────────────────────────────────
|
||||
private static bool[,] GeneratePlatform(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
int w = s.Width, h = s.Height;
|
||||
var grid = new bool[w, h];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
grid[x, h - 1] = true;
|
||||
grid[x, h - 2] = true;
|
||||
|
||||
for (int y = 0; y < h - 2; y++)
|
||||
{
|
||||
// Density linearly increases from 10% at top to 60% at bottom,
|
||||
// scaled by user's FillDensity relative to default 0.48.
|
||||
float t = (float)y / (h - 3);
|
||||
float rowDensity = (0.1f + t * 0.5f) * (s.FillDensity / 0.48f);
|
||||
grid[x, y] = rng.NextDouble() < rowDensity;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
{
|
||||
// Threshold 4 (not 5): horizontal platform groups survive, isolated
|
||||
// vertical pixels collapse into flat platforms.
|
||||
grid = SmoothPass(grid, 4);
|
||||
for (int x = 0; x < w; x++) { grid[x, h - 1] = true; grid[x, h - 2] = true; }
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Terrain ───────────────────────────────────────────────────────────
|
||||
private static bool[,] GenerateTerrain(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
int w = s.Width, h = s.Height;
|
||||
var grid = new bool[w, h];
|
||||
|
||||
// Start terrain surface at ~60% from bottom (40% from top)
|
||||
int surfaceRow = (int)(h * 0.4f);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int delta = rng.Next(-2, 3);
|
||||
surfaceRow = Math.Clamp(surfaceRow + delta, h / 6, h - 2);
|
||||
|
||||
for (int y = surfaceRow; y < h; y++)
|
||||
grid[x, y] = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
grid = SmoothPass(grid, 5);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Shared helpers ────────────────────────────────────────────────
|
||||
private static bool[,] RandomFill(int w, int h, float density, Random rng)
|
||||
{
|
||||
var grid = new bool[w, h];
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
grid[x, y] = rng.NextDouble() < density;
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static bool[,] SmoothPass(bool[,] grid, int threshold)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
var next = new bool[w, h];
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
next[x, y] = CountSolidNeighbors(grid, x, y) >= threshold;
|
||||
return next;
|
||||
}
|
||||
|
||||
private static int CountSolidNeighbors(bool[,] grid, int cx, int cy)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1), count = 0;
|
||||
for (int dx = -1; dx <= 1; dx++)
|
||||
for (int dy = -1; dy <= 1; dy++)
|
||||
{
|
||||
if (dx == 0 && dy == 0) continue;
|
||||
int nx = cx + dx, ny = cy + dy;
|
||||
// Out-of-bounds counts as solid (closes cave edges naturally)
|
||||
if (nx < 0 || nx >= w || ny < 0 || ny >= h) count++;
|
||||
else if (grid[nx, ny]) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void EnforceBorder(bool[,] grid)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
for (int x = 0; x < w; x++) { grid[x, 0] = true; grid[x, h - 1] = true; }
|
||||
for (int y = 0; y < h; y++) { grid[0, y] = true; grid[w - 1, y] = true; }
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://exr10b7nmkgn
|
||||
@@ -1,23 +0,0 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public enum CaMode { Cave, Platform, Terrain }
|
||||
|
||||
public class CaGeneratorSettings
|
||||
{
|
||||
public CaMode Mode { get; set; } = CaMode.Cave;
|
||||
public int Width { get; set; } = 40;
|
||||
public int Height { get; set; } = 22;
|
||||
public Vector2I Offset { get; set; } = Vector2I.Zero;
|
||||
public float FillDensity { get; set; } = 0.48f;
|
||||
public int SmoothingPasses { get; set; } = 4;
|
||||
public bool BorderWalls { get; set; } = true;
|
||||
public int Seed { get; set; } = 12345;
|
||||
// TerrainSet == -1 → raw tile mode
|
||||
public int TerrainSet { get; set; } = 0;
|
||||
public int Terrain { get; set; } = 0;
|
||||
// Used only when TerrainSet == -1
|
||||
public int SourceId { get; set; } = 0;
|
||||
public Vector2I AtlasCoords { get; set; } = Vector2I.Zero;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://isnscgr1thvc
|
||||
@@ -1,79 +0,0 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaGeneratorTestRunner : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
int pass = 0, fail = 0;
|
||||
|
||||
void Assert(bool cond, string msg)
|
||||
{
|
||||
if (cond) { GD.Print($" PASS: {msg}"); pass++; }
|
||||
else { GD.PrintErr($" FAIL: {msg}"); fail++; }
|
||||
}
|
||||
|
||||
GD.Print("=== CaGenerator Tests ===");
|
||||
|
||||
// Grid dimensions
|
||||
var s = new CaGeneratorSettings { Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var g = CaGenerator.Generate(s);
|
||||
Assert(g.GetLength(0) == 20, "Width == 20");
|
||||
Assert(g.GetLength(1) == 15, "Height == 15");
|
||||
|
||||
// Determinism
|
||||
var g2 = CaGenerator.Generate(s);
|
||||
bool det = true;
|
||||
for (int x = 0; x < 20 && det; x++)
|
||||
for (int y = 0; y < 15 && det; y++)
|
||||
if (g[x, y] != g2[x, y]) det = false;
|
||||
Assert(det, "Same seed → same output");
|
||||
|
||||
// Different seeds → different output
|
||||
var s2 = new CaGeneratorSettings { Width = 20, Height = 15, SmoothingPasses = 0, Seed = 99 };
|
||||
var g3 = CaGenerator.Generate(s2);
|
||||
bool diff = false;
|
||||
for (int x = 0; x < 20 && !diff; x++)
|
||||
for (int y = 0; y < 15 && !diff; y++)
|
||||
if (g[x, y] != g3[x, y]) diff = true;
|
||||
Assert(diff, "Different seeds → different output");
|
||||
|
||||
// Cave border walls
|
||||
var sb = new CaGeneratorSettings { Width = 20, Height = 15, BorderWalls = true, SmoothingPasses = 0, Seed = 42 };
|
||||
var gb = CaGenerator.Generate(sb);
|
||||
bool border = true;
|
||||
for (int x = 0; x < 20; x++) if (!gb[x, 0] || !gb[x, 14]) { border = false; break; }
|
||||
for (int y = 0; y < 15; y++) if (!gb[0, y] || !gb[19, y]) { border = false; break; }
|
||||
Assert(border, "Cave: border cells all solid");
|
||||
|
||||
// Platform floor
|
||||
var sp = new CaGeneratorSettings { Mode = CaMode.Platform, Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var gp = CaGenerator.Generate(sp);
|
||||
bool floor = true;
|
||||
for (int x = 0; x < 20; x++) if (!gp[x, 14] || !gp[x, 13]) { floor = false; break; }
|
||||
Assert(floor, "Platform: bottom 2 rows solid");
|
||||
|
||||
// Platform: top row not all solid (mostly empty at top)
|
||||
int topSolid = 0;
|
||||
for (int x = 0; x < 20; x++) if (gp[x, 0]) topSolid++;
|
||||
Assert(topSolid < 15, "Platform: top row mostly empty");
|
||||
|
||||
// Terrain: bottom always solid
|
||||
var st = new CaGeneratorSettings { Mode = CaMode.Terrain, Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var gt = CaGenerator.Generate(st);
|
||||
bool terrBottom = true;
|
||||
for (int x = 0; x < 20; x++) if (!gt[x, 14]) { terrBottom = false; break; }
|
||||
Assert(terrBottom, "Terrain: bottom row always solid");
|
||||
|
||||
// Smooth: output same dimensions
|
||||
var smoothed = CaGenerator.Smooth(g);
|
||||
Assert(smoothed.GetLength(0) == 20, "Smooth: width preserved");
|
||||
Assert(smoothed.GetLength(1) == 15, "Smooth: height preserved");
|
||||
|
||||
GD.Print($"=== Results: {pass} passed, {fail} failed ===");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
uid://6y4snwf31boh
|
||||
@@ -1,360 +0,0 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaLevelGeneratorDock : Control
|
||||
{
|
||||
public CaLevelGeneratorPlugin Plugin { get; set; }
|
||||
|
||||
// Controls referenced in Task 8 wiring
|
||||
private OptionButton _layerDropdown;
|
||||
private OptionButton _terrainDropdown;
|
||||
private HBoxContainer _rawTileRow;
|
||||
private SpinBox _sourceIdSpin;
|
||||
private SpinBox _atlasXSpin;
|
||||
private SpinBox _atlasYSpin;
|
||||
private Button _caveBtn;
|
||||
private Button _platformBtn;
|
||||
private Button _terrainBtn;
|
||||
private SpinBox _widthSpin;
|
||||
private SpinBox _heightSpin;
|
||||
private SpinBox _offsetXSpin;
|
||||
private SpinBox _offsetYSpin;
|
||||
private HSlider _densitySlider;
|
||||
private Label _densityLabel;
|
||||
private HSlider _smoothPassSlider;
|
||||
private Label _smoothPassLabel;
|
||||
private CheckBox _borderCheck;
|
||||
private SpinBox _seedSpin;
|
||||
private Button _genBtn;
|
||||
private Button _smoothBtn;
|
||||
private Button _clearBtn;
|
||||
|
||||
private CaMode _mode = CaMode.Cave;
|
||||
|
||||
private System.Collections.Generic.List<TileMapLayer> _layers = new();
|
||||
private TileMapLayer _selectedLayer;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
CustomMinimumSize = new Vector2(200, 0);
|
||||
var scroll = new ScrollContainer();
|
||||
scroll.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect);
|
||||
scroll.SizeFlagsVertical = SizeFlags.ExpandFill;
|
||||
AddChild(scroll);
|
||||
|
||||
var vbox = new VBoxContainer();
|
||||
vbox.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
scroll.AddChild(vbox);
|
||||
|
||||
// Target Layer
|
||||
vbox.AddChild(new Label { Text = "Target Layer" });
|
||||
_layerDropdown = new OptionButton();
|
||||
_layerDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
vbox.AddChild(_layerDropdown);
|
||||
|
||||
// Terrain
|
||||
vbox.AddChild(new Label { Text = "Terrain" });
|
||||
_terrainDropdown = new OptionButton();
|
||||
_terrainDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
vbox.AddChild(_terrainDropdown);
|
||||
|
||||
// Raw tile row (hidden when terrain is available)
|
||||
_rawTileRow = new HBoxContainer();
|
||||
_rawTileRow.Visible = false;
|
||||
_rawTileRow.AddChild(new Label { Text = "Src" });
|
||||
_sourceIdSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_sourceIdSpin);
|
||||
_rawTileRow.AddChild(new Label { Text = "X" });
|
||||
_atlasXSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_atlasXSpin);
|
||||
_rawTileRow.AddChild(new Label { Text = "Y" });
|
||||
_atlasYSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_atlasYSpin);
|
||||
vbox.AddChild(_rawTileRow);
|
||||
|
||||
// Mode toggle
|
||||
vbox.AddChild(new Label { Text = "Mode" });
|
||||
var modeRow = new HBoxContainer();
|
||||
modeRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
_caveBtn = MakeModeButton("Cave", () => SetMode(CaMode.Cave));
|
||||
_platformBtn = MakeModeButton("Platform", () => SetMode(CaMode.Platform));
|
||||
_terrainBtn = MakeModeButton("Terrain", () => SetMode(CaMode.Terrain));
|
||||
_caveBtn.ButtonPressed = true;
|
||||
modeRow.AddChild(_caveBtn);
|
||||
modeRow.AddChild(_platformBtn);
|
||||
modeRow.AddChild(_terrainBtn);
|
||||
vbox.AddChild(modeRow);
|
||||
|
||||
vbox.AddChild(new HSeparator());
|
||||
|
||||
// Width / Height
|
||||
var dimRow = new HBoxContainer();
|
||||
dimRow.AddChild(MakeSpinColumn("Width", out _widthSpin, 5, 500, 40));
|
||||
dimRow.AddChild(MakeSpinColumn("Height", out _heightSpin, 5, 500, 22));
|
||||
vbox.AddChild(dimRow);
|
||||
|
||||
// Offset X / Y
|
||||
var offRow = new HBoxContainer();
|
||||
offRow.AddChild(MakeSpinColumn("Offset X", out _offsetXSpin, -9999, 9999, 0));
|
||||
offRow.AddChild(MakeSpinColumn("Offset Y", out _offsetYSpin, -9999, 9999, 0));
|
||||
vbox.AddChild(offRow);
|
||||
|
||||
// Fill Density
|
||||
var densHeader = new HBoxContainer();
|
||||
densHeader.AddChild(new Label { Text = "Fill Density", SizeFlagsHorizontal = SizeFlags.ExpandFill });
|
||||
_densityLabel = new Label { Text = "48%" };
|
||||
densHeader.AddChild(_densityLabel);
|
||||
vbox.AddChild(densHeader);
|
||||
_densitySlider = new HSlider { MinValue = 0, MaxValue = 100, Value = 48, Step = 1 };
|
||||
_densitySlider.ValueChanged += v => _densityLabel.Text = $"{(int)v}%";
|
||||
vbox.AddChild(_densitySlider);
|
||||
|
||||
// Smoothing Passes
|
||||
var smoothHeader = new HBoxContainer();
|
||||
smoothHeader.AddChild(new Label { Text = "Smoothing Passes", SizeFlagsHorizontal = SizeFlags.ExpandFill });
|
||||
_smoothPassLabel = new Label { Text = "4" };
|
||||
smoothHeader.AddChild(_smoothPassLabel);
|
||||
vbox.AddChild(smoothHeader);
|
||||
_smoothPassSlider = new HSlider { MinValue = 0, MaxValue = 10, Value = 4, Step = 1 };
|
||||
_smoothPassSlider.ValueChanged += v => _smoothPassLabel.Text = $"{(int)v}";
|
||||
vbox.AddChild(_smoothPassSlider);
|
||||
|
||||
// Border walls
|
||||
_borderCheck = new CheckBox { Text = "Solid border walls", ButtonPressed = true };
|
||||
vbox.AddChild(_borderCheck);
|
||||
|
||||
// Seed
|
||||
vbox.AddChild(new Label { Text = "Seed" });
|
||||
var seedRow = new HBoxContainer();
|
||||
_seedSpin = new SpinBox { MinValue = 0, MaxValue = int.MaxValue, Value = 12345,
|
||||
AllowGreater = true, SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
var randBtn = new Button { Text = "🎲" };
|
||||
randBtn.Pressed += () => _seedSpin.Value = GD.Randi();
|
||||
seedRow.AddChild(_seedSpin);
|
||||
seedRow.AddChild(randBtn);
|
||||
vbox.AddChild(seedRow);
|
||||
|
||||
vbox.AddChild(new HSeparator());
|
||||
|
||||
// Action buttons
|
||||
_genBtn = new Button { Text = "▶ Generate", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
vbox.AddChild(_genBtn);
|
||||
|
||||
var actionRow = new HBoxContainer();
|
||||
actionRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
_smoothBtn = new Button { Text = "✦ Smooth", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_clearBtn = new Button { Text = "✕ Clear", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
actionRow.AddChild(_smoothBtn);
|
||||
actionRow.AddChild(_clearBtn);
|
||||
vbox.AddChild(actionRow);
|
||||
|
||||
_layerDropdown.ItemSelected += OnLayerSelected;
|
||||
_terrainDropdown.ItemSelected += _ => SaveSettings();
|
||||
_genBtn.Pressed += OnGenerate;
|
||||
_smoothBtn.Pressed += OnSmooth;
|
||||
_clearBtn.Pressed += OnClear;
|
||||
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
public void OnSceneChanged(Node sceneRoot)
|
||||
{
|
||||
ScanLayers(sceneRoot);
|
||||
RestoreLastLayer(sceneRoot?.SceneFilePath ?? "");
|
||||
}
|
||||
|
||||
private void SetMode(CaMode mode)
|
||||
{
|
||||
_mode = mode;
|
||||
_caveBtn.ButtonPressed = mode == CaMode.Cave;
|
||||
_platformBtn.ButtonPressed = mode == CaMode.Platform;
|
||||
_terrainBtn.ButtonPressed = mode == CaMode.Terrain;
|
||||
}
|
||||
|
||||
private static Button MakeModeButton(string text, System.Action onPressed)
|
||||
{
|
||||
var btn = new Button { Text = text, ToggleMode = true,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
btn.Pressed += onPressed;
|
||||
return btn;
|
||||
}
|
||||
|
||||
private static Control MakeSpinColumn(string label, out SpinBox spin,
|
||||
double min, double max, double value)
|
||||
{
|
||||
var col = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
col.AddChild(new Label { Text = label });
|
||||
spin = new SpinBox { MinValue = min, MaxValue = max, Value = value,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
col.AddChild(spin);
|
||||
return col;
|
||||
}
|
||||
|
||||
private void ScanLayers(Node root)
|
||||
{
|
||||
_layers.Clear();
|
||||
_layerDropdown.Clear();
|
||||
if (root == null) return;
|
||||
CollectLayers(root);
|
||||
foreach (var layer in _layers)
|
||||
_layerDropdown.AddItem(layer.Name);
|
||||
if (_layers.Count > 0) OnLayerSelected(0);
|
||||
}
|
||||
|
||||
private void CollectLayers(Node node)
|
||||
{
|
||||
if (node is TileMapLayer layer) _layers.Add(layer);
|
||||
foreach (Node child in node.GetChildren()) CollectLayers(child);
|
||||
}
|
||||
|
||||
private void OnLayerSelected(long index)
|
||||
{
|
||||
if (index < 0 || index >= _layers.Count) return;
|
||||
_selectedLayer = _layers[(int)index];
|
||||
PopulateTerrainDropdown(_selectedLayer);
|
||||
|
||||
var sceneRoot = EditorInterface.Singleton.GetEditedSceneRoot();
|
||||
if (sceneRoot != null)
|
||||
{
|
||||
var key = $"ca_generator/last_layer_{sceneRoot.SceneFilePath}";
|
||||
EditorInterface.Singleton.GetEditorSettings()
|
||||
.SetSetting(key, _selectedLayer.GetPath().ToString());
|
||||
}
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private void RestoreLastLayer(string sceneFilePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sceneFilePath) || _layers.Count == 0) return;
|
||||
var key = $"ca_generator/last_layer_{sceneFilePath}";
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
if (!es.HasSetting(key)) return;
|
||||
var path = es.GetSetting(key).AsString();
|
||||
for (int i = 0; i < _layers.Count; i++)
|
||||
{
|
||||
if (_layers[i].GetPath().ToString() == path)
|
||||
{
|
||||
_layerDropdown.Select(i);
|
||||
OnLayerSelected(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateTerrainDropdown(TileMapLayer layer)
|
||||
{
|
||||
_terrainDropdown.Clear();
|
||||
var tileSet = layer.TileSet;
|
||||
bool hasTerrains = false;
|
||||
|
||||
if (tileSet != null)
|
||||
{
|
||||
for (int ts = 0; ts < tileSet.GetTerrainSetsCount(); ts++)
|
||||
{
|
||||
for (int t = 0; t < tileSet.GetTerrainsCount(ts); t++)
|
||||
{
|
||||
_terrainDropdown.AddItem(tileSet.GetTerrainName(ts, t));
|
||||
_terrainDropdown.SetItemMetadata(
|
||||
_terrainDropdown.ItemCount - 1,
|
||||
Variant.From((ts << 16) | t));
|
||||
hasTerrains = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_terrainDropdown.Visible = hasTerrains;
|
||||
_rawTileRow.Visible = !hasTerrains;
|
||||
}
|
||||
|
||||
private CaGeneratorSettings BuildSettings()
|
||||
{
|
||||
int terrainSet = -1, terrain = 0;
|
||||
if (_terrainDropdown.Visible && _terrainDropdown.ItemCount > 0)
|
||||
{
|
||||
int packed = _terrainDropdown.GetSelectedMetadata().AsInt32();
|
||||
terrainSet = packed >> 16;
|
||||
terrain = packed & 0xFFFF;
|
||||
}
|
||||
|
||||
return new CaGeneratorSettings
|
||||
{
|
||||
Mode = _mode,
|
||||
Width = (int)_widthSpin.Value,
|
||||
Height = (int)_heightSpin.Value,
|
||||
Offset = new Vector2I((int)_offsetXSpin.Value, (int)_offsetYSpin.Value),
|
||||
FillDensity = (float)_densitySlider.Value / 100f,
|
||||
SmoothingPasses = (int)_smoothPassSlider.Value,
|
||||
BorderWalls = _borderCheck.ButtonPressed,
|
||||
Seed = (int)_seedSpin.Value,
|
||||
TerrainSet = terrainSet,
|
||||
Terrain = terrain,
|
||||
SourceId = (int)_sourceIdSpin.Value,
|
||||
AtlasCoords = new Vector2I((int)_atlasXSpin.Value, (int)_atlasYSpin.Value),
|
||||
};
|
||||
}
|
||||
|
||||
private void OnGenerate()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
var settings = BuildSettings();
|
||||
var grid = CaGenerator.Generate(settings);
|
||||
TilemapPainter.Paint(_selectedLayer, grid, settings, Plugin.UndoRedo);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private void OnSmooth()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
TilemapPainter.Smooth(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
|
||||
}
|
||||
|
||||
private void OnClear()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
TilemapPainter.Clear(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
|
||||
}
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
es.SetSetting("ca_generator/mode", (int)_mode);
|
||||
es.SetSetting("ca_generator/width", (int)_widthSpin.Value);
|
||||
es.SetSetting("ca_generator/height", (int)_heightSpin.Value);
|
||||
es.SetSetting("ca_generator/offset_x", (int)_offsetXSpin.Value);
|
||||
es.SetSetting("ca_generator/offset_y", (int)_offsetYSpin.Value);
|
||||
es.SetSetting("ca_generator/fill_density", _densitySlider.Value);
|
||||
es.SetSetting("ca_generator/smoothing_passes", (int)_smoothPassSlider.Value);
|
||||
es.SetSetting("ca_generator/border_walls", _borderCheck.ButtonPressed);
|
||||
es.SetSetting("ca_generator/seed", (int)_seedSpin.Value);
|
||||
es.SetSetting("ca_generator/source_id", (int)_sourceIdSpin.Value);
|
||||
es.SetSetting("ca_generator/atlas_x", (int)_atlasXSpin.Value);
|
||||
es.SetSetting("ca_generator/atlas_y", (int)_atlasYSpin.Value);
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
if (es == null) return;
|
||||
|
||||
SetMode((CaMode)(es.HasSetting("ca_generator/mode") ? es.GetSetting("ca_generator/mode").AsInt32() : 0));
|
||||
_widthSpin.Value = es.HasSetting("ca_generator/width") ? es.GetSetting("ca_generator/width").AsDouble() : 40.0;
|
||||
_heightSpin.Value = es.HasSetting("ca_generator/height") ? es.GetSetting("ca_generator/height").AsDouble() : 22.0;
|
||||
_offsetXSpin.Value = es.HasSetting("ca_generator/offset_x") ? es.GetSetting("ca_generator/offset_x").AsDouble() : 0.0;
|
||||
_offsetYSpin.Value = es.HasSetting("ca_generator/offset_y") ? es.GetSetting("ca_generator/offset_y").AsDouble() : 0.0;
|
||||
_densitySlider.Value = es.HasSetting("ca_generator/fill_density") ? es.GetSetting("ca_generator/fill_density").AsDouble() : 48.0;
|
||||
_smoothPassSlider.Value = es.HasSetting("ca_generator/smoothing_passes") ? es.GetSetting("ca_generator/smoothing_passes").AsDouble() : 4.0;
|
||||
_borderCheck.ButtonPressed = es.HasSetting("ca_generator/border_walls") ? es.GetSetting("ca_generator/border_walls").AsBool() : true;
|
||||
_seedSpin.Value = es.HasSetting("ca_generator/seed") ? es.GetSetting("ca_generator/seed").AsDouble() : 12345.0;
|
||||
|
||||
_sourceIdSpin.Value = es.HasSetting("ca_generator/source_id") ? es.GetSetting("ca_generator/source_id").AsDouble() : 0.0;
|
||||
_atlasXSpin.Value = es.HasSetting("ca_generator/atlas_x") ? es.GetSetting("ca_generator/atlas_x").AsDouble() : 0.0;
|
||||
_atlasYSpin.Value = es.HasSetting("ca_generator/atlas_y") ? es.GetSetting("ca_generator/atlas_y").AsDouble() : 0.0;
|
||||
|
||||
_densityLabel.Text = $"{(int)_densitySlider.Value}%";
|
||||
_smoothPassLabel.Text = $"{(int)_smoothPassSlider.Value}";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
uid://dnuvfv3rgyywd
|
||||
@@ -1,37 +0,0 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaLevelGeneratorPlugin : EditorPlugin
|
||||
{
|
||||
private EditorDock _editorDock;
|
||||
private CaLevelGeneratorDock _dock;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
_dock = new CaLevelGeneratorDock { Plugin = this };
|
||||
_editorDock = new EditorDock { Title = "CA Level Generator" };
|
||||
_editorDock.AddChild(_dock);
|
||||
AddDock(_editorDock);
|
||||
SceneChanged += OnSceneChanged;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
SceneChanged -= OnSceneChanged;
|
||||
RemoveDock(_editorDock);
|
||||
_editorDock.QueueFree();
|
||||
_editorDock = null;
|
||||
_dock = null;
|
||||
}
|
||||
|
||||
private void OnSceneChanged(Node sceneRoot)
|
||||
{
|
||||
_dock?.OnSceneChanged(sceneRoot);
|
||||
}
|
||||
|
||||
public EditorUndoRedoManager UndoRedo => GetUndoRedo();
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
uid://cojnhxpcgepi2
|
||||
@@ -1,100 +0,0 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public static class TilemapPainter
|
||||
{
|
||||
public static void Paint(
|
||||
TileMapLayer layer,
|
||||
bool[,] grid,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var before = layer.TileMapData;
|
||||
ApplyGrid(layer, grid, settings);
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Generate");
|
||||
}
|
||||
|
||||
public static void Smooth(
|
||||
TileMapLayer layer,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var grid = ReadGrid(layer, settings.Offset, new Vector2I(settings.Width, settings.Height));
|
||||
grid = CaGenerator.Smooth(grid);
|
||||
var before = layer.TileMapData;
|
||||
ApplyGrid(layer, grid, settings);
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Smooth");
|
||||
}
|
||||
|
||||
public static void Clear(
|
||||
TileMapLayer layer,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var before = layer.TileMapData;
|
||||
for (int x = 0; x < settings.Width; x++)
|
||||
for (int y = 0; y < settings.Height; y++)
|
||||
layer.EraseCell(settings.Offset + new Vector2I(x, y));
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Clear");
|
||||
}
|
||||
|
||||
private static bool[,] ReadGrid(TileMapLayer layer, Vector2I offset, Vector2I size)
|
||||
{
|
||||
var grid = new bool[size.X, size.Y];
|
||||
for (int x = 0; x < size.X; x++)
|
||||
for (int y = 0; y < size.Y; y++)
|
||||
grid[x, y] = layer.GetCellSourceId(offset + new Vector2I(x, y)) != -1;
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static void ApplyGrid(TileMapLayer layer, bool[,] grid, CaGeneratorSettings settings)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
layer.EraseCell(settings.Offset + new Vector2I(x, y));
|
||||
|
||||
if (settings.TerrainSet >= 0)
|
||||
{
|
||||
var solidCells = new Array<Vector2I>();
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
if (grid[x, y])
|
||||
solidCells.Add(settings.Offset + new Vector2I(x, y));
|
||||
|
||||
if (solidCells.Count > 0)
|
||||
layer.SetCellsTerrainConnect(solidCells, settings.TerrainSet, settings.Terrain);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
if (grid[x, y])
|
||||
layer.SetCell(
|
||||
settings.Offset + new Vector2I(x, y),
|
||||
settings.SourceId,
|
||||
settings.AtlasCoords);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterUndo(
|
||||
TileMapLayer layer,
|
||||
byte[] before,
|
||||
byte[] after,
|
||||
EditorUndoRedoManager undoRedo,
|
||||
string actionName)
|
||||
{
|
||||
undoRedo.CreateAction(actionName);
|
||||
undoRedo.AddUndoProperty(layer, "tile_map_data", before);
|
||||
undoRedo.AddDoProperty(layer, "tile_map_data", after);
|
||||
undoRedo.CommitAction(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
uid://y55l4iw35tih
|
||||
@@ -1,6 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://test_ca_generator"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/ca_level_generator/CaGeneratorTestRunner.cs" id="1_catest"]
|
||||
|
||||
[node name="CaGeneratorTestRunner" type="Node"]
|
||||
script = ExtResource("1_catest")
|
||||
@@ -1,6 +0,0 @@
|
||||
[plugin]
|
||||
name="CA Level Generator"
|
||||
description="Cellular automata level blockout generator"
|
||||
author="Gabriel Kaszewski"
|
||||
version="1.0"
|
||||
script="CaLevelGeneratorPlugin.cs"
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://bargnp4twtmxg"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://bargnp4twtmxg"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_aya2w"]
|
||||
[ext_resource type="Script" uid="uid://r4jybneigfcn" path="res://scripts/components/CollectableComponent.cs" id="2_htmrw"]
|
||||
@@ -9,33 +9,33 @@
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_3ask2"]
|
||||
radius = 9.0
|
||||
|
||||
[node name="Big Coin" type="Area2D" unique_id=354254828 groups=["coins"]]
|
||||
[node name="Big Coin" type="Area2D" groups=["coins"]]
|
||||
scale = Vector2(2, 2)
|
||||
collision_layer = 2
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2066526597]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_3ask2")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1626463721]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_aya2w")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 51
|
||||
|
||||
[node name="CollectableComponent" type="Node" parent="." unique_id=1124310030 node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
script = ExtResource("2_htmrw")
|
||||
Area2D = NodePath("..")
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
Data = ExtResource("3_lk3av")
|
||||
Sfx = NodePath("../sfx")
|
||||
|
||||
[node name="FadeAwayComponent" type="Node" parent="." unique_id=222617739 node_paths=PackedStringArray("Sprite", "Area")]
|
||||
[node name="FadeAwayComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Area")]
|
||||
script = ExtResource("4_62p7g")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
Area = NodePath("..")
|
||||
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="." unique_id=1978747299]
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("5_dbffd")
|
||||
volume_db = -5.0
|
||||
bus = &"sfx"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://d08dfqmirnd66"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://d08dfqmirnd66"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_1co1x"]
|
||||
[ext_resource type="Script" uid="uid://r4jybneigfcn" path="res://scripts/components/CollectableComponent.cs" id="2_lthbn"]
|
||||
@@ -9,32 +9,32 @@
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_3ask2"]
|
||||
radius = 9.0
|
||||
|
||||
[node name="Big Treasure" type="Area2D" unique_id=1021217632 groups=["coins"]]
|
||||
[node name="Big Treasure" type="Area2D" groups=["coins"]]
|
||||
collision_layer = 2
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=458290011]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_3ask2")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=564060301]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_1co1x")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 64
|
||||
|
||||
[node name="CollectableComponent" type="Node" parent="." unique_id=2009195182 node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
script = ExtResource("2_lthbn")
|
||||
Area2D = NodePath("..")
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
Data = ExtResource("3_k64cr")
|
||||
Sfx = NodePath("../sfx")
|
||||
|
||||
[node name="FadeAwayComponent" type="Node" parent="." unique_id=1809580000 node_paths=PackedStringArray("Sprite", "Area")]
|
||||
[node name="FadeAwayComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Area")]
|
||||
script = ExtResource("4_qwwsj")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
FadeDuration = 0.4
|
||||
Area = NodePath("..")
|
||||
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="." unique_id=466669009]
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("5_fxf8v")
|
||||
bus = &"sfx"
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
[gd_scene format=3 uid="uid://bqi5s710xb1ju"]
|
||||
[gd_scene load_steps=58 format=3 uid="uid://bqi5s710xb1ju"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://csel4s0e4g5uf" path="res://scripts/components/PlayerController.cs" id="1_yysbb"]
|
||||
[ext_resource type="Resource" uid="uid://vgutbpovj8hc" path="res://resources/movement_presets/platform_movement.tres" id="2_7til7"]
|
||||
[ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="2_lgb3u"]
|
||||
[ext_resource type="PackedScene" uid="uid://bcv8kx6bc7u5e" path="res://objects/movement_abilities/ground_ability.tscn" id="2_oefns"]
|
||||
[ext_resource type="Texture2D" uid="uid://jl1gwqchhpdc" path="res://sprites/left_eye.png" id="3_2srrh"]
|
||||
[ext_resource type="PackedScene" uid="uid://d0r5edxnx5jqx" path="res://objects/movement_abilities/variable_jump_ability.tscn" id="3_bnap0"]
|
||||
[ext_resource type="Script" uid="uid://bf4yclropol43" path="res://scripts/components/Movement/GroundMovementAbility.cs" id="4_7til7"]
|
||||
[ext_resource type="Texture2D" uid="uid://iiawtnwmeny3" path="res://sprites/right_eye.png" id="4_ccn81"]
|
||||
[ext_resource type="PackedScene" uid="uid://cala7bpo1v4no" path="res://objects/movement_abilities/gravity_ability.tscn" id="4_qec3q"]
|
||||
[ext_resource type="PackedScene" uid="uid://bty3jq8u0pxkf" path="res://objects/movement_abilities/one_way_platform_ability.tscn" id="5_dhjci"]
|
||||
[ext_resource type="Texture2D" uid="uid://0l454rfplmqg" path="res://sprites/MrBrick_base-sheet.png" id="5_yysbb"]
|
||||
[ext_resource type="PackedScene" uid="uid://bu3vuxlrvoo1t" path="res://objects/movement_abilities/spaceship_ability.tscn" id="6_721q0"]
|
||||
[ext_resource type="Script" uid="uid://chgw53qwt7rt8" path="res://scripts/components/Movement/GravityAbility.cs" id="6_xuhvf"]
|
||||
[ext_resource type="Script" uid="uid://ccksp2e76s7sr" path="res://scripts/components/Movement/VariableJumpAbility.cs" id="7_bl1gx"]
|
||||
[ext_resource type="PackedScene" uid="uid://chjbi5mgtwhsh" path="res://objects/movement_abilities/wall_jump_ability.tscn" id="7_bnap0"]
|
||||
[ext_resource type="Script" uid="uid://ck6kmnbwhsttt" path="res://scripts/components/Movement/OneWayPlatformAbility.cs" id="7_uno3u"]
|
||||
[ext_resource type="Texture2D" uid="uid://dhkwyv6ayb5qb" path="res://sprites/flying_ship.png" id="8_6lsog"]
|
||||
[ext_resource type="PackedScene" uid="uid://dre1vit1m4d2n" path="res://objects/movement_abilities/grid_movement_ability.tscn" id="8_xuhvf"]
|
||||
[ext_resource type="Script" uid="uid://dy78ak8eykw6e" path="res://scripts/components/FlipComponent.cs" id="9_yysbb"]
|
||||
[ext_resource type="Script" uid="uid://mnjg3p0aw1ow" path="res://scripts/components/CanPickUpComponent.cs" id="10_yysbb"]
|
||||
[ext_resource type="Script" uid="uid://ccqb8kd5m0eh7" path="res://scripts/components/ScoreComponent.cs" id="11_o1ihh"]
|
||||
[ext_resource type="Script" uid="uid://dgb8bqcri7nsj" path="res://scripts/components/HealthComponent.cs" id="12_ur2y5"]
|
||||
[ext_resource type="Script" uid="uid://byw1legrv1ep2" path="res://scripts/components/PlayerDeathComponent.cs" id="13_7til7"]
|
||||
[ext_resource type="Script" uid="uid://cecelixl41t3j" path="res://scripts/components/InvulnerabilityComponent.cs" id="15_xuhvf"]
|
||||
@@ -65,7 +76,7 @@ point_count = 2
|
||||
[sub_resource type="CurveTexture" id="CurveTexture_xoue7"]
|
||||
curve = SubResource("Curve_82d6e")
|
||||
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_oxudy"]
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_lgb3u"]
|
||||
resource_local_to_scene = true
|
||||
lifetime_randomness = 1.0
|
||||
particle_flag_disable_z = true
|
||||
@@ -82,202 +93,230 @@ scale_curve = SubResource("CurveTexture_xoue7")
|
||||
color = Color(0.764706, 0.443137, 0, 1)
|
||||
color_ramp = SubResource("GradientTexture1D_lgb3u")
|
||||
|
||||
[node name="Brick Player" type="CharacterBody2D" unique_id=634211282 node_paths=PackedStringArray("MovementAbilitiesContainer") groups=["player"]]
|
||||
[node name="Brick Player" type="CharacterBody2D" node_paths=PackedStringArray("MovementAbilitiesContainer") groups=["player"]]
|
||||
collision_layer = 4
|
||||
collision_mask = 107
|
||||
script = ExtResource("1_yysbb")
|
||||
MovementAbilitiesContainer = NodePath("Movements")
|
||||
DefaultPreset = ExtResource("2_7til7")
|
||||
GroundMovementScene = ExtResource("2_oefns")
|
||||
JumpMovementScene = ExtResource("3_bnap0")
|
||||
GravityScene = ExtResource("4_qec3q")
|
||||
OneWayPlatformScene = ExtResource("5_dhjci")
|
||||
SpaceshipMovementScene = ExtResource("6_721q0")
|
||||
WallJumpScene = ExtResource("7_bnap0")
|
||||
GridMovementScene = ExtResource("8_xuhvf")
|
||||
metadata/_custom_type_script = "uid://csel4s0e4g5uf"
|
||||
|
||||
[node name="Movements" type="Node" parent="." unique_id=1545001]
|
||||
[node name="Movements" type="Node" parent="."]
|
||||
|
||||
[node name="Graphics" type="Node2D" parent="." unique_id=271317654]
|
||||
[node name="GroundMovementAbility" type="Node" parent="Movements"]
|
||||
script = ExtResource("4_7til7")
|
||||
MaxSpeed = 376.0
|
||||
Friction = 2500.0
|
||||
metadata/_custom_type_script = "uid://bf4yclropol43"
|
||||
|
||||
[node name="Root" type="Node2D" parent="Graphics" unique_id=2012260442]
|
||||
[node name="GravityAbility" type="Node" parent="Movements"]
|
||||
script = ExtResource("6_xuhvf")
|
||||
metadata/_custom_type_script = "uid://chgw53qwt7rt8"
|
||||
|
||||
[node name="Base" type="Sprite2D" parent="Graphics/Root" unique_id=1178176210]
|
||||
[node name="VariableJumpAbility" type="Node" parent="Movements"]
|
||||
script = ExtResource("7_bl1gx")
|
||||
JumpCutMultiplier = 0.507
|
||||
metadata/_custom_type_script = "uid://ccksp2e76s7sr"
|
||||
|
||||
[node name="OneWayPlatformAbility" type="Node" parent="Movements"]
|
||||
script = ExtResource("7_uno3u")
|
||||
metadata/_custom_type_script = "uid://ck6kmnbwhsttt"
|
||||
|
||||
[node name="Graphics" type="Node2D" parent="."]
|
||||
|
||||
[node name="Root" type="Node2D" parent="Graphics"]
|
||||
|
||||
[node name="Base" type="Sprite2D" parent="Graphics/Root"]
|
||||
material = SubResource("ShaderMaterial_xoue7")
|
||||
texture = ExtResource("5_yysbb")
|
||||
hframes = 5
|
||||
|
||||
[node name="Left Eye" type="Sprite2D" parent="Graphics/Root" unique_id=653633051]
|
||||
[node name="Left Eye" type="Sprite2D" parent="Graphics/Root"]
|
||||
position = Vector2(-7, -6)
|
||||
texture = ExtResource("3_2srrh")
|
||||
hframes = 2
|
||||
|
||||
[node name="Right Eye" type="Sprite2D" parent="Graphics/Root" unique_id=721230787]
|
||||
[node name="Right Eye" type="Sprite2D" parent="Graphics/Root"]
|
||||
position = Vector2(6, -5)
|
||||
texture = ExtResource("4_ccn81")
|
||||
hframes = 2
|
||||
|
||||
[node name="Ship" type="Sprite2D" parent="Graphics" unique_id=1074443059]
|
||||
[node name="Ship" type="Sprite2D" parent="Graphics"]
|
||||
visible = false
|
||||
position = Vector2(1, 7)
|
||||
texture = ExtResource("8_6lsog")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=22428429]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
visible = false
|
||||
position = Vector2(0, 0.5)
|
||||
shape = SubResource("RectangleShape2D_hdsg1")
|
||||
|
||||
[node name="FlipPlayerComponent" type="Node2D" parent="." unique_id=290535881 node_paths=PackedStringArray("LeftEye", "RightEye", "PlayerController")]
|
||||
[node name="FlipPlayerComponent" type="Node2D" parent="." node_paths=PackedStringArray("LeftEye", "RightEye", "PlayerController")]
|
||||
script = ExtResource("9_yysbb")
|
||||
LeftEye = NodePath("../Graphics/Root/Left Eye")
|
||||
RightEye = NodePath("../Graphics/Root/Right Eye")
|
||||
PlayerController = NodePath("..")
|
||||
|
||||
[node name="StompDamageArea" type="Area2D" parent="." unique_id=2071262827]
|
||||
[node name="StompDamageArea" type="Area2D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 8
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="StompDamageArea" unique_id=1230518642]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="StompDamageArea"]
|
||||
visible = false
|
||||
position = Vector2(0, 1)
|
||||
shape = SubResource("RectangleShape2D_vad0t")
|
||||
|
||||
[node name="CanPickUpComponent" type="Node" parent="." unique_id=1912343790]
|
||||
[node name="CanPickUpComponent" type="Node" parent="."]
|
||||
script = ExtResource("10_yysbb")
|
||||
|
||||
[node name="HealthComponent" type="Node2D" parent="." unique_id=278902432 node_paths=PackedStringArray("HurtSfx", "HealSfx")]
|
||||
[node name="ScoreComponent" type="Node" parent="."]
|
||||
script = ExtResource("11_o1ihh")
|
||||
|
||||
[node name="HealthComponent" type="Node2D" parent="." node_paths=PackedStringArray("HurtSfx", "HealSfx")]
|
||||
script = ExtResource("12_ur2y5")
|
||||
HurtSfx = NodePath("../sfx_hurt")
|
||||
HealSfx = NodePath("../sfx_heal")
|
||||
|
||||
[node name="PlayerDeathComponent" type="Node2D" parent="." unique_id=1989490803 node_paths=PackedStringArray("DeathSfx", "HealthComponent")]
|
||||
[node name="PlayerDeathComponent" type="Node2D" parent="." node_paths=PackedStringArray("DeathSfx", "HealthComponent")]
|
||||
process_mode = 3
|
||||
script = ExtResource("13_7til7")
|
||||
DeathSfx = NodePath("../sfx_hurt")
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
|
||||
[node name="InvulnerabilityComponent" type="Node" parent="." unique_id=963173254 node_paths=PackedStringArray("FlashingComponent")]
|
||||
[node name="InvulnerabilityComponent" type="Node" parent="." node_paths=PackedStringArray("FlashingComponent")]
|
||||
script = ExtResource("15_xuhvf")
|
||||
FlashingComponent = NodePath("../FlashingComponent Base")
|
||||
|
||||
[node name="FlashingComponent Base" type="Node" parent="." unique_id=533766453 node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
[node name="FlashingComponent Base" type="Node" parent="." node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
script = ExtResource("16_uno3u")
|
||||
Sprite = NodePath("../Graphics/Root/Base")
|
||||
FlashDuration = 1.0
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
|
||||
[node name="FlashingComponent LEye" type="Node" parent="." unique_id=835038717 node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
[node name="FlashingComponent LEye" type="Node" parent="." node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
script = ExtResource("16_uno3u")
|
||||
Sprite = NodePath("../Graphics/Root/Left Eye")
|
||||
FlashDuration = 1.0
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
|
||||
[node name="FlashingComponent REye" type="Node" parent="." unique_id=601265429 node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
[node name="FlashingComponent REye" type="Node" parent="." node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
script = ExtResource("16_uno3u")
|
||||
Sprite = NodePath("../Graphics/Root/Right Eye")
|
||||
FlashDuration = 1.0
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
|
||||
[node name="StompDamageComponent" type="Node" parent="." unique_id=1027107459 node_paths=PackedStringArray("Area", "Root")]
|
||||
[node name="StompDamageComponent" type="Node" parent="." node_paths=PackedStringArray("Area", "Root")]
|
||||
script = ExtResource("17_bl1gx")
|
||||
Damage = 4.0
|
||||
Area = NodePath("../StompDamageArea")
|
||||
Root = NodePath("..")
|
||||
|
||||
[node name="SkillUnlockerComponent" type="Node" parent="." unique_id=496647555]
|
||||
[node name="SkillUnlockerComponent" type="Node" parent="."]
|
||||
script = ExtResource("25_yysbb")
|
||||
|
||||
[node name="HitComponent" type="Node" parent="." unique_id=131916578 node_paths=PackedStringArray("Sprite", "Health", "HitFx")]
|
||||
[node name="HitComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Health", "HitFx")]
|
||||
script = ExtResource("26_6n1ss")
|
||||
Sprite = NodePath("../Graphics/Root/Base")
|
||||
Health = NodePath("../HealthComponent")
|
||||
HitFx = NodePath("../HitParticles")
|
||||
|
||||
[node name="MagneticArea" type="Area2D" parent="." unique_id=1477305842]
|
||||
[node name="MagneticArea" type="Area2D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="MagneticArea" unique_id=1552683633]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="MagneticArea"]
|
||||
visible = false
|
||||
shape = SubResource("CircleShape2D_ps31c")
|
||||
|
||||
[node name="CanBeLaunchedComponent" type="Node" parent="." unique_id=1998429478]
|
||||
[node name="CanBeLaunchedComponent" type="Node" parent="."]
|
||||
script = ExtResource("27_oefns")
|
||||
|
||||
[node name="TriggerLeverComponent" type="Node" parent="." unique_id=366225548]
|
||||
[node name="TriggerLeverComponent" type="Node" parent="."]
|
||||
script = ExtResource("28_bnap0")
|
||||
|
||||
[node name="sfx_jump" type="AudioStreamPlayer2D" parent="." unique_id=218072388]
|
||||
[node name="sfx_jump" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("18_pysae")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="sfx_hurt" type="AudioStreamPlayer2D" parent="." unique_id=1815263121]
|
||||
[node name="sfx_hurt" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("19_7anly")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="sfx_heal" type="AudioStreamPlayer2D" parent="." unique_id=1792916109]
|
||||
[node name="sfx_heal" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("20_bptj5")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="sfx_shoot" type="AudioStreamPlayer2D" parent="." unique_id=1414786458]
|
||||
[node name="sfx_shoot" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("32_x2b7c")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="ChargingBarLayer" parent="." unique_id=664675361 instance=ExtResource("28_3f5nm")]
|
||||
[node name="ChargingBarLayer" parent="." instance=ExtResource("28_3f5nm")]
|
||||
offset_left = -17.0
|
||||
offset_top = -30.0
|
||||
offset_right = 23.0
|
||||
offset_bottom = -20.0
|
||||
|
||||
[node name="HitParticles" parent="." unique_id=1322585720 instance=ExtResource("28_jh5m0")]
|
||||
process_material = SubResource("ParticleProcessMaterial_oxudy")
|
||||
[node name="HitParticles" parent="." instance=ExtResource("28_jh5m0")]
|
||||
process_material = SubResource("ParticleProcessMaterial_lgb3u")
|
||||
|
||||
[node name="ShipShooter" type="Node" parent="." unique_id=1147013800 node_paths=PackedStringArray("BulletSpawn", "ShootSfx")]
|
||||
[node name="ShipShooter" type="Node" parent="." node_paths=PackedStringArray("BulletSpawn", "ShootSfx")]
|
||||
script = ExtResource("30_usc1p")
|
||||
BulletScene = ExtResource("36_oxudy")
|
||||
BulletSpawn = NodePath("../Ship shoot spawn")
|
||||
ShootSfx = NodePath("../sfx_shoot")
|
||||
|
||||
[node name="Ship shoot spawn" type="Marker2D" parent="." unique_id=1653596970]
|
||||
[node name="Ship shoot spawn" type="Marker2D" parent="."]
|
||||
position = Vector2(17, 5)
|
||||
gizmo_extents = 1.0
|
||||
|
||||
[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="." unique_id=65174812]
|
||||
[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="."]
|
||||
position = Vector2(0, 3)
|
||||
scale = Vector2(0.8, 1.9)
|
||||
|
||||
[node name="PlayerInputHandler" type="Node" parent="." unique_id=1581385683]
|
||||
[node name="PlayerInputHandler" type="Node" parent="."]
|
||||
script = ExtResource("42_e5pae")
|
||||
metadata/_custom_type_script = "uid://dssa2taiwktis"
|
||||
|
||||
[node name="SpriteTilterComponent" type="Node" parent="." unique_id=1433925210 node_paths=PackedStringArray("RotationTarget")]
|
||||
[node name="SpriteTilterComponent" type="Node" parent="." node_paths=PackedStringArray("RotationTarget")]
|
||||
script = ExtResource("43_xuhvf")
|
||||
RotationTarget = NodePath("../Graphics/Root/Base")
|
||||
metadata/_custom_type_script = "uid://ceoxet1nqws8w"
|
||||
|
||||
[node name="PlayerSfxComponent" type="Node" parent="." unique_id=1375936690 node_paths=PackedStringArray("JumpSfx")]
|
||||
[node name="PlayerSfxComponent" type="Node" parent="." node_paths=PackedStringArray("JumpSfx")]
|
||||
script = ExtResource("49_qec3q")
|
||||
JumpSfx = NodePath("../sfx_jump")
|
||||
metadata/_custom_type_script = "uid://b1h8r5irryxcx"
|
||||
|
||||
[node name="PlayerGraphicsComponent" type="Node" parent="." unique_id=443649347 node_paths=PackedStringArray("DefaultSprite", "SpaceshipSprite")]
|
||||
[node name="PlayerGraphicsComponent" type="Node" parent="." node_paths=PackedStringArray("DefaultSprite", "SpaceshipSprite")]
|
||||
script = ExtResource("50_dhjci")
|
||||
DefaultSprite = NodePath("../Graphics/Root")
|
||||
SpaceshipSprite = NodePath("../Graphics/Ship")
|
||||
metadata/_custom_type_script = "uid://b2aanqykvdnev"
|
||||
|
||||
[node name="ProgressiveDamageComponent" type="Node" parent="." unique_id=1763641730 node_paths=PackedStringArray("HealthComponent", "Sprite")]
|
||||
[node name="ProgressiveDamageComponent" type="Node" parent="." node_paths=PackedStringArray("HealthComponent", "Sprite")]
|
||||
script = ExtResource("38_dhjci")
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
Sprite = NodePath("../Graphics/Root/Base")
|
||||
metadata/_custom_type_script = "uid://dupnaark1f7gm"
|
||||
|
||||
[node name="PacXonGridInteractor" type="Node" parent="." unique_id=1036082136]
|
||||
[node name="PacXonGridInteractor" type="Node" parent="."]
|
||||
script = ExtResource("42_xuhvf")
|
||||
metadata/_custom_type_script = "uid://c00siqtssccr6"
|
||||
|
||||
[node name="PacXonTrailComponent" type="Line2D" parent="." unique_id=100969687]
|
||||
[node name="PacXonTrailComponent" type="Line2D" parent="."]
|
||||
script = ExtResource("44_uno3u")
|
||||
metadata/_custom_type_script = "uid://cmk4m7mplqnrm"
|
||||
|
||||
[node name="Feet" type="Marker2D" parent="." unique_id=1308840991]
|
||||
[node name="Feet" type="Marker2D" parent="."]
|
||||
position = Vector2(0, 16)
|
||||
|
||||
[node name="FootstepGfx" type="Node2D" parent="." unique_id=362059837 node_paths=PackedStringArray("_controller", "_marker")]
|
||||
[node name="FootstepGfx" type="Node2D" parent="." node_paths=PackedStringArray("_controller", "_marker")]
|
||||
script = ExtResource("46_6n1ss")
|
||||
_particles = ExtResource("45_bl1gx")
|
||||
_controller = NodePath("..")
|
||||
@@ -288,7 +327,7 @@ _minMoveSpeed = 4.0
|
||||
_randomOffsetRange = 0.3
|
||||
metadata/_custom_type_script = "uid://d3ksrjt1ek4gi"
|
||||
|
||||
[node name="JumpGfxComponent" type="Node2D" parent="." unique_id=1468920790 node_paths=PackedStringArray("Controller")]
|
||||
[node name="JumpGfxComponent" type="Node2D" parent="." node_paths=PackedStringArray("Controller")]
|
||||
script = ExtResource("47_oefns")
|
||||
ParticleScene = ExtResource("48_bnap0")
|
||||
Controller = NodePath("..")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://54w4wisfj8v8"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://54w4wisfj8v8"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_epuj5"]
|
||||
[ext_resource type="Script" uid="uid://r4jybneigfcn" path="res://scripts/components/CollectableComponent.cs" id="2_gxix7"]
|
||||
@@ -9,33 +9,33 @@
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_3ask2"]
|
||||
radius = 9.0
|
||||
|
||||
[node name="Coin" type="Area2D" unique_id=1771447403 groups=["coins"]]
|
||||
[node name="Coin" type="Area2D" groups=["coins"]]
|
||||
collision_layer = 2
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=707378099]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_3ask2")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=898624458]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_epuj5")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 51
|
||||
|
||||
[node name="CollectableComponent" type="Node" parent="." unique_id=564726971 node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("Area2D", "CollisionShape", "Sfx")]
|
||||
script = ExtResource("2_gxix7")
|
||||
Area2D = NodePath("..")
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
Data = ExtResource("3_fm2fq")
|
||||
Sfx = NodePath("../sfx")
|
||||
|
||||
[node name="FadeAwayComponent" type="Node" parent="." unique_id=1534239994 node_paths=PackedStringArray("Sprite", "Area")]
|
||||
[node name="FadeAwayComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Area")]
|
||||
script = ExtResource("4_gxix7")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
FadeDuration = 0.4
|
||||
Area = NodePath("..")
|
||||
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="." unique_id=1641717]
|
||||
[node name="sfx" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("5_4jc2c")
|
||||
volume_db = -10.0
|
||||
bus = &"sfx"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene format=3 uid="uid://c40r76qqacqie"]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://c40r76qqacqie"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cysarpu6snb2y" path="res://sprites/ppc-tileset.png" id="1_jmsgb"]
|
||||
[ext_resource type="Texture2D" uid="uid://cw42lvnqxubq2" path="res://sprites/PS_Tileset_10_nes.png" id="1_jmsgb"]
|
||||
[ext_resource type="Script" uid="uid://xqhrb1c7f6y4" path="res://scripts/components/CollapsableComponent.cs" id="2_jmsgb"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_l44jt"]
|
||||
@@ -9,30 +9,30 @@ size = Vector2(16, 16)
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_sfbe2"]
|
||||
size = Vector2(16, 2)
|
||||
|
||||
[node name="Collapsing Block" type="StaticBody2D" unique_id=1834310310]
|
||||
[node name="Collapsing Block" type="StaticBody2D"]
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=2120289038]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_jmsgb")
|
||||
hframes = 64
|
||||
vframes = 64
|
||||
frame = 710
|
||||
hframes = 16
|
||||
vframes = 12
|
||||
frame = 182
|
||||
|
||||
[node name="StaticCollisionShape2D" type="CollisionShape2D" parent="." unique_id=196070485]
|
||||
[node name="StaticCollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("RectangleShape2D_l44jt")
|
||||
|
||||
[node name="Collapsable detector" type="Area2D" parent="." unique_id=1910035087]
|
||||
[node name="Collapsable detector" type="Area2D" parent="."]
|
||||
collision_mask = 4
|
||||
|
||||
[node name="AreaCollisionShape2D" type="CollisionShape2D" parent="Collapsable detector" unique_id=1903927379]
|
||||
[node name="AreaCollisionShape2D" type="CollisionShape2D" parent="Collapsable detector"]
|
||||
position = Vector2(0, -8)
|
||||
shape = SubResource("RectangleShape2D_sfbe2")
|
||||
|
||||
[node name="ToCollapseTimer" type="Timer" parent="." unique_id=2109761872]
|
||||
[node name="ToCollapseTimer" type="Timer" parent="."]
|
||||
wait_time = 0.5
|
||||
|
||||
[node name="ResetTimer" type="Timer" parent="." unique_id=1072118129]
|
||||
[node name="ResetTimer" type="Timer" parent="."]
|
||||
|
||||
[node name="CollapsableComponent" type="Node" parent="." unique_id=1696909259 node_paths=PackedStringArray("ToCollapseTimer", "ResetTimer", "Sprite2D", "CollisionShape")]
|
||||
[node name="CollapsableComponent" type="Node" parent="." node_paths=PackedStringArray("ToCollapseTimer", "ResetTimer", "Sprite2D", "CollisionShape")]
|
||||
script = ExtResource("2_jmsgb")
|
||||
ToCollapseTimer = NodePath("../ToCollapseTimer")
|
||||
ResetTimer = NodePath("../ResetTimer")
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://dk2cu8qs7odib"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_214vd"]
|
||||
[ext_resource type="Script" uid="uid://r4jybneigfcn" path="res://scripts/components/CollectableComponent.cs" id="2_h7fi3"]
|
||||
[ext_resource type="Script" uid="uid://bjln6jb1sigx2" path="res://scripts/components/FadeAwayComponent.cs" id="3_b687r"]
|
||||
[ext_resource type="Resource" path="res://resources/collectables/double_jump_pickup.tres" id="3_h7fi3"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_pickup"]
|
||||
radius = 12.0
|
||||
|
||||
[node name="SkillPickup" type="Area2D" groups=["Collectables"]]
|
||||
collision_layer = 2
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_pickup")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_214vd")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 24
|
||||
|
||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("Area2D", "CollisionShape")]
|
||||
script = ExtResource("2_h7fi3")
|
||||
Area2D = NodePath("..")
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
Data = ExtResource("3_h7fi3")
|
||||
|
||||
[node name="FadeAwayComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Area")]
|
||||
script = ExtResource("3_b687r")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
FadeDuration = 0.5
|
||||
Area = NodePath("..")
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://12jnkdygpxwc"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://12jnkdygpxwc"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_agxwm"]
|
||||
[ext_resource type="Script" uid="uid://dnh0mekg2vqxi" path="res://scripts/components/RequirementComponent.cs" id="2_ed7mh"]
|
||||
@@ -8,14 +8,14 @@
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_yfu6m"]
|
||||
size = Vector2(28, 32)
|
||||
|
||||
[node name="ExitLevel" type="Area2D" unique_id=1951927125 node_paths=PackedStringArray("DoorSprite")]
|
||||
[node name="ExitLevel" type="Area2D" node_paths=PackedStringArray("DoorSprite")]
|
||||
collision_layer = 0
|
||||
collision_mask = 4
|
||||
script = ExtResource("4_06sog")
|
||||
DoorSprite = NodePath("Sprite2D")
|
||||
OpenedDoorFrame = 88
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1296410089]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
position = Vector2(0, -8)
|
||||
scale = Vector2(2, 2)
|
||||
texture = ExtResource("1_agxwm")
|
||||
@@ -23,15 +23,15 @@ hframes = 12
|
||||
vframes = 12
|
||||
frame = 54
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=220927363]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
position = Vector2(0, -8)
|
||||
shape = SubResource("RectangleShape2D_yfu6m")
|
||||
|
||||
[node name="RequirementComponent" type="Node" parent="." unique_id=1338124097]
|
||||
[node name="RequirementComponent" type="Node" parent="."]
|
||||
script = ExtResource("2_ed7mh")
|
||||
RequirementType = 2
|
||||
RequirementType = 1
|
||||
|
||||
[node name="UnlockOnRequirementComponent" type="Node" parent="." unique_id=1279359200 node_paths=PackedStringArray("RequirementComponent", "UnlockTarget")]
|
||||
[node name="UnlockOnRequirementComponent" type="Node" parent="." node_paths=PackedStringArray("RequirementComponent", "UnlockTarget")]
|
||||
script = ExtResource("3_ed7mh")
|
||||
RequirementComponent = NodePath("../RequirementComponent")
|
||||
UnlockTarget = NodePath("..")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://xp4njljog0x2"]
|
||||
[gd_scene load_steps=30 format=3 uid="uid://xp4njljog0x2"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://22k1u37j6k8y" path="res://sprites/flying_enemy.png" id="1_30hhw"]
|
||||
[ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="1_uyhuj"]
|
||||
@@ -60,7 +60,7 @@ point_count = 2
|
||||
[sub_resource type="CurveTexture" id="CurveTexture_7b7mt"]
|
||||
curve = SubResource("Curve_f2w8b")
|
||||
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_q78ru"]
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_qxfb0"]
|
||||
resource_local_to_scene = true
|
||||
lifetime_randomness = 1.0
|
||||
particle_flag_disable_z = true
|
||||
@@ -80,52 +80,50 @@ color_ramp = SubResource("GradientTexture1D_f1fvy")
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_cmp1h"]
|
||||
size = Vector2(16, 26)
|
||||
|
||||
[node name="Flying Enemy" type="CharacterBody2D" unique_id=1068972930]
|
||||
[node name="Flying Enemy" type="CharacterBody2D"]
|
||||
collision_layer = 8
|
||||
collision_mask = 21
|
||||
motion_mode = 1
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=572073196]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
visible = false
|
||||
shape = SubResource("CapsuleShape2D_hil2i")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=191340928]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
material = SubResource("ShaderMaterial_q78ru")
|
||||
texture = ExtResource("1_30hhw")
|
||||
|
||||
[node name="Jetpack Particles" type="GPUParticles2D" parent="." unique_id=1641064286]
|
||||
[node name="Jetpack Particles" type="GPUParticles2D" parent="."]
|
||||
z_index = -1
|
||||
position = Vector2(-4, 16)
|
||||
explosiveness = 0.5
|
||||
fixed_fps = 24
|
||||
process_material = SubResource("ParticleProcessMaterial_fd2du")
|
||||
|
||||
[node name="Jetpack Particles2" type="GPUParticles2D" parent="." unique_id=962140317]
|
||||
[node name="Jetpack Particles2" type="GPUParticles2D" parent="."]
|
||||
z_index = -1
|
||||
position = Vector2(4, 16)
|
||||
explosiveness = 0.5
|
||||
fixed_fps = 24
|
||||
process_material = SubResource("ParticleProcessMaterial_fd2du")
|
||||
|
||||
[node name="HealthComponent" type="Node2D" parent="." unique_id=1125679087 node_paths=PackedStringArray("HurtSfx")]
|
||||
[node name="HealthComponent" type="Node2D" parent="." node_paths=PackedStringArray("HurtSfx")]
|
||||
script = ExtResource("3_uyhuj")
|
||||
Health = 0.25
|
||||
MaxHealth = 0.25
|
||||
HurtSfx = NodePath("../sfx_hurt")
|
||||
|
||||
[node name="sfx_hurt" type="AudioStreamPlayer2D" parent="." unique_id=1006537001]
|
||||
[node name="sfx_hurt" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("3_fd2du")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="sfx_shoot" type="AudioStreamPlayer2D" parent="." unique_id=1437744637]
|
||||
[node name="sfx_shoot" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("4_rhq76")
|
||||
bus = &"sfx"
|
||||
|
||||
[node name="DamageComponent" type="Node" parent="." unique_id=1923393563 node_paths=PackedStringArray("Area")]
|
||||
[node name="DamageComponent" type="Node" parent="." node_paths=PackedStringArray("Area")]
|
||||
script = ExtResource("6_q78ru")
|
||||
Area = NodePath("../Hitbox")
|
||||
|
||||
[node name="PeriodicShootingComponent" type="Node" parent="." unique_id=1743534415 node_paths=PackedStringArray("BulletSpawnPointRight", "BulletSpawnPointLeft")]
|
||||
[node name="PeriodicShootingComponent" type="Node" parent="." node_paths=PackedStringArray("BulletSpawnPointRight", "BulletSpawnPointLeft")]
|
||||
script = ExtResource("7_weo6b")
|
||||
BulletScene = ExtResource("7_4ajjm")
|
||||
ShootInterval = 2.0
|
||||
@@ -133,68 +131,68 @@ BulletSpawnPointRight = NodePath("../laser spawn point right")
|
||||
BulletSpawnPointLeft = NodePath("../laser spawn point left")
|
||||
ShootingIntervalVariation = 0.5
|
||||
|
||||
[node name="EnemyDeathComponent" type="Node" parent="." unique_id=1519565079 node_paths=PackedStringArray("CollisionShape", "Health")]
|
||||
[node name="EnemyDeathComponent" type="Node" parent="." node_paths=PackedStringArray("CollisionShape", "Health")]
|
||||
script = ExtResource("9_6p4k7")
|
||||
TweenDuration = 0.1
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
Health = NodePath("../HealthComponent")
|
||||
|
||||
[node name="FlashingComponent" type="Node" parent="." unique_id=1761479670 node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
[node name="FlashingComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "HealthComponent")]
|
||||
process_mode = 3
|
||||
script = ExtResource("10_jmybk")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
HealthComponent = NodePath("../HealthComponent")
|
||||
|
||||
[node name="HitComponent" type="Node" parent="." unique_id=2106183592 node_paths=PackedStringArray("Sprite", "Health", "HitFx")]
|
||||
[node name="HitComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Health", "HitFx")]
|
||||
script = ExtResource("11_2yvae")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
Health = NodePath("../HealthComponent")
|
||||
HitFx = NodePath("../HitParticles")
|
||||
|
||||
[node name="StatusEffectComponent" type="Node" parent="." unique_id=2016067092]
|
||||
[node name="StatusEffectComponent" type="Node" parent="."]
|
||||
script = ExtResource("12_xlup2")
|
||||
|
||||
[node name="FireEffectComponent" type="Node" parent="." unique_id=599378746 node_paths=PackedStringArray("Health", "StatusEffectComponent", "FireFX")]
|
||||
[node name="FireEffectComponent" type="Node" parent="." node_paths=PackedStringArray("Health", "StatusEffectComponent", "FireFX")]
|
||||
script = ExtResource("13_mrjm6")
|
||||
Health = NodePath("../HealthComponent")
|
||||
StatusEffectComponent = NodePath("../StatusEffectComponent")
|
||||
FireFX = NodePath("../FireFX")
|
||||
|
||||
[node name="IceEffectComponent" type="Node" parent="." unique_id=1515560540 node_paths=PackedStringArray("ComponentsToDisable", "StatusEffectComponent", "IceFx")]
|
||||
[node name="IceEffectComponent" type="Node" parent="." node_paths=PackedStringArray("ComponentsToDisable", "StatusEffectComponent", "IceFx")]
|
||||
script = ExtResource("14_pkino")
|
||||
ComponentsToDisable = [NodePath("../PeriodicShootingComponent"), NodePath("../DamageComponent")]
|
||||
StatusEffectComponent = NodePath("../StatusEffectComponent")
|
||||
IceFx = NodePath("../Ice FX")
|
||||
|
||||
[node name="HitParticles" parent="." unique_id=579475644 instance=ExtResource("13_xlup2")]
|
||||
[node name="HitParticles" parent="." instance=ExtResource("13_xlup2")]
|
||||
position = Vector2(0, 1)
|
||||
process_material = SubResource("ParticleProcessMaterial_q78ru")
|
||||
process_material = SubResource("ParticleProcessMaterial_qxfb0")
|
||||
|
||||
[node name="FireFX" parent="." unique_id=1136026281 instance=ExtResource("14_mrjm6")]
|
||||
[node name="FireFX" parent="." instance=ExtResource("14_mrjm6")]
|
||||
position = Vector2(0, 9)
|
||||
emitting = false
|
||||
amount = 2048
|
||||
|
||||
[node name="Ice FX" parent="." unique_id=275134518 instance=ExtResource("15_pkino")]
|
||||
[node name="Ice FX" parent="." instance=ExtResource("15_pkino")]
|
||||
visible = false
|
||||
position = Vector2(1, 0)
|
||||
scale = Vector2(0.684407, 0.929677)
|
||||
|
||||
[node name="laser spawn point right" type="Node2D" parent="." unique_id=915998238]
|
||||
[node name="laser spawn point right" type="Node2D" parent="."]
|
||||
position = Vector2(8, -2)
|
||||
|
||||
[node name="laser spawn point left" type="Node2D" parent="." unique_id=1180867485]
|
||||
[node name="laser spawn point left" type="Node2D" parent="."]
|
||||
position = Vector2(-9, -2)
|
||||
|
||||
[node name="Hitbox" type="Area2D" parent="." unique_id=1699649839]
|
||||
[node name="Hitbox" type="Area2D" parent="."]
|
||||
collision_layer = 8
|
||||
collision_mask = 20
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Hitbox" unique_id=379520850]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Hitbox"]
|
||||
position = Vector2(0, 2)
|
||||
shape = SubResource("RectangleShape2D_cmp1h")
|
||||
|
||||
[node name="PathFollowerComponent" type="Node2D" parent="." unique_id=1706994676]
|
||||
[node name="PathFollowerComponent" type="Node2D" parent="."]
|
||||
script = ExtResource("18_q78ru")
|
||||
ShouldRotate = false
|
||||
metadata/_custom_type_script = "uid://b4hvq2i66fjhi"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://cm3rixnnev1pg"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://cm3rixnnev1pg"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_ctugi"]
|
||||
[ext_resource type="Script" uid="uid://bgbnof7aeydmq" path="res://scripts/components/JumpPadComponent.cs" id="2_huktk"]
|
||||
@@ -6,23 +6,23 @@
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ci3ij"]
|
||||
size = Vector2(16, 6)
|
||||
|
||||
[node name="Jump pad" type="Area2D" unique_id=986549607]
|
||||
[node name="Jump pad" type="Area2D"]
|
||||
collision_layer = 0
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1755302504]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
position = Vector2(0, 5)
|
||||
shape = SubResource("RectangleShape2D_ci3ij")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1150967280]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_ctugi")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 120
|
||||
|
||||
[node name="JumpPadComponent" type="Node" parent="." unique_id=1295810804 node_paths=PackedStringArray("Area", "Sprite")]
|
||||
[node name="JumpPadComponent" type="Node" parent="." node_paths=PackedStringArray("Area", "Sprite")]
|
||||
script = ExtResource("2_huktk")
|
||||
JumpForce = 1210.0
|
||||
JumpForce = 1110.0
|
||||
Area = NodePath("..")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
StartAnimationIndex = 120
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://0idmnkwids1r"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_sprite"]
|
||||
[ext_resource type="Script" uid="uid://r4jybneigfcn" path="res://scripts/components/CollectableComponent.cs" id="2_collectable"]
|
||||
[ext_resource type="Script" uid="uid://bjln6jb1sigx2" path="res://scripts/components/FadeAwayComponent.cs" id="3_fadeaway"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_pickup"]
|
||||
radius = 12.0
|
||||
|
||||
[node name="SkillPickup" type="Area2D" groups=["Collectables"]]
|
||||
collision_layer = 2
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_pickup")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_sprite")
|
||||
hframes = 12
|
||||
vframes = 12
|
||||
frame = 24
|
||||
|
||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("Area2D", "CollisionShape")]
|
||||
script = ExtResource("2_collectable")
|
||||
Area2D = NodePath("..")
|
||||
CollisionShape = NodePath("../CollisionShape2D")
|
||||
|
||||
[node name="FadeAwayComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Area")]
|
||||
script = ExtResource("3_fadeaway")
|
||||
Sprite = NodePath("../Sprite2D")
|
||||
FadeDuration = 0.5
|
||||
Area = NodePath("..")
|
||||
@@ -1,20 +1,18 @@
|
||||
[gd_scene format=3 uid="uid://lpovacvt3yyj"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://lpovacvt3yyj"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://dhkwyv6ayb5qb" path="res://sprites/flying_ship.png" id="1_r82pf"]
|
||||
[ext_resource type="Script" uid="uid://dtv2r7q4elgre" path="res://scripts/components/SpaceshipEnterComponent.cs" id="2_wanmd"]
|
||||
[ext_resource type="Resource" uid="uid://d033qwwfs3i72" path="res://resources/movement_presets/spaceship_movement.tres" id="2_yda36"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_wanmd"]
|
||||
radius = 16.1245
|
||||
|
||||
[node name="Spaceship Enter" type="Area2D" unique_id=916428603]
|
||||
[node name="Spaceship Enter" type="Area2D"]
|
||||
collision_layer = 0
|
||||
collision_mask = 4
|
||||
script = ExtResource("2_wanmd")
|
||||
Preset = ExtResource("2_yda36")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=433507900]
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_r82pf")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=993596426]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("CircleShape2D_wanmd")
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
[gd_scene format=3 uid="uid://dkqa3q6j2gof4"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dkqa3q6j2gof4"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d3gfg05ll8uw3" path="res://scripts/components/SpaceshipExitComponent.cs" id="1_1cmfv"]
|
||||
[ext_resource type="Resource" uid="uid://vgutbpovj8hc" path="res://resources/movement_presets/platform_movement.tres" id="2_njt46"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_njt46"]
|
||||
|
||||
[node name="Spaceship exit" type="Area2D" unique_id=922920366]
|
||||
[node name="Spaceship exit" type="Area2D" node_paths=PackedStringArray("Area")]
|
||||
collision_layer = 0
|
||||
collision_mask = 4
|
||||
script = ExtResource("1_1cmfv")
|
||||
Preset = ExtResource("2_njt46")
|
||||
Area = NodePath(".")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1697409658]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("RectangleShape2D_njt46")
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
[gd_scene format=3 uid="uid://b4eifkc31jsun"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://b4eifkc31jsun"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c6eoi3ymefc0x" path="res://Autoloads/GameManager.cs" id="1_t2tr6"]
|
||||
[ext_resource type="PackedScene" uid="uid://dwr3avefuwnpy" path="res://scenes/level_tutorial_1.tscn" id="2_7rb6w"]
|
||||
[ext_resource type="PackedScene" uid="uid://bol7g83v2accs" path="res://scenes/level_village_1.tscn" id="2_bentb"]
|
||||
[ext_resource type="PackedScene" uid="uid://chqb11pfoqmeb" path="res://scenes/level_village_2.tscn" id="3_ajlkg"]
|
||||
[ext_resource type="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/level_village_3.tscn" id="4_se5tb"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhad760x3vvco" path="res://scenes/level_village_4.tscn" id="5_mnosh"]
|
||||
[ext_resource type="PackedScene" uid="uid://bbwef3n2gjkt8" path="res://scenes/level_village_5.tscn" id="6_7rb6w"]
|
||||
[ext_resource type="Script" uid="uid://chrhjch4ymfvr" path="res://scripts/Screenshot.cs" id="6_bbtu1"]
|
||||
|
||||
[node name="GameManager" type="Node" unique_id=2076336659]
|
||||
[node name="GameManager" type="Node"]
|
||||
script = ExtResource("1_t2tr6")
|
||||
LevelScenes = Array[PackedScene]([ExtResource("2_7rb6w"), ExtResource("2_bentb"), ExtResource("3_ajlkg"), ExtResource("4_se5tb"), ExtResource("5_mnosh"), ExtResource("6_7rb6w")])
|
||||
LevelScenes = Array[PackedScene]([ExtResource("2_bentb"), ExtResource("3_ajlkg"), ExtResource("4_se5tb"), ExtResource("5_mnosh")])
|
||||
|
||||
[node name="Screenshot" type="Node" parent="." unique_id=812485936]
|
||||
[node name="Screenshot" type="Node" parent="."]
|
||||
script = ExtResource("6_bbtu1")
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,8 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://cala7bpo1v4no"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cala7bpo1v4no"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://chgw53qwt7rt8" path="res://scripts/components/Movement/GravityAbility.cs" id="1_tn5sj"]
|
||||
|
||||
[node name="GravityAbility" type="Node" unique_id=711941081]
|
||||
[node name="GravityAbility" type="Node"]
|
||||
script = ExtResource("1_tn5sj")
|
||||
DescendGravity = 1000.0
|
||||
metadata/_custom_type_script = "uid://chgw53qwt7rt8"
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
[gd_scene format=3 uid="uid://d0r5edxnx5jqx"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://d0r5edxnx5jqx"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ccksp2e76s7sr" path="res://scripts/components/Movement/VariableJumpAbility.cs" id="1_y30i5"]
|
||||
|
||||
[node name="VariableJumpAbility" type="Node" unique_id=735694377]
|
||||
[node name="VariableJumpAbility" type="Node"]
|
||||
script = ExtResource("1_y30i5")
|
||||
JumpHeight = 112.0
|
||||
JumpCutMultiplier = 0.507
|
||||
metadata/_custom_type_script = "uid://ccksp2e76s7sr"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bimyb8suadq3u"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dtxkjif7prm70"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dl7vthhurirwc" path="res://scripts/components/XRayVisionSkillComponent.cs" id="1_ebn6n"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://bi6v7u17vg1ww"]
|
||||
[gd_scene load_steps=13 format=3 uid="uid://bi6v7u17vg1ww"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dru77vj07e18s" path="res://Autoloads/SkillManager.cs" id="1_31033"]
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="2_87da4"]
|
||||
@@ -6,12 +6,13 @@
|
||||
[ext_resource type="Resource" uid="uid://cdp8sex36vdq2" path="res://resources/skills/explosive_brick.tres" id="4_53vnv"]
|
||||
[ext_resource type="Resource" uid="uid://cr5lo4h8wm0jc" path="res://resources/skills/fire_brick.tres" id="5_77gav"]
|
||||
[ext_resource type="Resource" uid="uid://ceakv6oqob6m7" path="res://resources/skills/ice_brick.tres" id="6_gib8v"]
|
||||
[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="7_6wy8o"]
|
||||
[ext_resource type="Resource" uid="uid://bxsgq8703qx4u" path="res://resources/skills/double_jump.tres" id="8_87da4"]
|
||||
[ext_resource type="Resource" uid="uid://cseilsspimw1n" path="res://resources/skills/ground_pound_skill.tres" id="9_77gav"]
|
||||
[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="10_gib8v"]
|
||||
[ext_resource type="Resource" uid="uid://c5dj06l86winx" path="res://resources/skills/xray_vision.tres" id="10_gib8v"]
|
||||
[ext_resource type="Resource" uid="uid://d12defdtmlk0u" path="res://resources/skills/brick_shield.tres" id="11_6wy8o"]
|
||||
[ext_resource type="Resource" uid="uid://dghnl301o1aiy" path="res://resources/skills/brick_armor.tres" id="12_gib8v"]
|
||||
|
||||
[node name="SkillManager" type="Node" unique_id=1205356464]
|
||||
[node name="SkillManager" type="Node"]
|
||||
script = ExtResource("1_31033")
|
||||
AvailableSkills = Array[ExtResource("2_87da4")]([ExtResource("3_shjvi"), ExtResource("4_53vnv"), ExtResource("5_77gav"), ExtResource("6_gib8v"), ExtResource("10_gib8v"), ExtResource("8_87da4"), ExtResource("9_77gav"), ExtResource("11_6wy8o"), ExtResource("12_gib8v")])
|
||||
AvailableSkills = Array[ExtResource("2_87da4")]([ExtResource("3_shjvi"), ExtResource("4_53vnv"), ExtResource("5_77gav"), ExtResource("6_gib8v"), ExtResource("7_6wy8o"), ExtResource("8_87da4"), ExtResource("9_77gav"), ExtResource("10_gib8v"), ExtResource("11_6wy8o"), ExtResource("12_gib8v")])
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://display_settings_scene"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://display_settings_script" path="res://scripts/UI/DisplaySettings.cs" id="1_dispset"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dispset"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="Display settings" type="Control" node_paths=PackedStringArray("WindowModeButton", "ResolutionButton", "DisplaySettingsControl")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 6
|
||||
size_flags_vertical = 6
|
||||
script = ExtResource("1_dispset")
|
||||
WindowModeButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Window Mode/WindowModeButton")
|
||||
ResolutionButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resolution/ResolutionButton")
|
||||
DisplaySettingsControl = NodePath(".")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_dispset")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="Display" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "DISPLAY"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Window Mode" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Window Mode"]
|
||||
layout_mode = 2
|
||||
text = "WINDOW_MODE"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="WindowModeButton" type="OptionButton" parent="PanelContainer/MarginContainer/VBoxContainer/Window Mode"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Resolution" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Resolution"]
|
||||
layout_mode = 2
|
||||
text = "RESOLUTION"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ResolutionButton" type="OptionButton" parent="PanelContainer/MarginContainer/VBoxContainer/Resolution"]
|
||||
layout_mode = 2
|
||||
@@ -1,97 +0,0 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://gameplay_settings_scene"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gameplay_settings_script" path="res://scripts/UI/GameplaySettings.cs" id="1_gameplay"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gameplay"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="Gameplay Settings" type="Control" node_paths=PackedStringArray("DeadzoneSlider", "DeadzoneValueLabel", "SensitivitySlider", "SensitivityValueLabel", "GameplaySettingsControl")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 6
|
||||
size_flags_vertical = 6
|
||||
script = ExtResource("1_gameplay")
|
||||
DeadzoneSlider = NodePath("PanelContainer/MarginContainer/VBoxContainer/Deadzone/HSlider")
|
||||
DeadzoneValueLabel = NodePath("PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer/DeadzoneValueLabel")
|
||||
SensitivitySlider = NodePath("PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HSlider")
|
||||
SensitivityValueLabel = NodePath("PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer/SensitivityValueLabel")
|
||||
GameplaySettingsControl = NodePath(".")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_gameplay")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="Gameplay" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "GAMEPLAY"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Deadzone" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DeadzoneLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "GAMEPAD_DEADZONE"
|
||||
|
||||
[node name="DeadzoneValueLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "0.20"
|
||||
|
||||
[node name="HSlider" type="HSlider" parent="PanelContainer/MarginContainer/VBoxContainer/Deadzone"]
|
||||
custom_minimum_size = Vector2(64, 0)
|
||||
layout_mode = 2
|
||||
value = 0.2
|
||||
|
||||
[node name="Sensitivity" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SensitivityLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "GAMEPAD_SENSITIVITY"
|
||||
|
||||
[node name="SensitivityValueLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "1.00"
|
||||
|
||||
[node name="HSlider" type="HSlider" parent="PanelContainer/MarginContainer/VBoxContainer/Sensitivity"]
|
||||
custom_minimum_size = Vector2(64, 0)
|
||||
layout_mode = 2
|
||||
value = 1.0
|
||||
@@ -1,25 +1,19 @@
|
||||
[gd_scene format=3 uid="uid://cvfsbiy5ggrpg"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cvfsbiy5ggrpg"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bxpr4m7lq7clh" path="res://objects/ui/input_button.tscn" id="1_h8s4o"]
|
||||
[ext_resource type="Script" uid="uid://dqefxy5hke5a" path="res://scripts/UI/InputSettings.cs" id="2_inputs"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_se25o"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="Input Settings" type="Control" unique_id=1872609318 node_paths=PackedStringArray("ActionsContainer", "ResetButton", "InputSettingsControl")]
|
||||
[node name="Input Settings" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("2_inputs")
|
||||
ActionsContainer = NodePath("PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions")
|
||||
ResetButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Reset to default Button")
|
||||
InputSettingsControl = NodePath(".")
|
||||
InputButtonScene = ExtResource("1_h8s4o")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=287000043]
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -28,33 +22,51 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_se25o")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=64621467]
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 16
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 16
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer" unique_id=2057149310]
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=1153692820]
|
||||
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "INPUT"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=1654052120]
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Actions" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer" unique_id=484943157]
|
||||
[node name="Actions" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="Reset to default Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=337239596]
|
||||
[node name="Input button" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input button2" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input button3" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input button4" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input button5" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input button6" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/Actions" instance=ExtResource("1_h8s4o")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Reset to default Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "RESET_TO_DEFAULT_BUTTON"
|
||||
flat = true
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[ext_resource type="Script" uid="uid://vokgv56bjpf1" path="res://scripts/UI/MarketplaceButton.cs" id="2_vb2qn"]
|
||||
|
||||
[node name="MarketplaceButton" type="Button" node_paths=PackedStringArray("SkillLevelContainer")]
|
||||
focus_mode = 2
|
||||
offset_right = 8.0
|
||||
offset_bottom = 8.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://i6mnjbjcoqe5"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://i6mnjbjcoqe5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cakgxndurgfa3" path="res://scripts/UI/PauseMenu.cs" id="1_h4pd5"]
|
||||
[ext_resource type="PackedScene" uid="uid://cl00e2ocomk3m" path="res://scenes/main_menu.tscn" id="2_h4pd5"]
|
||||
@@ -6,7 +6,7 @@
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4ivv"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="Pause menu" type="Control" unique_id=923659871 node_paths=PackedStringArray("PauseMenuControl", "ResumeButton", "MainMenuButton", "QuitButton", "SettingsButton")]
|
||||
[node name="Pause menu" type="Control" node_paths=PackedStringArray("PauseMenuControl", "ResumeButton", "MainMenuButton", "QuitButton", "SettingsButton")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -23,7 +23,7 @@ QuitButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Quit game Bu
|
||||
SettingsButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
|
||||
MainMenuScene = ExtResource("2_h4pd5")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=1782689001]
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -32,52 +32,46 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_g4ivv")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=824088919]
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer" unique_id=1826945529]
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="Pause" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=1706564131]
|
||||
[node name="Pause" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "PAUSE"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=868621584]
|
||||
[node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Resume Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=826636099]
|
||||
[node name="Resume Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
focus_next = NodePath("../Settings Button")
|
||||
text = "RESUME_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="Settings Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=334350065]
|
||||
[node name="Settings Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
focus_next = NodePath("../Exit to menu Button")
|
||||
focus_previous = NodePath("../Resume Button")
|
||||
text = "SETTINGS_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="Exit to menu Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=683937353]
|
||||
[node name="Exit to menu Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
focus_next = NodePath("../Quit game Button")
|
||||
focus_previous = NodePath("../Settings Button")
|
||||
text = "EXIT_TO_MENU_BUTTON"
|
||||
flat = true
|
||||
|
||||
[node name="Quit game Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=2008979602]
|
||||
[node name="Quit game Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
focus_previous = NodePath("../Exit to menu Button")
|
||||
text = "QUIT_BUTTON"
|
||||
flat = true
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[ext_resource type="Script" uid="uid://bw8dlgq86jrtt" path="res://scripts/UI/SkillButton.cs" id="2_m2732"]
|
||||
|
||||
[node name="SkillButton" type="Button"]
|
||||
focus_mode = 2
|
||||
offset_right = 8.0
|
||||
offset_bottom = 8.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
|
||||
config_version=5
|
||||
|
||||
[animation]
|
||||
|
||||
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Mr. Brick Adventures"
|
||||
@@ -23,39 +19,33 @@ config/version="in-dev"
|
||||
run/main_scene="uid://cl00e2ocomk3m"
|
||||
config/use_custom_user_dir=true
|
||||
config/custom_user_dir_name="MrBrickAdventures"
|
||||
config/features=PackedStringArray("4.6", "C#", "GL Compatibility")
|
||||
config/features=PackedStringArray("4.5", "C#", "GL Compatibility")
|
||||
run/max_fps=180
|
||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||
boot_splash/show_image=false
|
||||
boot_splash/stretch_mode=0
|
||||
boot_splash/fullsize=false
|
||||
boot_splash/use_filter=false
|
||||
config/icon="uid://jix7wdn0isr3"
|
||||
|
||||
[autoload]
|
||||
|
||||
GameManager="*res://objects/game_manager.tscn"
|
||||
PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd"
|
||||
AudioController="*res://objects/audio_controller.tscn"
|
||||
UIManager="*res://Autoloads/UIManager.cs"
|
||||
ConfigFileHandler="*res://Autoloads/ConfigFileHandler.cs"
|
||||
SettingsManager="*res://Autoloads/SettingsManager.cs"
|
||||
InputDeviceManager="*res://Autoloads/InputDeviceManager.cs"
|
||||
SaveSystem="*res://Autoloads/SaveSystem.cs"
|
||||
ConsoleManager="*res://Autoloads/ConsoleManager.cs"
|
||||
LimboConsole="*uid://dyxornv8vwibg"
|
||||
LimboConsole="*res://addons/limbo_console/limbo_console.gd"
|
||||
DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
||||
EventBus="*res://Autoloads/EventBus.cs"
|
||||
SteamManager="*res://Autoloads/SteamManager.cs"
|
||||
AchievementManager="*res://objects/achievement_manager.tscn"
|
||||
SkillManager="*res://objects/skill_manager.tscn"
|
||||
FloatingTextManager="*res://objects/floating_text_manager.tscn"
|
||||
EventBus="*res://Autoloads/EventBus.cs"
|
||||
StatisticsManager="*res://Autoloads/StatisticsManager.cs"
|
||||
SpeedRunManager="res://Autoloads/SpeedRunManager.cs"
|
||||
GhostManager="res://objects/ghost_manager.tscn"
|
||||
StatisticsEventHandler="*res://scripts/Events/StatisticsEventHandler.cs"
|
||||
CoinStateHandler="*res://scripts/Events/CoinStateHandler.cs"
|
||||
LivesStateHandler="*res://scripts/Events/LivesStateHandler.cs"
|
||||
SkillCollectHandler="*res://scripts/Events/SkillCollectHandler.cs"
|
||||
GameStateStore="*res://Autoloads/GameStateStore.cs"
|
||||
GameManager="*res://objects/game_manager.tscn"
|
||||
|
||||
[debug]
|
||||
|
||||
@@ -88,7 +78,7 @@ movie_writer/fps=24
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/ca_level_generator/plugin.cfg", "res://addons/dialogue_manager/plugin.cfg", "res://addons/limbo_console/plugin.cfg", "res://addons/phantom_camera/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://addons/limbo_console/plugin.cfg", "res://addons/phantom_camera/plugin.cfg")
|
||||
|
||||
[file_customization]
|
||||
|
||||
@@ -203,15 +193,18 @@ screenshot={
|
||||
}
|
||||
limbo_console_toggle={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":96,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
limbo_auto_complete_reverse={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194306,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
limbo_console_search_history={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[internationalization]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://bsnr5v2b2mfsl"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://bsnr5v2b2mfsl"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_wfbgp"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_wfbgp")
|
||||
Amount = 5.0
|
||||
Type = 1
|
||||
Type = 0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://b6xqotmke54x"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://b6xqotmke54x"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_5mosu"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_5mosu")
|
||||
Amount = 50.0
|
||||
Type = 1
|
||||
Type = 0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://b6apusc0jmi3x"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://b6apusc0jmi3x"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_d8txc"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_d8txc")
|
||||
Amount = 1.0
|
||||
Type = 2
|
||||
Type = 1
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://vql535ckoeqm"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://vql535ckoeqm"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_7pquc"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_7pquc")
|
||||
Amount = 1.0
|
||||
Type = 1
|
||||
Type = 0
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://dfyp1n4p52ydm"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_script"]
|
||||
[ext_resource type="Resource" uid="uid://bxsgq8703qx4u" path="res://resources/skills/double_jump.tres" id="2_skill"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_script")
|
||||
Type = 4
|
||||
Skill = ExtResource("2_skill")
|
||||
@@ -1,8 +1,9 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://2tl3yoh202no"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://2tl3yoh202no"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_brkhb"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_brkhb")
|
||||
Amount = 0.25
|
||||
Type = 3
|
||||
Type = 2
|
||||
metadata/_custom_type_script = "uid://cb5f0mx0hrt3b"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://bws2xldndlre1"]
|
||||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://bws2xldndlre1"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://gptsgaw3agkf" path="res://scripts/Resources/CollectableResource.cs" id="1_clntw"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_clntw")
|
||||
Amount = 50.0
|
||||
Type = 1
|
||||
Type = 0
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://qld841xv5ui0"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_chped"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_chped")
|
||||
LevelName = "LEVEL_5_NAME"
|
||||
ScenePath = "res://scenes/level_village_5.tscn"
|
||||
@@ -1,12 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="MovementPreset" format=3 uid="uid://vgutbpovj8hc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://tt1los3lafsi" path="res://scripts/Resources/MovementPreset.cs" id="1_0yvgi"]
|
||||
[ext_resource type="PackedScene" uid="uid://bcv8kx6bc7u5e" path="res://objects/movement_abilities/ground_ability.tscn" id="1_sll4h"]
|
||||
[ext_resource type="PackedScene" uid="uid://d0r5edxnx5jqx" path="res://objects/movement_abilities/variable_jump_ability.tscn" id="2_g20lq"]
|
||||
[ext_resource type="PackedScene" uid="uid://cala7bpo1v4no" path="res://objects/movement_abilities/gravity_ability.tscn" id="3_085b1"]
|
||||
[ext_resource type="PackedScene" uid="uid://bty3jq8u0pxkf" path="res://objects/movement_abilities/one_way_platform_ability.tscn" id="4_yebn0"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_0yvgi")
|
||||
Abilities = [ExtResource("1_sll4h"), ExtResource("2_g20lq"), ExtResource("3_085b1"), ExtResource("4_yebn0")]
|
||||
metadata/_custom_type_script = "uid://tt1los3lafsi"
|
||||
@@ -1,9 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="MovementPreset" format=3 uid="uid://d033qwwfs3i72"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://tt1los3lafsi" path="res://scripts/Resources/MovementPreset.cs" id="1_dfw61"]
|
||||
[ext_resource type="PackedScene" uid="uid://bu3vuxlrvoo1t" path="res://objects/movement_abilities/spaceship_ability.tscn" id="1_hadk8"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_dfw61")
|
||||
Abilities = [ExtResource("1_hadk8")]
|
||||
metadata/_custom_type_script = "uid://tt1los3lafsi"
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" format=3 uid="uid://dghnl301o1aiy"]
|
||||
[gd_resource type="Resource" script_class="SkillData" load_steps=5 format=3 uid="uid://dghnl301o1aiy"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cdeh7wfc62fr4" path="res://objects/player_skills/brick_armor_skill_component.tscn" id="1_aqcna"]
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="1_unqwr"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" format=3 uid="uid://d12defdtmlk0u"]
|
||||
[gd_resource type="Resource" script_class="SkillData" load_steps=6 format=3 uid="uid://d12defdtmlk0u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="1_m360g"]
|
||||
[ext_resource type="PackedScene" uid="uid://blwk5qduvdnxv" path="res://objects/player_skills/brick_shield_skill_component.tscn" id="1_xjknp"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" format=3 uid="uid://bxsgq8703qx4u"]
|
||||
[gd_resource type="Resource" script_class="SkillData" load_steps=5 format=3 uid="uid://bxsgq8703qx4u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="1_p5qvt"]
|
||||
[ext_resource type="PackedScene" uid="uid://dwaxbojb44a6l" path="res://objects/player_skills/double_jump_skill.tscn" id="1_t7o84"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" format=3 uid="uid://cseilsspimw1n"]
|
||||
[gd_resource type="Resource" script_class="SkillData" load_steps=5 format=3 uid="uid://cseilsspimw1n"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://lu3wvpqefekn" path="res://objects/player_skills/ground_pound_skill_component.tscn" id="1_auljr"]
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="1_i1qac"]
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" format=3 uid="uid://mwqffpqncwxo"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dwb0e05pewcsn" path="res://scripts/Resources/SkillUpgrade.cs" id="1_vptvl"]
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="2_rw7jf"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_rw7jf")
|
||||
metadata/_custom_type_script = "uid://d4crrfmbgxnqf"
|
||||
31
resources/skills/xray_vision.tres
Normal file
31
resources/skills/xray_vision.tres
Normal file
@@ -0,0 +1,31 @@
|
||||
[gd_resource type="Resource" script_class="SkillData" load_steps=6 format=3 uid="uid://c5dj06l86winx"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://dtxkjif7prm70" path="res://objects/player_skills/x_ray_vision_skill_component.tscn" id="1_ax2d8"]
|
||||
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="1_g8qe3"]
|
||||
[ext_resource type="Script" uid="uid://dwb0e05pewcsn" path="res://scripts/Resources/SkillUpgrade.cs" id="2_o726x"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_72ltj"]
|
||||
script = ExtResource("2_o726x")
|
||||
Cost = 200
|
||||
Description = ""
|
||||
Properties = Dictionary[String, Variant]({
|
||||
"duration": 5.0
|
||||
})
|
||||
metadata/_custom_type_script = "uid://dwb0e05pewcsn"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_2kdfi"]
|
||||
script = ExtResource("2_o726x")
|
||||
Cost = 275
|
||||
Description = ""
|
||||
Properties = Dictionary[String, Variant]({
|
||||
"duration": 10.0
|
||||
})
|
||||
metadata/_custom_type_script = "uid://dwb0e05pewcsn"
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_g8qe3")
|
||||
Name = "XRAY_VISION"
|
||||
Description = "XRAY_VISION_DESCRIPTION"
|
||||
Node = ExtResource("1_ax2d8")
|
||||
Upgrades = Array[ExtResource("2_o726x")]([SubResource("Resource_72ltj"), SubResource("Resource_2kdfi")])
|
||||
metadata/_custom_type_script = "uid://d4crrfmbgxnqf"
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="TileSet" format=3 uid="uid://dua4ns4tdknd1"]
|
||||
[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://dua4ns4tdknd1"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cysarpu6snb2y" path="res://sprites/ppc-tileset.png" id="4_ffexy"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="TileSet" format=3 uid="uid://bc5a20s6kuy8e"]
|
||||
[gd_resource type="TileSet" load_steps=23 format=3 uid="uid://bc5a20s6kuy8e"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_ej5iv"]
|
||||
[ext_resource type="PackedScene" uid="uid://54w4wisfj8v8" path="res://objects/entities/coin.tscn" id="2_31a0q"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="TileSet" format=3 uid="uid://bbppo0irxdmqy"]
|
||||
[gd_resource type="TileSet" load_steps=9 format=3 uid="uid://bbppo0irxdmqy"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_6ec4i"]
|
||||
[ext_resource type="Texture2D" uid="uid://cw42lvnqxubq2" path="res://sprites/PS_Tileset_10_nes.png" id="2_0dgh6"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="TileSet" format=3 uid="uid://ccffmjebvuoaj"]
|
||||
[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://ccffmjebvuoaj"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://dxvevrm15uus1" path="res://sprites/flowers_tileset.png" id="1_6pkiv"]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,12 +1,10 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://cl00e2ocomk3m"]
|
||||
[gd_scene load_steps=6 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://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://b5fx1vdfky307" path="res://objects/ui/audio_settings.tscn" id="4_8ln24"]
|
||||
[ext_resource type="PackedScene" uid="uid://cvfsbiy5ggrpg" path="res://objects/ui/input_settings.tscn" id="5_rtw2f"]
|
||||
[ext_resource type="PackedScene" uid="uid://display_settings_scene" path="res://objects/ui/display_settings.tscn" id="6_dispset"]
|
||||
[ext_resource type="PackedScene" uid="uid://gameplay_settings_scene" path="res://objects/ui/gameplay_settings.tscn" id="7_gameplay"]
|
||||
|
||||
[node name="Main menu" type="CanvasLayer"]
|
||||
|
||||
@@ -30,8 +28,14 @@ visible = false
|
||||
[node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")]
|
||||
visible = false
|
||||
|
||||
[node name="Gameplay Settings" parent="." instance=ExtResource("7_gameplay")]
|
||||
visible = false
|
||||
[node name="Gameplay Settings" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="Display Settings" parent="." instance=ExtResource("6_dispset")]
|
||||
visible = false
|
||||
[node name="Display Settings" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
159
scenes/pac_xon_mini_game.tscn
Normal file
159
scenes/pac_xon_mini_game.tscn
Normal file
@@ -0,0 +1,159 @@
|
||||
[gd_scene load_steps=18 format=3 uid="uid://bljbcv22gq872"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dx4m2ouyvwkir" path="res://scripts/components/PacXonGridManager.cs" id="1_0g620"]
|
||||
[ext_resource type="Texture2D" uid="uid://bolouq7v3acmx" path="res://sprites/pacxon_tileset.png" id="1_7fq4x"]
|
||||
[ext_resource type="Script" uid="uid://b8lu5pdufiy37" path="res://scripts/PacXonLevel.cs" id="2_lbrge"]
|
||||
[ext_resource type="PackedScene" uid="uid://bqi5s710xb1ju" path="res://objects/entities/brick_player.tscn" id="3_tehv8"]
|
||||
[ext_resource type="Texture2D" uid="uid://dedn7c7464pg2" path="res://sprites/brick_pacxon.png" id="5_tn615"]
|
||||
[ext_resource type="PackedScene" uid="uid://b3877xt5upsj2" path="res://objects/entities/ghost.tscn" id="6_8wuxa"]
|
||||
[ext_resource type="Script" uid="uid://d23haq52m7ulv" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="7_7j16a"]
|
||||
[ext_resource type="Script" uid="uid://ccfft4b8rwgbo" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="8_2w5m3"]
|
||||
|
||||
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tn615"]
|
||||
texture = ExtResource("1_7fq4x")
|
||||
0:0/0 = 0
|
||||
1:0/0 = 0
|
||||
2:0/0 = 0
|
||||
|
||||
[sub_resource type="TileSet" id="TileSet_8wuxa"]
|
||||
sources/0 = SubResource("TileSetAtlasSource_tn615")
|
||||
|
||||
[sub_resource type="Gradient" id="Gradient_qb72p"]
|
||||
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||
|
||||
[sub_resource type="GradientTexture1D" id="GradientTexture1D_lgb3u"]
|
||||
gradient = SubResource("Gradient_qb72p")
|
||||
|
||||
[sub_resource type="Curve" id="Curve_82d6e"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
|
||||
point_count = 2
|
||||
|
||||
[sub_resource type="CurveTexture" id="CurveTexture_xoue7"]
|
||||
curve = SubResource("Curve_82d6e")
|
||||
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_lgb3u"]
|
||||
resource_local_to_scene = true
|
||||
lifetime_randomness = 1.0
|
||||
particle_flag_disable_z = true
|
||||
emission_shape = 1
|
||||
emission_sphere_radius = 8.0
|
||||
direction = Vector3(0.1, -0.5, 0)
|
||||
initial_velocity_min = 200.0
|
||||
initial_velocity_max = 400.0
|
||||
gravity = Vector3(0, 80, 0)
|
||||
damping_min = 400.0
|
||||
damping_max = 800.0
|
||||
scale_max = 3.0
|
||||
scale_curve = SubResource("CurveTexture_xoue7")
|
||||
color = Color(0.764706, 0.443137, 0, 1)
|
||||
color_ramp = SubResource("GradientTexture1D_lgb3u")
|
||||
|
||||
[sub_resource type="Resource" id="Resource_uptla"]
|
||||
script = ExtResource("8_2w5m3")
|
||||
duration = 1.0
|
||||
transition = 0
|
||||
ease = 2
|
||||
|
||||
[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_7j16a"]
|
||||
|
||||
[node name="PacXonMiniGame" type="Node2D"]
|
||||
|
||||
[node name="PacXonGridManager" type="TileMapLayer" parent="."]
|
||||
tile_set = SubResource("TileSet_8wuxa")
|
||||
script = ExtResource("1_0g620")
|
||||
PlayArea = Rect2i(1, 1, 27, 14)
|
||||
metadata/_custom_type_script = "uid://dx4m2ouyvwkir"
|
||||
|
||||
[node name="PacXonLevel" type="Node" parent="." node_paths=PackedStringArray("Player", "GridManager", "GhostContainer", "PercentageLabel")]
|
||||
script = ExtResource("2_lbrge")
|
||||
Player = NodePath("../Brick Player")
|
||||
GridManager = NodePath("../PacXonGridManager")
|
||||
GhostContainer = NodePath("../Ghosts")
|
||||
PercentageLabel = NodePath("../Label")
|
||||
metadata/_custom_type_script = "uid://b8lu5pdufiy37"
|
||||
|
||||
[node name="Brick Player" parent="." instance=ExtResource("3_tehv8")]
|
||||
position = Vector2(101, 213)
|
||||
motion_mode = 1
|
||||
metadata/_edit_group_ = true
|
||||
|
||||
[node name="GroundMovementAbility" parent="Brick Player/Movements" index="0"]
|
||||
process_mode = 4
|
||||
|
||||
[node name="GravityAbility" parent="Brick Player/Movements" index="1"]
|
||||
process_mode = 4
|
||||
|
||||
[node name="VariableJumpAbility" parent="Brick Player/Movements" index="2"]
|
||||
process_mode = 4
|
||||
|
||||
[node name="OneWayPlatformAbility" parent="Brick Player/Movements" index="3"]
|
||||
process_mode = 4
|
||||
|
||||
[node name="Base" parent="Brick Player/Graphics/Root" index="0"]
|
||||
texture = ExtResource("5_tn615")
|
||||
hframes = 1
|
||||
|
||||
[node name="Left Eye" parent="Brick Player/Graphics/Root" index="1"]
|
||||
visible = false
|
||||
|
||||
[node name="Right Eye" parent="Brick Player/Graphics/Root" index="2"]
|
||||
visible = false
|
||||
|
||||
[node name="HitParticles" parent="Brick Player" index="24"]
|
||||
process_material = SubResource("ParticleProcessMaterial_lgb3u")
|
||||
|
||||
[node name="VisibleOnScreenNotifier2D" parent="Brick Player" index="27"]
|
||||
position = Vector2(0, -4.76837e-07)
|
||||
scale = Vector2(0.8, 0.8)
|
||||
|
||||
[node name="Ghosts" type="Node2D" parent="."]
|
||||
|
||||
[node name="Ghost" parent="Ghosts" instance=ExtResource("6_8wuxa")]
|
||||
position = Vector2(252, 155)
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_left = 73.0
|
||||
offset_right = 121.0
|
||||
offset_bottom = 8.0
|
||||
text = "sdsdsd"
|
||||
|
||||
[node name="PhantomCamera2D" type="Node2D" parent="."]
|
||||
position = Vector2(-240, -135)
|
||||
script = ExtResource("7_7j16a")
|
||||
snap_to_pixel = true
|
||||
tween_resource = SubResource("Resource_uptla")
|
||||
draw_limits = true
|
||||
limit_target = NodePath("../PacXonGridManager")
|
||||
metadata/_custom_type_script = "uid://d23haq52m7ulv"
|
||||
|
||||
[node name="Word boundary top" type="StaticBody2D" parent="."]
|
||||
position = Vector2(0, -2)
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Word boundary top"]
|
||||
shape = SubResource("WorldBoundaryShape2D_7j16a")
|
||||
|
||||
[node name="Word boundary bottom" type="StaticBody2D" parent="."]
|
||||
position = Vector2(0, 272)
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Word boundary bottom"]
|
||||
shape = SubResource("WorldBoundaryShape2D_7j16a")
|
||||
|
||||
[node name="Word boundary left" type="StaticBody2D" parent="."]
|
||||
position = Vector2(0, 272)
|
||||
rotation = 1.5708
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Word boundary left"]
|
||||
shape = SubResource("WorldBoundaryShape2D_7j16a")
|
||||
|
||||
[node name="Word boundary right" type="StaticBody2D" parent="."]
|
||||
position = Vector2(482, 272)
|
||||
rotation = -1.5708
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Word boundary right"]
|
||||
shape = SubResource("WorldBoundaryShape2D_7j16a")
|
||||
|
||||
[editable path="Brick Player"]
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace Mr.BrickAdventures;
|
||||
|
||||
/// <summary>
|
||||
/// Constants for autoload paths and other commonly used values.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
// Autoload paths
|
||||
public const string EventBusPath = "/root/EventBus";
|
||||
public const string GameManagerPath = "/root/GameManager";
|
||||
public const string GameStateStorePath = "/root/GameStateStore";
|
||||
public const string SaveSystemPath = "/root/SaveSystem";
|
||||
public const string SpeedRunManagerPath = "/root/SpeedRunManager";
|
||||
public const string GhostManagerPath = "/root/GhostManager";
|
||||
public const string AchievementManagerPath = "/root/AchievementManager";
|
||||
public const string StatisticsManagerPath = "/root/StatisticsManager";
|
||||
public const string SkillManagerPath = "/root/SkillManager";
|
||||
public const string FloatingTextManagerPath = "/root/FloatingTextManager";
|
||||
public const string UIManagerPath = "/root/UIManager";
|
||||
public const string ConsoleManagerPath = "/root/ConsoleManager";
|
||||
public const string ConfigFileHandlerPath = "/root/ConfigFileHandler";
|
||||
|
||||
// Group names
|
||||
public const string CoinsGroup = "coins";
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://bn7o3n3bomvrd
|
||||
@@ -1,29 +0,0 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Handles coin collection events and updates the GameStateStore.
|
||||
/// Replaces the manual coin logic in GameManager.
|
||||
/// </summary>
|
||||
public partial class CoinStateHandler : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
EventBus.Instance.CoinCollected += OnCoinCollected;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.CoinCollected -= OnCoinCollected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCoinCollected(int amount, Vector2 position)
|
||||
{
|
||||
GameStateStore.Instance?.AddSessionCoins(amount);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://1qg3q53kkh0k
|
||||
@@ -1,5 +1,4 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
@@ -7,30 +6,26 @@ namespace Mr.BrickAdventures.scripts.Events;
|
||||
[GlobalClass]
|
||||
public partial class GhostEventHandler : Node
|
||||
{
|
||||
private GhostManager _ghostManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
EventBus.Instance.LevelStarted += OnLevelStarted;
|
||||
EventBus.Instance.LevelCompleted += OnLevelCompleted;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.LevelStarted -= OnLevelStarted;
|
||||
EventBus.Instance.LevelCompleted -= OnLevelCompleted;
|
||||
}
|
||||
_ghostManager = GetNode<GhostManager>("/root/GhostManager");
|
||||
var eventBus = GetNode<EventBus>("/root/EventBus");
|
||||
|
||||
eventBus.LevelStarted += OnLevelStarted;
|
||||
eventBus.LevelCompleted += OnLevelCompleted;
|
||||
}
|
||||
|
||||
private void OnLevelStarted(int levelIndex, Node currentScene)
|
||||
{
|
||||
GD.Print($"GhostEventHandler: Level {levelIndex} started.");
|
||||
GhostManager.Instance.StartRecording(levelIndex);
|
||||
GhostManager.Instance.SpawnGhostPlayer(levelIndex, currentScene);
|
||||
_ghostManager.StartRecording(levelIndex);
|
||||
_ghostManager.SpawnGhostPlayer(levelIndex, currentScene);
|
||||
}
|
||||
|
||||
|
||||
private void OnLevelCompleted(int levelIndex, Node currentScene, double completionTime)
|
||||
{
|
||||
GhostManager.Instance.StopRecording(true, completionTime);
|
||||
_ghostManager.StopRecording(true, completionTime);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Handles player death events and updates lives in GameStateStore.
|
||||
/// </summary>
|
||||
public partial class LivesStateHandler : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
EventBus.Instance.PlayerDied += OnPlayerDied;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.PlayerDied -= OnPlayerDied;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerDied(Vector2 position)
|
||||
{
|
||||
GameStateStore.Instance?.RemoveLife();
|
||||
GameStateStore.Instance?.ResetSession();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://b4ocg7g8vmtvp
|
||||
@@ -1,41 +0,0 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Handles skill collection events and unlocks skills via GameStateStore.
|
||||
/// Skills are immediately activated but only persisted on level complete.
|
||||
/// </summary>
|
||||
public partial class SkillCollectHandler : Node
|
||||
{
|
||||
private SkillManager SkillManager => SkillManager.Instance;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
EventBus.Instance.SkillCollected += OnSkillCollected;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.SkillCollected -= OnSkillCollected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSkillCollected(SkillData skill, Vector2 position)
|
||||
{
|
||||
if (skill == null) return;
|
||||
|
||||
// Unlock in session (will be committed on level complete, lost on death)
|
||||
GameStateStore.Instance?.UnlockSkillInSession(skill);
|
||||
|
||||
// Immediately activate the skill for the player
|
||||
SkillManager?.AddSkill(skill);
|
||||
|
||||
// Emit skill unlocked event for UI/achievements
|
||||
EventBus.EmitSkillUnlocked(skill.Name, skill.Level);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://c1po4hjvqbslm
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user