Add Resume/Exit buttons to pause menu, handle logic for returning to main menu and starting a new game

This commit is contained in:
2025-12-05 20:05:28 -08:00
parent 678916be89
commit 5b9de11e5a
17 changed files with 354 additions and 239 deletions

View File

@@ -1,20 +1,14 @@
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Godot;
using Godot.Collections;
using NathanHoad;
using SimpleInjector.Lifestyles;
using System;
using System.IO.Abstractions;
using System.Linq;
using System.Threading.Tasks;
using Zennysoft.Game.Abstractions;
using Zennysoft.Game.Implementation;
using Zennysoft.Ma.Adapter;
using static Zennysoft.Game.Ma.SceneLoader;
using static Zennysoft.Ma.Adapter.AppLogic.State;
namespace Zennysoft.Game.Ma;
@@ -37,8 +31,6 @@ public partial class App : Node, IApp
[Node] private GalleryMenu GalleryMenu { get; set; }
public IInstantiator Instantiator { get; set; } = default!;
IAppRepo IProvide<IAppRepo>.Value() => AppRepo;
public IAppRepo AppRepo { get; set; } = default!;
@@ -57,9 +49,6 @@ public partial class App : Node, IApp
private IGame _game;
private IDataViewer _enemyViewer;
private event Action OnGameLoaded;
private event Action OnEnemyViewerLoaded;
private double _reportedProgress = 0;
public void Initialize()
@@ -110,6 +99,11 @@ public partial class App : Node, IApp
this.Provide();
}
private void GameExitRequested()
{
AppLogic.Input(new AppLogic.Input.QuitGame());
}
private void DeleteSaveData()
{
var saveFileManager = _container.GetInstance<ISaveFileManager>();
@@ -150,27 +144,31 @@ public partial class App : Node, IApp
})
.Handle((in AppLogic.Output.SetupGameScene _) =>
{
LoadingScreen.Show();
LoadGame(GAME_SCENE_PATH);
MainMenu.ReleaseFocus();
MainMenu.Hide();
})
.Handle((in AppLogic.Output.ShowMainMenu _) =>
{
})
.Handle((in AppLogic.Output.ShowGame _) =>
.Handle((in AppLogic.Output.CloseGame _) =>
{
LoadingScreen.Hide();
_game.GameExitRequested -= GameExitRequested;
MainMenu.StartGameButton.GrabFocus();
_game.CallDeferred(MethodName.QueueFree, []);
GetTree().Paused = false;
})
.Handle((in AppLogic.Output.StartLoadingSaveFile _) =>
{
})
.Handle((in AppLogic.Output.EnemyViewerOpened _) =>
{
LoadingScreen.Show();
LoadEnemyViewer(ENEMY_VIEWER_PATH);
MainMenu.ReleaseFocus();
MainMenu.Hide();
})
.Handle((in AppLogic.Output.EnemyViewerExited _) =>
{
LoadingScreen.Hide();
if (_enemyViewer != null && _enemyViewer is DataViewer enemyViewer)
enemyViewer.CallDeferred(MethodName.QueueFree);
MainMenu.Show();
@@ -202,6 +200,7 @@ public partial class App : Node, IApp
{
var scene = await LoadSceneInternal(sceneName);
_game = scene as IGame;
_game.GameExitRequested += GameExitRequested;
await ToSignal(GetTree().CreateTimer(0.8f), "timeout");
CallDeferred(MethodName.AddChild, scene);
}
@@ -216,6 +215,7 @@ public partial class App : Node, IApp
private async Task<Node> LoadSceneInternal(string sceneName)
{
LoadingScreen.Show();
LoadingScreen.ProgressBar.Value = 0;
var sceneLoader = new SceneLoader();
CallDeferred(MethodName.AddChild, sceneLoader);

View File

@@ -10,12 +10,13 @@
process_mode = 3
script = ExtResource("1_rt73h")
[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")]
unique_name_in_owner = true
[node name="MainMenu" parent="." instance=ExtResource("2_1uiag")]
unique_name_in_owner = true
[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")]
unique_name_in_owner = true
visible = false
[node name="OptionsMenu" parent="." instance=ExtResource("2_v0mgf")]
unique_name_in_owner = true
visible = false

View File

@@ -56,6 +56,8 @@ public partial class Game : Node3D, IGame
[Signal]
public delegate void SaveFileLoadedEventHandler();
public event Action GameExitRequested;
#endregion
public RescuedItemDatabase RescuedItems { get; set; } = default!;
@@ -174,6 +176,8 @@ public partial class Game : Node3D, IGame
GameOverMenu.NewGame += OnNewGame;
GameOverMenu.QuitGame += OnQuit;
PauseMenu.ExitGamePressed += OnQuit;
GameRepo.IsPaused.Sync += IsPaused_Sync;
InGameUI.PlayerInfoUI.Activate();
}
@@ -252,6 +256,12 @@ public partial class Game : Node3D, IGame
{
if (@event.IsActionPressed(GameInputs.Debug))
GameState.Input(new GameState.Input.DebugButtonPressed());
if (@event.IsActionPressed(GameInputs.Pause))
GameState.Input(new GameState.Input.PauseButtonPressed());
if (Input.IsActionJustPressed(GameInputs.Inventory))
GameState.Input(new GameState.Input.InventoryButtonPressed());
if (Input.IsActionJustPressed(GameInputs.Interact))
GameState.Input(new GameState.Input.InteractButtonPressed());
}
private void HandleGameLogic()
@@ -280,12 +290,13 @@ public partial class Game : Node3D, IGame
})
.Handle((in GameState.Output.OpenInventoryMenu _) =>
{
//InGameUI.InventoryMenu.RefreshInventoryScreen();
GameRepo.Pause();
InGameUI.InventoryMenu.Show();
InGameUI.InventoryMenu.SetProcessInput(true);
})
.Handle((in GameState.Output.CloseInventoryMenu _) =>
{
GameRepo.Resume();
InGameUI.InventoryMenu.Hide();
InGameUI.InventoryMenu.SetProcessInput(false);
})
@@ -337,6 +348,10 @@ public partial class Game : Node3D, IGame
}
LoadNextLevel.FadeOut();
})
.Handle((in GameState.Output.ExitGame _) =>
{
OnQuit();
})
.Handle((in GameState.Output.GameOver _) =>
{
//GameRepo.Pause();
@@ -507,7 +522,7 @@ public partial class Game : Node3D, IGame
LoadNextLevel.Hide();
}
private void OnQuit() => GetTree().Root.QueueFree();
private void OnQuit() => GameExitRequested?.Invoke();
public void OnExitTree()
{

View File

@@ -4,6 +4,7 @@ namespace Zennysoft.Game.Ma;
using Chickensoft.AutoInject;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.SaveFileBuilder;
using System;
using System.Threading.Tasks;
using Zennysoft.Ma.Adapter;
@@ -30,4 +31,6 @@ public interface IGame : IProvide<IGame>, IProvide<IGameRepo>, IProvide<IPlayer>
public Task Save();
public QuestData QuestData { get; }
public event Action GameExitRequested;
}

View File

@@ -7,6 +7,7 @@
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1ctjd"]
[node name="Control" type="Control"]
process_mode = 3
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0

View File

@@ -107,187 +107,187 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
public void Initialize()
{
var container = new SimpleInjector.Container();
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
var container = new SimpleInjector.Container();
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
PlayerLogic = container.GetInstance<IPlayerLogic>();
PlayerLogic.Set(this as IPlayer);
PlayerLogic.Set(Settings);
PlayerLogic = container.GetInstance<IPlayerLogic>();
PlayerLogic.Set(this as IPlayer);
PlayerLogic.Set(Settings);
Inventory = new Inventory();
HealthComponent = new HealthComponent(InitialHP);
VTComponent = new VTComponent(InitialVT);
AttackComponent = new AttackComponent(InitialAttack);
DefenseComponent = new DefenseComponent(InitialDefense);
ExperiencePointsComponent = new ExperiencePointsComponent();
LuckComponent = new LuckComponent(InitialLuck);
EquipmentComponent = new EquipmentComponent();
Inventory = new Inventory();
HealthComponent = new HealthComponent(InitialHP);
VTComponent = new VTComponent(InitialVT);
AttackComponent = new AttackComponent(InitialAttack);
DefenseComponent = new DefenseComponent(InitialDefense);
ExperiencePointsComponent = new ExperiencePointsComponent();
LuckComponent = new LuckComponent(InitialLuck);
EquipmentComponent = new EquipmentComponent();
_itemReroller = new ItemReroller(ItemDatabase.Instance);
_itemReroller = new ItemReroller(ItemDatabase.Instance);
Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration };
Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration };
PlayerBinding = PlayerLogic.Bind();
PlayerBinding = PlayerLogic.Bind();
PlayerBinding
.Handle((in PlayerLogic.Output.ThrowItem output) =>
{
})
.Handle((in PlayerLogic.Output.Move output) =>
{
Move(output.delta);
});
PlayerBinding
.Handle((in PlayerLogic.Output.ThrowItem output) =>
{
})
.Handle((in PlayerLogic.Output.Move output) =>
{
Move(output.delta);
});
PlayerLogic.Start();
this.Provide();
PlayerLogic.Start();
this.Provide();
}
public void ResetPlayerData()
{
foreach (var item in Inventory.Items)
Inventory.Remove(item);
foreach (var item in Inventory.Items)
Inventory.Remove(item);
HealthComponent.Reset();
VTComponent.Reset();
AttackComponent.Reset();
DefenseComponent.Reset();
ExperiencePointsComponent.Reset();
LuckComponent.Reset();
EquipmentComponent.Reset();
HealthComponent.Reset();
VTComponent.Reset();
AttackComponent.Reset();
DefenseComponent.Reset();
ExperiencePointsComponent.Reset();
LuckComponent.Reset();
EquipmentComponent.Reset();
HealthTimer.Timeout += OnHealthTimerTimeout;
HealthTimer.Timeout += OnHealthTimerTimeout;
}
#region Initialization
public void OnReady()
{
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
HealthComponent.HealthReachedZero += Die;
HealthTimer.WaitTime = _healthTimerWaitTime;
SetProcessInput(false);
SetPhysicsProcess(false);
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
HealthComponent.HealthReachedZero += Die;
HealthTimer.WaitTime = _healthTimerWaitTime;
SetProcessInput(false);
SetPhysicsProcess(false);
}
#endregion
public void Activate()
{
SetProcessInput(true);
SetPhysicsProcess(true);
SetHealthTimerStatus(HealthTimerIsActive);
SetProcessInput(true);
SetPhysicsProcess(true);
SetHealthTimerStatus(HealthTimerIsActive);
}
public void Deactivate()
{
Velocity = Vector3.Zero;
SetProcessInput(false);
SetPhysicsProcess(false);
SetHealthTimerStatus(false);
Velocity = Vector3.Zero;
SetProcessInput(false);
SetPhysicsProcess(false);
SetHealthTimerStatus(false);
}
private void SetHealthTimerStatus(bool isActive)
{
if (isActive)
HealthTimer.Start();
else
HealthTimer.Stop();
if (isActive)
HealthTimer.Start();
else
HealthTimer.Stop();
}
public void TeleportPlayer(Transform3D newTransform)
{
Transform = newTransform;
Transform = newTransform;
}
public void TakeDamage(AttackData damage)
{
_camera3D.AddShake(1.0f);
TakeDamageAnimationPlayer.Play("take_damage");
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance);
HealthComponent.Damage(damageReceived);
SfxDatabase.Instance.Play(SoundEffect.TakeDamage);
_camera3D.AddShake(1.0f);
TakeDamageAnimationPlayer.Play("take_damage");
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance);
HealthComponent.Damage(damageReceived);
SfxDatabase.Instance.Play(SoundEffect.TakeDamage);
}
public void Knockback(float impulse)
{
_knockbackStrength = impulse;
_knockbackDirection = GlobalBasis.Z.Normalized();
_knockbackStrength = impulse;
_knockbackDirection = GlobalBasis.Z.Normalized();
}
public void LevelUp()
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var hpIncrease = rng.RandiRange(3, 6);
HealthComponent.RaiseMaximumHP(hpIncrease);
ExperiencePointsComponent.LevelUp();
var rng = new RandomNumberGenerator();
rng.Randomize();
var hpIncrease = rng.RandiRange(3, 6);
HealthComponent.RaiseMaximumHP(hpIncrease);
ExperiencePointsComponent.LevelUp();
}
public void Die()
{
PlayerFXAnimations.Play("death");
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout -= OnHealthTimerTimeout;
SetProcessInput(false);
SetPhysicsProcess(false);
PlayerDied?.Invoke();
PlayerFXAnimations.Play("death");
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout -= OnHealthTimerTimeout;
SetProcessInput(false);
SetPhysicsProcess(false);
PlayerDied?.Invoke();
}
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed(GameInputs.Attack))
Attack();
if (@event.IsActionPressed(GameInputs.Sprint))
Settings.MoveSpeed *= 2;
if (@event.IsActionReleased(GameInputs.Sprint))
Settings.MoveSpeed /= 2;
if (@event.IsActionPressed(GameInputs.Attack))
Attack();
if (@event.IsActionPressed(GameInputs.Sprint))
Settings.MoveSpeed *= 2;
if (@event.IsActionReleased(GameInputs.Sprint))
Settings.MoveSpeed /= 2;
}
public void PlayTestAnimation()
{
PlayerFXAnimations.Play("test_animation");
PlayerFXAnimations.Play("test_animation");
}
public void OnPhysicsProcess(double delta)
{
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
}
public void Equip(EquipableItem equipable)
{
if (equipable.ItemTag == ItemTag.MysteryItem)
{
var rerolledItem = _itemReroller.RerollItem(equipable, Inventory);
Equip(rerolledItem);
return;
}
if (equipable.ItemTag == ItemTag.MysteryItem)
{
var rerolledItem = _itemReroller.RerollItem(equipable, Inventory);
Equip(rerolledItem);
return;
}
HealthComponent.RaiseMaximumHP(equipable.BonusHP, false);
VTComponent.RaiseMaximumVT(equipable.BonusVT, false);
HealthComponent.RaiseMaximumHP(equipable.BonusHP, false);
VTComponent.RaiseMaximumVT(equipable.BonusVT, false);
EquipmentComponent.Equip(equipable);
EquipmentComponent.Equip(equipable);
}
public void Unequip(EquipableItem equipable)
{
HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP);
VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT);
HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP);
VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT);
EquipmentComponent.Unequip(equipable);
EquipmentComponent.Unequip(equipable);
}
private static Vector3 GlobalInputVector
{
get
{
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
var input = new Vector3
{
X = rawInput.X,
Z = rawInput.Y
};
return input with { Y = 0f };
}
get
{
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
var input = new Vector3
{
X = rawInput.X,
Z = rawInput.Y
};
return input with { Y = 0f };
}
}
private static float LeftStrafeInputVector => Input.GetActionStrength(GameInputs.StrafeLeft);
@@ -296,143 +296,143 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
private void Attack()
{
if (PlayerIsHittingGeometry())
AnimationPlayer.Play("hit_wall");
else if (!AnimationPlayer.IsPlaying())
PlayAttackAnimation();
if (PlayerIsHittingGeometry())
AnimationPlayer.Play("hit_wall");
else if (!AnimationPlayer.IsPlaying())
PlayAttackAnimation();
}
private void ThrowItem()
{
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
var throwItem = itemScene.Instantiate<ThrowableItem>();
GetTree().Root.AddChildEx(throwItem);
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
throwItem.GlobalRotation = GlobalRotation;
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
var throwItem = itemScene.Instantiate<ThrowableItem>();
GetTree().Root.AddChildEx(throwItem);
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
throwItem.GlobalRotation = GlobalRotation;
}
private void PlayAttackAnimation()
{
SfxDatabase.Instance.Play(((Weapon)EquipmentComponent.EquippedWeapon.Value).SoundEffect);
var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed;
AnimationPlayer.SetSpeedScale((float)attackSpeed);
AnimationPlayer.Play("attack");
SfxDatabase.Instance.Play(((Weapon)EquipmentComponent.EquippedWeapon.Value).SoundEffect);
var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed;
AnimationPlayer.SetSpeedScale((float)attackSpeed);
AnimationPlayer.Play("attack");
}
private void OnExitTree()
{
PlayerLogic.Stop();
PlayerBinding.Dispose();
Hitbox.AreaEntered -= Hitbox_AreaEntered;
CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered;
HealthComponent.HealthReachedZero -= Die;
HealthTimer.Timeout -= OnHealthTimerTimeout;
PlayerLogic.Stop();
PlayerBinding.Dispose();
Hitbox.AreaEntered -= Hitbox_AreaEntered;
CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered;
HealthComponent.HealthReachedZero -= Die;
HealthTimer.Timeout -= OnHealthTimerTimeout;
}
private void Move(float delta)
{
var rawInput = GlobalInputVector;
var strafeLeftInput = LeftStrafeInputVector;
var strafeRightInput = RightStrafeInputVector;
var rawInput = GlobalInputVector;
var strafeLeftInput = LeftStrafeInputVector;
var strafeRightInput = RightStrafeInputVector;
var transform = Transform;
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
_knockbackStrength *= 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
if (!WalkSFX.Playing && !Velocity.IsZeroApprox())
WalkSFX.Play();
else if (Velocity.IsZeroApprox())
WalkSFX.Stop();
MoveAndSlide();
var transform = Transform;
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
_knockbackStrength *= 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
if (!WalkSFX.Playing && !Velocity.IsZeroApprox())
WalkSFX.Play();
else if (Velocity.IsZeroApprox())
WalkSFX.Stop();
MoveAndSlide();
}
private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition;
private void OnHealthTimerTimeout()
{
if (VTComponent.CurrentVT.Value > 0)
{
if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
reduceOnTick = !reduceOnTick;
if (VTComponent.CurrentVT.Value > 0)
{
if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
reduceOnTick = !reduceOnTick;
HealthComponent.Heal(1);
HealthComponent.Heal(1);
if (reduceOnTick)
VTComponent.Reduce(1);
}
else
HealthComponent.Damage(1);
if (reduceOnTick)
VTComponent.Reduce(1);
}
else
HealthComponent.Damage(1);
}
private void Hitbox_AreaEntered(Area3D area)
{
var target = area.GetOwner();
if (target is IEnemy enemy)
HitEnemy(enemy);
var target = area.GetOwner();
if (target is IEnemy enemy)
HitEnemy(enemy);
}
private void HitEnemy(IEnemy enemy)
{
var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity;
var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense;
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck);
var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack;
var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement;
var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity;
var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense;
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck);
var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack;
var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement;
if (isCriticalHit)
{
totalDamage += (int)(totalDamage * 0.5f);
SfxDatabase.Instance.Play(SoundEffect.Crit);
}
if (isCriticalHit)
{
totalDamage += (int)(totalDamage * 0.5f);
SfxDatabase.Instance.Play(SoundEffect.Crit);
}
var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance);
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None);
enemy.HealthComponent.Damage(damageDealt);
var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance);
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None);
enemy.HealthComponent.Damage(damageDealt);
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized());
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
HealthComponent.Damage(5);
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized());
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
HealthComponent.Damage(5);
}
private void CollisionDetector_AreaEntered(Area3D area)
{
if (area.GetParent() is InventoryItem inventoryItem)
{
var isAdded = Inventory.PickUpItem(inventoryItem);
if (isAdded)
inventoryItem.QueueFree();
}
if (area.GetParent() is DroppedItem droppedItem)
{
var isAdded = Inventory.PickUpItem(droppedItem.Item);
if (isAdded)
droppedItem.QueueFree();
}
if (area.GetParent() is ThrownItem thrownItem)
{
var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown);
if (isAdded)
thrownItem.QueueFree();
}
if (area.GetParent() is Restorative restorative)
{
restorative.QueueFree();
}
if (area.GetParent() is InventoryItem inventoryItem)
{
var isAdded = Inventory.PickUpItem(inventoryItem);
if (isAdded)
inventoryItem.QueueFree();
}
if (area.GetParent() is DroppedItem droppedItem)
{
var isAdded = Inventory.PickUpItem(droppedItem.Item);
if (isAdded)
droppedItem.QueueFree();
}
if (area.GetParent() is ThrownItem thrownItem)
{
var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown);
if (isAdded)
thrownItem.QueueFree();
}
if (area.GetParent() is Restorative restorative)
{
restorative.QueueFree();
}
}
private bool PlayerIsHittingGeometry()
{
var collisions = WallCheck.GetCollidingBodies();
return collisions.Count > 0;
var collisions = WallCheck.GetCollidingBodies();
return collisions.Count > 0;
}
private void WallCheck_BodyEntered(Node body)
{
GD.Print("Hit wall");
AnimationPlayer.Stop();
GD.Print("Hit wall");
AnimationPlayer.Stop();
}
}

