diff --git a/scripts/Resources/StatusEffectDataResource.cs b/scripts/Resources/StatusEffectDataResource.cs index 31ff410..3152115 100644 --- a/scripts/Resources/StatusEffectDataResource.cs +++ b/scripts/Resources/StatusEffectDataResource.cs @@ -4,5 +4,7 @@ namespace Mr.BrickAdventures.scripts.Resources; public partial class StatusEffectDataResource : Resource { + [Export] public float Duration { get; set; } = 1f; + [Export] public float DamagePerSecond { get; set; } = 0.25f; [Export] public StatusEffectType Type { get; set; } } \ No newline at end of file diff --git a/scripts/components/CanPickUpComponent.cs b/scripts/components/CanPickUpComponent.cs new file mode 100644 index 0000000..ca3fe8f --- /dev/null +++ b/scripts/components/CanPickUpComponent.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace Mr.BrickAdventures.scripts.components; + +public partial class CanPickUpComponent : Node +{ + +} \ No newline at end of file diff --git a/scripts/components/CollapsableComponent.cs b/scripts/components/CollapsableComponent.cs new file mode 100644 index 0000000..9afc5a7 --- /dev/null +++ b/scripts/components/CollapsableComponent.cs @@ -0,0 +1,81 @@ +using System.Threading.Tasks; +using Godot; + +namespace Mr.BrickAdventures.scripts.components; + +public partial class CollapsableComponent : Node +{ + [Export] public Timer ToCollapseTimer { get; set; } + [Export] public Timer ResetTimer { get; set; } + [Export] public Sprite2D Sprite2D { get; set; } + [Export] public CollisionShape2D CollisionShape { get; set; } + [Export] public float CollapseTime { get; set; } = 0.5f; + [Export] public float ResetTime { get; set; } = 0.5f; + [Export] public float AnimationTime { get; set; } = 0.25f; + + public override void _Ready() + { + ResetTimers(); + + ToCollapseTimer.Timeout += OnToCollapseTimerTimeout; + ResetTimer.Timeout += OnResetTimerTimeout; + } + + public void OnCollapsableDetectorBodyEntered(Node2D body) + { + ToCollapseTimer.Start(); + } + + public void OnCollapsableDetectorBodyExited(Node2D body) + { + var collapseTimeLeft = Mathf.Abs(ToCollapseTimer.TimeLeft - CollapseTime); + if (collapseTimeLeft < (0.1f * CollapseTime)) + { + ResetTimers(); + } + } + + private void OnToCollapseTimerTimeout() + { + _ = Collapse(); + } + + private void OnResetTimerTimeout() + { + _ = Reactivate(); + } + + private async Task Collapse() + { + ToCollapseTimer.Stop(); + ToCollapseTimer.SetWaitTime(CollapseTime); + + var tween = CreateTween(); + tween.TweenProperty(Sprite2D, "modulate:a", 0f, AnimationTime); + await ToSignal(tween, Tween.SignalName.Finished); + + CollisionShape?.CallDeferred("set_disabled", true); + ResetTimer.Start(); + } + + private async Task Reactivate() + { + ResetTimer.Stop(); + ResetTimer.SetWaitTime(ResetTime); + + var tween = CreateTween(); + tween.TweenProperty(Sprite2D, "modulate:a", 1f, AnimationTime); + await ToSignal(tween, Tween.SignalName.Finished); + + CollisionShape?.CallDeferred("set_disabled", false); + } + + private void ResetTimers() + { + ToCollapseTimer.Stop(); + ToCollapseTimer.SetWaitTime(CollapseTime); + + ResetTimer.Stop(); + ResetTimer.SetWaitTime(ResetTime); + } +} \ No newline at end of file diff --git a/scripts/components/DestroyableComponent.cs b/scripts/components/DestroyableComponent.cs new file mode 100644 index 0000000..abf2679 --- /dev/null +++ b/scripts/components/DestroyableComponent.cs @@ -0,0 +1,35 @@ +using Godot; + +namespace Mr.BrickAdventures.scripts.components; + +public partial class DestroyableComponent : Node2D +{ + [Export] public HealthComponent Health { get; set; } + [Export] public PackedScene DestroyEffect { get; set; } + + public override void _Ready() + { + if (Health == null) + { + GD.PushError("DestroyableComponent: HealthComponent is not set."); + return; + } + + Health.Death += OnHealthDeath; + } + + private void OnHealthDeath() + { + if (DestroyEffect == null) + { + Owner.QueueFree(); + return; + } + + var effect = DestroyEffect.Instantiate(); + Health.GetParent().AddChild(effect); + effect.SetGlobalPosition(Health.GlobalPosition); + Owner.QueueFree(); + } + +} \ No newline at end of file diff --git a/scripts/components/EffectInflictorComponent.cs b/scripts/components/EffectInflictorComponent.cs new file mode 100644 index 0000000..c741a04 --- /dev/null +++ b/scripts/components/EffectInflictorComponent.cs @@ -0,0 +1,27 @@ +using Godot; +using Mr.BrickAdventures.scripts.Resources; + +namespace Mr.BrickAdventures.scripts.components; + +public partial class EffectInflictorComponent : Node +{ + [Export] public DamageComponent Damage { get; set; } + + public override void _Ready() + { + if (Damage == null) + { + GD.PushError("EffectInflictorComponent requires a DamageComponent to be set."); + return; + } + + Damage.EffectInflicted += OnEffectInflicted; + } + + private void OnEffectInflicted(Node2D target, StatusEffectDataResource effect) + { + var statusEffect = target.GetNodeOrNull("StatusEffectComponent"); + + statusEffect?.ApplyEffect(effect); + } +} \ No newline at end of file diff --git a/scripts/components/HealthComponent.cs b/scripts/components/HealthComponent.cs index 2473807..34fddb3 100644 --- a/scripts/components/HealthComponent.cs +++ b/scripts/components/HealthComponent.cs @@ -3,7 +3,7 @@ using Godot; namespace Mr.BrickAdventures.scripts.components; -public partial class HealthComponent : Node +public partial class HealthComponent : Node2D { [Export] public float Health { get; set; } = 1.0f; [Export] public float MaxHealth { get; set; } = 1.0f; diff --git a/scripts/components/StatusEffectComponent.cs b/scripts/components/StatusEffectComponent.cs new file mode 100644 index 0000000..ebada8f --- /dev/null +++ b/scripts/components/StatusEffectComponent.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using Godot; +using Mr.BrickAdventures.scripts.Resources; + +namespace Mr.BrickAdventures.scripts.components; + +public partial class StatusEffect : GodotObject +{ + public StatusEffectDataResource EffectData { get; set; } + public float ElapsedTime { get; set; } + public Timer Timer { get; set; } +} + +public partial class StatusEffectComponent : Node +{ + private List _activeEffects = []; + + [Signal] public delegate void EffectAppliedEventHandler(StatusEffect statusEffect); + [Signal] public delegate void EffectRemovedEventHandler(StatusEffectType type); + + public void ApplyEffect(StatusEffectDataResource effectData) + { + var data = effectData.Duplicate() as StatusEffectDataResource; + var timer = CreateTimer(effectData.Duration, data); + + var statusEffect = new StatusEffect + { + EffectData = data, + ElapsedTime = 0f, + Timer = timer + }; + _activeEffects.Add(statusEffect); + EmitSignalEffectApplied(statusEffect); + } + + public void RemoveEffect(StatusEffectType type) + { + var effectToRemove = _activeEffects.Find(effect => effect.EffectData.Type == type); + if (effectToRemove.EffectData == null) return; + _activeEffects.Remove(effectToRemove); + effectToRemove.Timer.QueueFree(); + EmitSignalEffectRemoved(type); + } + + private Timer CreateTimer(float duration, StatusEffectDataResource effectData) + { + var timer = new Timer(); + timer.SetWaitTime(duration); + timer.SetOneShot(true); + timer.SetAutostart(true); + timer.Timeout += () => RemoveEffect(effectData.Type); + AddChild(timer); + return timer; + } +} \ No newline at end of file