View File

@@ -56,8 +56,17 @@ public partial class GalleryMenu : Control
public void OnReady()
{
GalleryData = new GalleryData() { PlaceholderImage1 = true };
BackButton.Pressed += BackButton_Pressed;
GalleryData = new GalleryData() { PlaceholderImage1 = true };
BackButton.Pressed += BackButton_Pressed;
}
public override void _Input(InputEvent @event)
{
if (!Visible)
return;
if (@event.IsActionPressed(GameInputs.Interact))
BackButton.GrabFocus();
}
private void BackButton_Pressed() => EmitSignal(SignalName.GalleryExited);

View File

@@ -57,13 +57,4 @@ public partial class InGameUI : Control, IInGameUI
InventoryMenu.Hide();
InventoryMenu.SetProcessInput(false);
}
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed(GameInputs.Inventory) && !InventoryMenu.Visible)
{
GD.Print("Inventory button pressed");
InGameUILogic.Input(new InGameUILogic.Input.ShowInventory());
}
}
}

View File

@@ -100,7 +100,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
SfxDatabase.Instance.Play(SoundEffect.MoveUI);
}
public override void _Input(InputEvent @event)
public override void _UnhandledInput(InputEvent @event)
{
if (!Visible)
return;
@@ -108,12 +108,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
if ((!Input.IsActionJustPressed(GameInputs.UiUp) && Input.IsActionPressed(GameInputs.UiUp)) || (!Input.IsActionJustPressed(GameInputs.UiDown) && Input.IsActionPressed(GameInputs.UiDown)))
AcceptEvent();
if (Input.IsActionJustPressed(GameInputs.Inventory) && !(UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
{
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
AcceptEvent();
_gameRepo.CloseInventory();
}
if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
{
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
@@ -153,6 +147,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
}
else
{
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
_enableMenuSound = false;
}
}

View File

@@ -2,6 +2,7 @@ using Chickensoft.AutoInject;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Godot;
using System;
namespace Zennysoft.Game.Ma;
public interface IPauseMenu : IControl
@@ -10,6 +11,8 @@ public interface IPauseMenu : IControl
void FadeOut();
event PauseMenu.UnpauseButtonPressedEventHandler UnpauseButtonPressed;
event PauseMenu.TransitionCompletedEventHandler TransitionCompleted;
public event Action ExitGamePressed;
}
[Meta(typeof(IAutoNode))]
@@ -24,14 +27,32 @@ public partial class PauseMenu : Control, IPauseMenu
[Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!;
[Node] public Button ResumeButton { get; set; } = default!;
[Node] public Button ExitButton { get; set; } = default!;
public event Action ExitGamePressed;
public void OnResolved()
{
AnimationPlayer.AnimationFinished += OnAnimationFinished;
ResumeButton.Pressed += ResumeButton_Pressed;
ExitButton.Pressed += ExitButton_Pressed;
}
public void FadeIn() => AnimationPlayer.Play("fade_in");
private void ExitButton_Pressed() => ExitGamePressed?.Invoke();
private void ResumeButton_Pressed() => FadeOut();
public void FadeIn()
{
ResumeButton.GrabFocus();
AnimationPlayer.Play("fade_in");
}
public void FadeOut() => AnimationPlayer.Play("fade_out");
public void FadeOut()
{
ResumeButton.ReleaseFocus();
ExitButton.ReleaseFocus();
AnimationPlayer.Play("fade_out");
}
public override void _UnhandledInput(InputEvent @event)
{
@@ -41,5 +62,7 @@ public partial class PauseMenu : Control, IPauseMenu
public void OnAnimationFinished(StringName name)
{
if (name == "fade_out")
Hide();
}
}

View File

@@ -1,4 +1,9 @@
[gd_scene load_steps=5 format=3 uid="uid://blbqgw3wosc1w"]
[gd_scene load_steps=9 format=3 uid="uid://blbqgw3wosc1w"]
[ext_resource type="Script" uid="uid://cbal5oeaha4nx" path="res://src/ui/pause_menu/PauseMenu.cs" id="1_1mfd6"]
[ext_resource type="FontFile" uid="uid://beh6d5lo5ihq0" path="res://src/ui/fonts/georgiai.ttf" id="2_o1qdr"]
[ext_resource type="StyleBox" uid="uid://bxuy4tnftibfq" path="res://src/options/SelectedOptionsBox.tres" id="2_xhp56"]
[ext_resource type="StyleBox" uid="uid://bl15q835s4ene" path="res://src/options/UnselectedOptionsBox.tres" id="3_o1qdr"]
[sub_resource type="Animation" id="Animation_f1eqn"]
length = 0.001
@@ -62,6 +67,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_1mfd6")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true
@@ -77,3 +83,53 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0, 0, 0, 1)
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="ResumeButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_fonts/font = ExtResource("2_o1qdr")
theme_override_font_sizes/font_size = 38
theme_override_styles/focus = ExtResource("2_xhp56")
theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr")
theme_override_styles/disabled = ExtResource("3_o1qdr")
theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr")
theme_override_styles/hover_pressed = ExtResource("3_o1qdr")
theme_override_styles/hover_mirrored = ExtResource("3_o1qdr")
theme_override_styles/hover = ExtResource("3_o1qdr")
theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr")
theme_override_styles/pressed = ExtResource("3_o1qdr")
theme_override_styles/normal_mirrored = ExtResource("3_o1qdr")
theme_override_styles/normal = ExtResource("3_o1qdr")
text = "Resume"
flat = true
[node name="ExitButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_fonts/font = ExtResource("2_o1qdr")
theme_override_font_sizes/font_size = 38
theme_override_styles/focus = ExtResource("2_xhp56")
theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr")
theme_override_styles/disabled = ExtResource("3_o1qdr")
theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr")
theme_override_styles/hover_pressed = ExtResource("3_o1qdr")
theme_override_styles/hover_mirrored = ExtResource("3_o1qdr")
theme_override_styles/hover = ExtResource("3_o1qdr")
theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr")
theme_override_styles/pressed = ExtResource("3_o1qdr")
theme_override_styles/normal_mirrored = ExtResource("3_o1qdr")
theme_override_styles/normal = ExtResource("3_o1qdr")
text = "Exit Game"
flat = true