diff --git a/BoundingBoxes/BoundingBox.cs b/BoundingBoxes/BoundingBox.cs
index cbd20cb..f1972ef 100644
--- a/BoundingBoxes/BoundingBox.cs
+++ b/BoundingBoxes/BoundingBox.cs
@@ -1,11 +1,10 @@
using Godot;
using SupaLidlGame.Utils;
-namespace SupaLidlGame.BoundingBoxes
+namespace SupaLidlGame.BoundingBoxes;
+
+public abstract partial class BoundingBox : Area2D, IFaction
{
- public abstract partial class BoundingBox : Area2D, IFaction
- {
- [Export]
- public ushort Faction { get; set; }
- }
+ [Export]
+ public ushort Faction { get; set; }
}
diff --git a/BoundingBoxes/ConnectorBox.cs b/BoundingBoxes/ConnectorBox.cs
index c855f62..e853b20 100644
--- a/BoundingBoxes/ConnectorBox.cs
+++ b/BoundingBoxes/ConnectorBox.cs
@@ -2,71 +2,70 @@ using Godot;
using System;
using SupaLidlGame.Characters;
-namespace SupaLidlGame.BoundingBoxes
+namespace SupaLidlGame.BoundingBoxes;
+
+public partial class ConnectorBox : Area2D
{
- public partial class ConnectorBox : Area2D
+ [Signal]
+ public delegate void RequestedEnterEventHandler(
+ ConnectorBox box,
+ Player player);
+
+ [Export]
+ public string ToArea { get; set; }
+
+ [Export]
+ public string ToConnector { get; set; }
+
+ [Export]
+ public string Identifier { get; set; }
+
+ ///
+ /// Determines if the connector requires the user to interact to enter
+ /// the connector
+ ///
+ [Export]
+ public bool RequiresInteraction { get; set; } = false;
+
+ [Export]
+ public CollisionShape2D Collision { get; set; }
+
+ private Player _player = null;
+
+ public override void _Ready()
{
- [Signal]
- public delegate void RequestedEnterEventHandler(
- ConnectorBox box,
- Player player);
-
- [Export]
- public string ToArea { get; set; }
-
- [Export]
- public string ToConnector { get; set; }
-
- [Export]
- public string Identifier { get; set; }
-
- ///
- /// Determines if the connector requires the user to interact to enter
- /// the connector
- ///
- [Export]
- public bool RequiresInteraction { get; set; } = false;
-
- [Export]
- public CollisionShape2D Collision { get; set; }
-
- private Player _player = null;
-
- public override void _Ready()
+ if (Collision is null)
{
- if (Collision is null)
- {
- throw new NullReferenceException("Collision not specified");
- }
-
- BodyEntered += (Node2D body) =>
- {
- if (body is Player player)
- {
- _player = player;
- }
- };
-
- BodyExited += (Node2D body) =>
- {
- if (body is Player)
- {
- _player = null;
- }
- };
+ throw new NullReferenceException("Collision not specified");
}
- public override void _Process(double delta)
+ BodyEntered += (Node2D body) =>
{
- if (Input.IsActionJustReleased("interact"))
+ if (body is Player player)
{
- if (_player is not null)
- {
- EmitSignal(SignalName.RequestedEnter, this, _player);
- }
+ _player = player;
}
+ };
- base._Process(delta);
+ BodyExited += (Node2D body) =>
+ {
+ if (body is Player)
+ {
+ _player = null;
+ }
+ };
+ }
+
+ public override void _Process(double delta)
+ {
+ if (Input.IsActionJustReleased("interact"))
+ {
+ if (_player is not null)
+ {
+ EmitSignal(SignalName.RequestedEnter, this, _player);
+ }
}
+
+ base._Process(delta);
}
}
diff --git a/BoundingBoxes/Hitbox.cs b/BoundingBoxes/Hitbox.cs
index b7950ae..bbe1365 100644
--- a/BoundingBoxes/Hitbox.cs
+++ b/BoundingBoxes/Hitbox.cs
@@ -3,103 +3,102 @@ using Godot;
using SupaLidlGame.Characters;
using SupaLidlGame.Items;
-namespace SupaLidlGame.BoundingBoxes
+namespace SupaLidlGame.BoundingBoxes;
+
+public partial class Hitbox : BoundingBox
{
- public partial class Hitbox : BoundingBox
+ private HashSet _ignoreList = new HashSet();
+
+ [Signal]
+ public delegate void HitEventHandler(BoundingBox box);
+
+ [Export]
+ public float Damage { get; set; }
+
+ private bool _isDisabled = false;
+
+ ///
+ /// Getter/setter for the CollisionShape2D's Disabled property.
+ ///
+ [Export]
+ public bool IsDisabled
{
- private HashSet _ignoreList = new HashSet();
-
- [Signal]
- public delegate void HitEventHandler(BoundingBox box);
-
- [Export]
- public float Damage { get; set; }
-
- private bool _isDisabled = false;
-
- ///
- /// Getter/setter for the CollisionShape2D's Disabled property.
- ///
- [Export]
- public bool IsDisabled
+ get => _collisionShape.Disabled;
+ set
{
- get => _collisionShape.Disabled;
- set
+ _isDisabled = value;
+ if (_collisionShape is not null)
{
- _isDisabled = value;
- if (_collisionShape is not null)
+ _collisionShape.Disabled = value;
+ if (value)
{
- _collisionShape.Disabled = value;
- if (value)
- {
- DamageStartTime = Time.GetTicksMsec();
- }
+ DamageStartTime = Time.GetTicksMsec();
}
}
}
+ }
- [Export]
- public float Knockback { get; set; }
+ [Export]
+ public float Knockback { get; set; }
- public Character Inflictor { get; set; }
+ public Character Inflictor { get; set; }
- public ulong DamageStartTime { get; set; }
+ public ulong DamageStartTime { get; set; }
- private CollisionShape2D _collisionShape;
+ private CollisionShape2D _collisionShape;
- private bool _isParrying = false;
+ private bool _isParrying = false;
- public override void _Ready()
+ public override void _Ready()
+ {
+ _collisionShape = GetNode("CollisionShape2D");
+ IsDisabled = _isDisabled; // sets _collisionShape.Disabled
+ }
+
+ private bool ShouldParry(Hitbox box)
+ {
+ Node parent = GetParent();
+
+ // if this hitbox does not even belong to a weapon, skip
+ if (parent is not Weapon)
{
- _collisionShape = GetNode("CollisionShape2D");
- IsDisabled = _isDisabled; // sets _collisionShape.Disabled
- }
-
- private bool ShouldParry(Hitbox box)
- {
- Node parent = GetParent();
-
- // if this hitbox does not even belong to a weapon, skip
- if (parent is not Weapon)
- {
- return false;
- }
-
- var weapon = parent as Weapon;
-
- // if we hit a hitbox, we can parry if it can be parried
- if (box.GetParent() is Weapon other)
- {
- return weapon.IsParryable && other.IsParryable;
- }
-
return false;
}
- public void _on_area_entered(Area2D area)
+ var weapon = parent as Weapon;
+
+ // if we hit a hitbox, we can parry if it can be parried
+ if (box.GetParent() is Weapon other)
{
- if (area is BoundingBox box)
+ return weapon.IsParryable && other.IsParryable;
+ }
+
+ return false;
+ }
+
+ public void _on_area_entered(Area2D area)
+ {
+ if (area is BoundingBox box)
+ {
+ GD.Print("hit");
+ // we don't want to hurt teammates
+ if (Faction != box.Faction)
{
- GD.Print("hit");
- // we don't want to hurt teammates
- if (Faction != box.Faction)
+ if (!_ignoreList.Contains(box))
{
- if (!_ignoreList.Contains(box))
- {
- _ignoreList.Add(box);
- EmitSignal(SignalName.Hit, box);
- }
+ _ignoreList.Add(box);
+ EmitSignal(SignalName.Hit, box);
}
}
}
+ }
- public void ResetIgnoreList() => _ignoreList.Clear();
+ public void ResetIgnoreList() => _ignoreList.Clear();
- public bool HasHit(BoundingBox box) => _ignoreList.Contains(box);
+ public bool HasHit(BoundingBox box) => _ignoreList.Contains(box);
- public HashSet Hits
- {
- get => _ignoreList;
- }
+ public HashSet Hits
+ {
+ get => _ignoreList;
}
}
diff --git a/BoundingBoxes/Hurtbox.cs b/BoundingBoxes/Hurtbox.cs
index fc01ec7..ca36c51 100644
--- a/BoundingBoxes/Hurtbox.cs
+++ b/BoundingBoxes/Hurtbox.cs
@@ -2,39 +2,38 @@ using Godot;
using SupaLidlGame.Characters;
using SupaLidlGame.Utils;
-namespace SupaLidlGame.BoundingBoxes
+namespace SupaLidlGame.BoundingBoxes;
+
+public partial class Hurtbox : BoundingBox, IFaction
{
- public partial class Hurtbox : BoundingBox, IFaction
+ [Signal]
+ public delegate void ReceivedDamageEventHandler(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackOrigin = default,
+ Vector2 knockbackVector = default);
+
+ public override void _Ready()
{
- [Signal]
- public delegate void ReceivedDamageEventHandler(
- float damage,
- Character inflictor,
- float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default);
-
- public override void _Ready()
+ if (GetParent() is IFaction factionEntity)
{
- if (GetParent() is IFaction factionEntity)
- {
- Faction = factionEntity.Faction;
- }
- }
-
- public void InflictDamage(
- float damage,
- Character inflictor,
- float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default)
- {
- EmitSignal(
- SignalName.ReceivedDamage,
- damage,
- inflictor,
- knockback,
- knockbackOrigin, knockbackVector);
+ Faction = factionEntity.Faction;
}
}
+
+ public void InflictDamage(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackOrigin = default,
+ Vector2 knockbackVector = default)
+ {
+ EmitSignal(
+ SignalName.ReceivedDamage,
+ damage,
+ inflictor,
+ knockback,
+ knockbackOrigin, knockbackVector);
+ }
}
diff --git a/Characters/Character.cs b/Characters/Character.cs
index a21c4b8..74fdbe6 100644
--- a/Characters/Character.cs
+++ b/Characters/Character.cs
@@ -4,221 +4,220 @@ using SupaLidlGame.Items;
using SupaLidlGame.Utils;
using SupaLidlGame.State.Character;
-namespace SupaLidlGame.Characters
+namespace SupaLidlGame.Characters;
+
+public partial class Character : CharacterBody2D, IFaction
{
- public partial class Character : CharacterBody2D, IFaction
+ [Export]
+ public float Speed { get; protected set; } = 32.0f;
+
+ [Export]
+ public float Friction { get; protected set; } = 4.0f;
+
+ [Export]
+ public float Mass
{
- [Export]
- public float Speed { get; protected set; } = 32.0f;
-
- [Export]
- public float Friction { get; protected set; } = 4.0f;
-
- [Export]
- public float Mass
+ get => _mass;
+ set
{
- get => _mass;
- set
+ if (value > 0)
+ _mass = value;
+ }
+ }
+
+ protected float _mass = 1.0f;
+
+ public Vector2 NetImpulse { get; set; } = Vector2.Zero;
+
+ public Vector2 Direction { get; set; } = Vector2.Zero;
+
+ public Vector2 Target { get; set; } = Vector2.Zero;
+
+ [Export]
+ public float Health
+ {
+ get => _health;
+ set
+ {
+ if (!IsAlive && value < 0)
{
- if (value > 0)
- _mass = value;
- }
- }
-
- protected float _mass = 1.0f;
-
- public Vector2 NetImpulse { get; set; } = Vector2.Zero;
-
- public Vector2 Direction { get; set; } = Vector2.Zero;
-
- public Vector2 Target { get; set; } = Vector2.Zero;
-
- [Export]
- public float Health
- {
- get => _health;
- set
- {
- if (!IsAlive && value < 0)
- {
- return;
- }
-
- _health = value;
- if (_health <= 0)
- {
- Die();
- }
- }
- }
-
- public bool IsAlive => Health > 0;
-
- protected float _health = 100f;
-
- public double StunTime { get; set; }
-
- [Export]
- public AnimatedSprite2D Sprite { get; set; }
-
- [Export]
- public Inventory Inventory { get; set; }
-
- [Export]
- public CharacterStateMachine StateMachine { get; set; }
-
- [Export]
- public ushort Faction { get; set; }
-
- public override void _Process(double delta)
- {
- if (StateMachine != null)
- {
- StateMachine.Process(delta);
- }
-
- Sprite.FlipH = Target.X < 0;
- DrawTarget();
- }
-
- public override void _Input(InputEvent @event)
- {
- if (StateMachine != null)
- {
- StateMachine.Input(@event);
- }
- }
-
- public override void _PhysicsProcess(double delta)
- {
- if (StateMachine != null)
- {
- StateMachine.PhysicsProcess(delta);
- }
- }
-
- ///
- /// Modify the Character's velocity
- ///
- public virtual void ModifyVelocity()
- {
- if (StunTime > 0)
- {
- Velocity *= 0.25f;
- }
- }
-
- public virtual void Die()
- {
- GD.Print("lol died");
- QueueFree();
- }
-
- public void ApplyImpulse(Vector2 impulse, bool resetVelocity = false)
- {
- // delta p = F delta t
- if (resetVelocity)
- Velocity = Vector2.Zero;
- NetImpulse += impulse / Mass;
- }
-
- public virtual void Stun(float time)
- {
- StunTime += time;
- }
-
- protected void DrawTarget()
- {
- Vector2 target = Target;
- float angle = Mathf.Atan2(target.Y, Mathf.Abs(target.X));
- Vector2 scale = Inventory.Scale;
- if (target.X < 0)
- {
- scale.Y = -1;
- angle = Mathf.Pi - angle;
- }
- else
- {
- scale.Y = 1;
- }
- Inventory.Scale = scale;
- Inventory.Rotation = angle;
- }
-
- public void UseCurrentItem()
- {
- if (StunTime > 0)
- {
- GD.Print("tried to use weapon but stunned");
return;
}
- if (Inventory.SelectedItem is Weapon weapon)
+ _health = value;
+ if (_health <= 0)
{
- weapon.Use();
- }
- }
-
- public void LookTowardsDirection()
- {
- if (!Direction.IsZeroApprox())
- {
- Target = Direction;
- }
- }
-
- public virtual void _on_hurtbox_received_damage(
- float damage,
- Character inflictor,
- float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default)
- {
- Health -= damage;
-
- // create damage text
- var textScene = GD.Load("res://UI/FloatingText.tscn");
- var instance = textScene.Instantiate();
- instance.Text = Mathf.Round(damage).ToString();
- instance.GlobalPosition = GlobalPosition;
- this.GetAncestor().AddChild(instance);
-
- // apply knockback
- Vector2 knockbackDir = knockbackVector;
- if (knockbackDir == default)
- {
- if (knockbackOrigin == default)
- {
- knockbackOrigin = inflictor.GlobalPosition;
- }
-
- knockbackDir = knockbackOrigin.DirectionTo(GlobalPosition);
- }
-
- ApplyImpulse(knockbackDir.Normalized() * knockback);
-
- GD.Print("lol");
-
- // play damage animation
- var anim = GetNode("FlashAnimation");
- if (anim != null)
- {
- anim.Stop();
- anim.Play("Hurt");
- }
-
- // if anyone involved is a player, shake their screen
- Player plr = inflictor as Player ?? this as Player;
- if (plr is not null)
- {
- plr.Camera.Shake(1, 0.4f);
- }
-
- if (this.GetNode("HurtSound") is AudioStreamPlayer2D sound)
- {
- // very small pitch deviation
- sound.At(GlobalPosition).WithPitchDeviation(0.125f).Play();
+ Die();
}
}
}
+
+ public bool IsAlive => Health > 0;
+
+ protected float _health = 100f;
+
+ public double StunTime { get; set; }
+
+ [Export]
+ public AnimatedSprite2D Sprite { get; set; }
+
+ [Export]
+ public Inventory Inventory { get; set; }
+
+ [Export]
+ public CharacterStateMachine StateMachine { get; set; }
+
+ [Export]
+ public ushort Faction { get; set; }
+
+ public override void _Process(double delta)
+ {
+ if (StateMachine != null)
+ {
+ StateMachine.Process(delta);
+ }
+
+ Sprite.FlipH = Target.X < 0;
+ DrawTarget();
+ }
+
+ public override void _Input(InputEvent @event)
+ {
+ if (StateMachine != null)
+ {
+ StateMachine.Input(@event);
+ }
+ }
+
+ public override void _PhysicsProcess(double delta)
+ {
+ if (StateMachine != null)
+ {
+ StateMachine.PhysicsProcess(delta);
+ }
+ }
+
+ ///
+ /// Modify the Character's velocity
+ ///
+ public virtual void ModifyVelocity()
+ {
+ if (StunTime > 0)
+ {
+ Velocity *= 0.25f;
+ }
+ }
+
+ public virtual void Die()
+ {
+ GD.Print("lol died");
+ QueueFree();
+ }
+
+ public void ApplyImpulse(Vector2 impulse, bool resetVelocity = false)
+ {
+ // delta p = F delta t
+ if (resetVelocity)
+ Velocity = Vector2.Zero;
+ NetImpulse += impulse / Mass;
+ }
+
+ public virtual void Stun(float time)
+ {
+ StunTime += time;
+ }
+
+ protected void DrawTarget()
+ {
+ Vector2 target = Target;
+ float angle = Mathf.Atan2(target.Y, Mathf.Abs(target.X));
+ Vector2 scale = Inventory.Scale;
+ if (target.X < 0)
+ {
+ scale.Y = -1;
+ angle = Mathf.Pi - angle;
+ }
+ else
+ {
+ scale.Y = 1;
+ }
+ Inventory.Scale = scale;
+ Inventory.Rotation = angle;
+ }
+
+ public void UseCurrentItem()
+ {
+ if (StunTime > 0)
+ {
+ GD.Print("tried to use weapon but stunned");
+ return;
+ }
+
+ if (Inventory.SelectedItem is Weapon weapon)
+ {
+ weapon.Use();
+ }
+ }
+
+ public void LookTowardsDirection()
+ {
+ if (!Direction.IsZeroApprox())
+ {
+ Target = Direction;
+ }
+ }
+
+ public virtual void _on_hurtbox_received_damage(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackOrigin = default,
+ Vector2 knockbackVector = default)
+ {
+ Health -= damage;
+
+ // create damage text
+ var textScene = GD.Load("res://UI/FloatingText.tscn");
+ var instance = textScene.Instantiate();
+ instance.Text = Mathf.Round(damage).ToString();
+ instance.GlobalPosition = GlobalPosition;
+ this.GetAncestor().AddChild(instance);
+
+ // apply knockback
+ Vector2 knockbackDir = knockbackVector;
+ if (knockbackDir == default)
+ {
+ if (knockbackOrigin == default)
+ {
+ knockbackOrigin = inflictor.GlobalPosition;
+ }
+
+ knockbackDir = knockbackOrigin.DirectionTo(GlobalPosition);
+ }
+
+ ApplyImpulse(knockbackDir.Normalized() * knockback);
+
+ GD.Print("lol");
+
+ // play damage animation
+ var anim = GetNode("FlashAnimation");
+ if (anim != null)
+ {
+ anim.Stop();
+ anim.Play("Hurt");
+ }
+
+ // if anyone involved is a player, shake their screen
+ Player plr = inflictor as Player ?? this as Player;
+ if (plr is not null)
+ {
+ plr.Camera.Shake(1, 0.4f);
+ }
+
+ if (this.GetNode("HurtSound") is AudioStreamPlayer2D sound)
+ {
+ // very small pitch deviation
+ sound.At(GlobalPosition).WithPitchDeviation(0.125f).Play();
+ }
+ }
}
diff --git a/Characters/Enemy.cs b/Characters/Enemy.cs
index b33b6e1..4d5b335 100644
--- a/Characters/Enemy.cs
+++ b/Characters/Enemy.cs
@@ -1,19 +1,18 @@
using Godot;
using System;
-namespace SupaLidlGame.Characters
-{
- public partial class Enemy : NPC
- {
- public override void _Ready()
- {
- Inventory.SelectedItem = Inventory.GetNode("Sword");
- base._Ready();
- }
+namespace SupaLidlGame.Characters;
- public override void Die()
- {
- base.Die();
- }
+public partial class Enemy : NPC
+{
+ public override void _Ready()
+ {
+ Inventory.SelectedItem = Inventory.GetNode("Sword");
+ base._Ready();
+ }
+
+ public override void Die()
+ {
+ base.Die();
}
}
diff --git a/Characters/NPC.cs b/Characters/NPC.cs
index a834f9d..1e34d27 100644
--- a/Characters/NPC.cs
+++ b/Characters/NPC.cs
@@ -3,225 +3,224 @@ using SupaLidlGame.Extensions;
using SupaLidlGame.Items;
using System;
-namespace SupaLidlGame.Characters
+namespace SupaLidlGame.Characters;
+
+public partial class NPC : Character
{
- public partial class NPC : Character
+ ///
+ /// Time in seconds it takes for the NPC to think FeelsDankCube
+ ///
+ public const float ThinkTime = 0.125f;
+
+ public float[] Weights => _weights;
+
+ protected float _preferredWeightDistance = 64.0f;
+ protected float _maxWeightDistance = 8.0f;
+ protected float _preferredWeightDistanceSq = 4096.0f;
+ protected float _maxWeightDistanceSq = 64.0f;
+
+ [Export]
+ public float PreferredWeightDistance
+ {
+ get => _preferredWeightDistance;
+ protected set
+ {
+ _preferredWeightDistance = value;
+ _preferredWeightDistanceSq = value * value;
+ }
+ }
+
+ [Export]
+ public float MaxWeightDistance
+ {
+ get => _maxWeightDistance;
+ protected set
+ {
+ _maxWeightDistance = value;
+ _maxWeightDistanceSq = value * value;
+ }
+ }
+
+ protected float[] _weights = new float[16];
+ protected int _bestWeightIdx;
+ protected double _thinkTimeElapsed = 0;
+ protected Vector2 _blockingDir;
+ protected static readonly Vector2[] _weightDirs = new Vector2[16];
+
+ static NPC()
{
- ///
- /// Time in seconds it takes for the NPC to think FeelsDankCube
- ///
- public const float ThinkTime = 0.125f;
-
- public float[] Weights => _weights;
-
- protected float _preferredWeightDistance = 64.0f;
- protected float _maxWeightDistance = 8.0f;
- protected float _preferredWeightDistanceSq = 4096.0f;
- protected float _maxWeightDistanceSq = 64.0f;
-
- [Export]
- public float PreferredWeightDistance
- {
- get => _preferredWeightDistance;
- protected set
- {
- _preferredWeightDistance = value;
- _preferredWeightDistanceSq = value * value;
- }
- }
-
- [Export]
- public float MaxWeightDistance
- {
- get => _maxWeightDistance;
- protected set
- {
- _maxWeightDistance = value;
- _maxWeightDistanceSq = value * value;
- }
- }
-
- protected float[] _weights = new float[16];
- protected int _bestWeightIdx;
- protected double _thinkTimeElapsed = 0;
- protected Vector2 _blockingDir;
- protected static readonly Vector2[] _weightDirs = new Vector2[16];
-
- static NPC()
+ for (int i = 0; i < 16; i++)
{
- for (int i = 0; i < 16; i++)
- {
- float y = Mathf.Sin(Mathf.Pi * i * 2 / 16);
- float x = Mathf.Cos(Mathf.Pi * i * 2 / 16);
- _weightDirs[i] = new Vector2(x, y);
- }
+ float y = Mathf.Sin(Mathf.Pi * i * 2 / 16);
+ float x = Mathf.Cos(Mathf.Pi * i * 2 / 16);
+ _weightDirs[i] = new Vector2(x, y);
}
+ }
- public override void _Ready()
- {
- base._Ready();
- Array.Fill(_weights, 0);
- }
+ public override void _Ready()
+ {
+ base._Ready();
+ Array.Fill(_weights, 0);
+ }
- public override void _Draw()
- {
+ public override void _Draw()
+ {
#if DEBUG
- for (int i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++)
+ {
+ Vector2 vec = _weightDirs[i] * _weights[i] * 32;
+ Color c = Colors.Green;
+ if (_bestWeightIdx == i)
{
- Vector2 vec = _weightDirs[i] * _weights[i] * 32;
- Color c = Colors.Green;
- if (_bestWeightIdx == i)
- {
- c = Colors.Blue;
- }
- else if (_weights[i] < 0)
- {
- c = Colors.Red;
- vec = -vec;
- }
- DrawLine(Vector2.Zero, vec, c);
+ c = Colors.Blue;
}
+ else if (_weights[i] < 0)
+ {
+ c = Colors.Red;
+ vec = -vec;
+ }
+ DrawLine(Vector2.Zero, vec, c);
+ }
#endif
- base._Draw();
- }
+ base._Draw();
+ }
- protected virtual Character FindBestTarget()
+ protected virtual Character FindBestTarget()
+ {
+ float bestDist = float.MaxValue;
+ Character bestChar = null;
+ foreach (Node node in GetParent().GetChildren())
{
- float bestDist = float.MaxValue;
- Character bestChar = null;
- foreach (Node node in GetParent().GetChildren())
+ if (node is Character character && character.Faction != Faction)
{
- if (node is Character character && character.Faction != Faction)
+ float dist = Position.DistanceTo(character.Position);
+ if (dist < bestDist)
{
- float dist = Position.DistanceTo(character.Position);
- if (dist < bestDist)
- {
- bestDist = dist;
- bestChar = character;
- }
+ bestDist = dist;
+ bestChar = character;
}
}
- return bestChar;
}
+ return bestChar;
+ }
- public void ThinkProcess(double delta)
+ public void ThinkProcess(double delta)
+ {
+ if ((_thinkTimeElapsed += delta) > ThinkTime)
{
- if ((_thinkTimeElapsed += delta) > ThinkTime)
- {
- _thinkTimeElapsed = 0;
- Think();
+ _thinkTimeElapsed = 0;
+ Think();
#if DEBUG
- QueueRedraw();
+ QueueRedraw();
#endif
- }
-
- Direction = _weightDirs[_bestWeightIdx];
}
- public void UpdateWeights(Vector2 pos)
+ Direction = _weightDirs[_bestWeightIdx];
+ }
+
+ public void UpdateWeights(Vector2 pos)
+ {
+ // FIXME: TODO: remove all the spaghetti
+ Vector2 dir = Target.Normalized();
+ float distSq = GlobalPosition.DistanceSquaredTo(pos);
+
+ var spaceState = GetWorld2D().DirectSpaceState;
+ var exclude = new Godot.Collections.Array();
+ exclude.Add(this.GetRid());
+
+ // calculate weights based on distance
+ for (int i = 0; i < 16; i++)
{
- // FIXME: TODO: remove all the spaghetti
- Vector2 dir = Target.Normalized();
- float distSq = GlobalPosition.DistanceSquaredTo(pos);
+ float directDot = _weightDirs[i].Dot(dir);
+ // clamp dot from [-1, 1] to [0, 1]
+ directDot = (directDot + 1) / 2;
- var spaceState = GetWorld2D().DirectSpaceState;
- var exclude = new Godot.Collections.Array();
- exclude.Add(this.GetRid());
+ float strafeDot = Math.Abs(_weightDirs[i].Dot(dir.Clockwise90()));
+ float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16;
+ strafeDot = Mathf.Pow((strafeDot + 1) / 2, 2) + currDirDot;
- // calculate weights based on distance
- for (int i = 0; i < 16; i++)
+ // favor strafing when getting closer
+ if (distSq > _preferredWeightDistanceSq)
{
- float directDot = _weightDirs[i].Dot(dir);
- // clamp dot from [-1, 1] to [0, 1]
- directDot = (directDot + 1) / 2;
-
- float strafeDot = Math.Abs(_weightDirs[i].Dot(dir.Clockwise90()));
- float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16;
- strafeDot = Mathf.Pow((strafeDot + 1) / 2, 2) + currDirDot;
-
- // favor strafing when getting closer
- if (distSq > _preferredWeightDistanceSq)
- {
- _weights[i] = directDot;
- }
- else if (distSq > _maxWeightDistanceSq)
- {
- float dDotWeight = Mathf.Sqrt(distSq / 4096);
- float sDotWeight = 1 - dDotWeight;
- _weights[i] = (dDotWeight * directDot) +
- (sDotWeight * strafeDot);
- }
- else
- {
- _weights[i] = strafeDot;
- }
+ _weights[i] = directDot;
}
-
- // subtract weights that collide
- for (int i = 0; i < 16; i++)
+ else if (distSq > _maxWeightDistanceSq)
{
- var rayParams = new PhysicsRayQueryParameters2D
- {
- Exclude = exclude,
- CollideWithBodies = true,
- From = GlobalPosition,
- To = GlobalPosition + (_weightDirs[i] * 24),
- CollisionMask = 1 + 2 + 16
- };
+ float dDotWeight = Mathf.Sqrt(distSq / 4096);
+ float sDotWeight = 1 - dDotWeight;
+ _weights[i] = (dDotWeight * directDot) +
+ (sDotWeight * strafeDot);
+ }
+ else
+ {
+ _weights[i] = strafeDot;
+ }
+ }
- var result = spaceState.IntersectRay(rayParams);
+ // subtract weights that collide
+ for (int i = 0; i < 16; i++)
+ {
+ var rayParams = new PhysicsRayQueryParameters2D
+ {
+ Exclude = exclude,
+ CollideWithBodies = true,
+ From = GlobalPosition,
+ To = GlobalPosition + (_weightDirs[i] * 24),
+ CollisionMask = 1 + 2 + 16
+ };
- // if we hit something
- if (result.Count > 0)
+ var result = spaceState.IntersectRay(rayParams);
+
+ // if we hit something
+ if (result.Count > 0)
+ {
+ // then we subtract the value of this from the other weights
+ float oldWeight = _weights[i];
+ for (int j = 0; j < 16; j++)
{
- // then we subtract the value of this from the other weights
- float oldWeight = _weights[i];
- for (int j = 0; j < 16; j++)
+ if (i == j)
{
- if (i == j)
- {
- _weights[i] = 0;
- }
- else
- {
- float dot = _weightDirs[i].Dot(_weightDirs[j]);
- _weights[j] -= _weights[j] * dot;
- }
+ _weights[i] = 0;
+ }
+ else
+ {
+ float dot = _weightDirs[i].Dot(_weightDirs[j]);
+ _weights[j] -= _weights[j] * dot;
}
- }
- }
-
-
- float bestWeight = 0;
- for (int i = 0; i < 16; i++)
- {
- if (_weights[i] > bestWeight)
- {
- _bestWeightIdx = i;
- bestWeight = _weights[i];
}
}
}
- protected virtual void Think()
- {
- // TODO: the entity should wander if it doesn't find a best target
- Character bestTarget = FindBestTarget();
- if (bestTarget is not null)
- {
- Vector2 pos = FindBestTarget().GlobalPosition;
- Target = pos - GlobalPosition;
- Vector2 dir = Target;
- float dist = GlobalPosition.DistanceSquaredTo(pos);
- UpdateWeights(pos);
- if (dist < 1024)
+ float bestWeight = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (_weights[i] > bestWeight)
+ {
+ _bestWeightIdx = i;
+ bestWeight = _weights[i];
+ }
+ }
+ }
+
+ protected virtual void Think()
+ {
+ // TODO: the entity should wander if it doesn't find a best target
+ Character bestTarget = FindBestTarget();
+ if (bestTarget is not null)
+ {
+ Vector2 pos = FindBestTarget().GlobalPosition;
+ Target = pos - GlobalPosition;
+ Vector2 dir = Target;
+ float dist = GlobalPosition.DistanceSquaredTo(pos);
+ UpdateWeights(pos);
+
+ if (dist < 1024)
+ {
+ if (Inventory.SelectedItem is Weapon weapon)
{
- if (Inventory.SelectedItem is Weapon weapon)
- {
- UseCurrentItem();
- }
+ UseCurrentItem();
}
}
}
diff --git a/Characters/Player.cs b/Characters/Player.cs
index 71a1906..755fbab 100644
--- a/Characters/Player.cs
+++ b/Characters/Player.cs
@@ -1,65 +1,64 @@
using Godot;
using SupaLidlGame.Utils;
-namespace SupaLidlGame.Characters
+namespace SupaLidlGame.Characters;
+
+public partial class Player : Character
{
- public partial class Player : Character
+ private AnimatedSprite2D _sprite;
+ private string _spriteAnim;
+
+ [Export]
+ public PlayerCamera Camera { get; set; }
+
+ public string Animation
{
- private AnimatedSprite2D _sprite;
- private string _spriteAnim;
-
- [Export]
- public PlayerCamera Camera { get; set; }
-
- public string Animation
+ get => _sprite.Animation;
+ set
{
- get => _sprite.Animation;
- set
+ // the Player.Animation property might be set before this node is
+ // even ready, so if _sprite is null, then we just hold the new
+ // animation in a temp value, which will be assigned once this node
+ // is ready
+ if (_sprite is null)
{
- // the Player.Animation property might be set before this node is
- // even ready, so if _sprite is null, then we just hold the new
- // animation in a temp value, which will be assigned once this
- // node is ready
- if (_sprite is null)
- {
- _spriteAnim = value;
- return;
- }
-
- _sprite.Play(value);
- }
- }
-
- public override void _Ready()
- {
- _sprite = GetNode("Sprite");
- if (_spriteAnim != default)
- {
- _sprite.Animation = _spriteAnim;
- }
- }
-
- public override void ModifyVelocity()
- {
- if (StateMachine.CurrentState is SupaLidlGame.State.Character.PlayerRollState)
- {
- Velocity *= 2;
+ _spriteAnim = value;
+ return;
}
- base.ModifyVelocity();
- }
-
- public override void Stun(float time)
- {
- base.Stun(time);
- Camera.Shake(2, 0.8f);
- // TODO: implement visual effects for stun
- }
-
- public override void Die()
- {
- GD.Print("died");
- //base.Die();
+ _sprite.Play(value);
}
}
+
+ public override void _Ready()
+ {
+ _sprite = GetNode("Sprite");
+ if (_spriteAnim != default)
+ {
+ _sprite.Animation = _spriteAnim;
+ }
+ }
+
+ public override void ModifyVelocity()
+ {
+ if (StateMachine.CurrentState is SupaLidlGame.State.Character.PlayerRollState)
+ {
+ Velocity *= 2;
+ }
+
+ base.ModifyVelocity();
+ }
+
+ public override void Stun(float time)
+ {
+ base.Stun(time);
+ Camera.Shake(2, 0.8f);
+ // TODO: implement visual effects for stun
+ }
+
+ public override void Die()
+ {
+ GD.Print("died");
+ //base.Die();
+ }
}
diff --git a/Characters/Thinkers/Thinker.cs b/Characters/Thinkers/Thinker.cs
index fc0d812..ea27d1c 100644
--- a/Characters/Thinkers/Thinker.cs
+++ b/Characters/Thinkers/Thinker.cs
@@ -1,10 +1,9 @@
-namespace SupaLidlGame.Characters.Thinkers
-{
- public class Thinker
- {
- public virtual void Think()
- {
+namespace SupaLidlGame.Characters.Thinkers;
+
+public class Thinker
+{
+ public virtual void Think()
+ {
- }
}
}
diff --git a/Entities/Campfire.cs b/Entities/Campfire.cs
index 5fae800..5572dbb 100644
--- a/Entities/Campfire.cs
+++ b/Entities/Campfire.cs
@@ -1,24 +1,23 @@
using Godot;
using System;
-namespace SupaLidlGame.Entities
+namespace SupaLidlGame.Entities;
+
+public partial class Campfire : StaticBody2D
{
- public partial class Campfire : StaticBody2D
+ private PointLight2D _light;
+
+ [Signal]
+ public delegate void OnCampfireUseEventHandler();
+
+ public override void _Ready()
{
- private PointLight2D _light;
+ _light = GetNode("PointLight2D");
+ }
- [Signal]
- public delegate void OnCampfireUseEventHandler();
-
- public override void _Ready()
- {
- _light = GetNode("PointLight2D");
- }
-
- public override void _Process(double delta)
- {
- _light.Energy += (GD.Randf() - 0.5f) * 8 * (float)delta;
- _light.Energy = Math.Clamp(_light.Energy, 1.2f, 2.0f);
- }
+ public override void _Process(double delta)
+ {
+ _light.Energy += (GD.Randf() - 0.5f) * 8 * (float)delta;
+ _light.Energy = Math.Clamp(_light.Energy, 1.2f, 2.0f);
}
}
diff --git a/Entities/Projectile.cs b/Entities/Projectile.cs
index 8e157c8..06c1f71 100644
--- a/Entities/Projectile.cs
+++ b/Entities/Projectile.cs
@@ -2,51 +2,50 @@ using Godot;
using SupaLidlGame.Characters;
using SupaLidlGame.BoundingBoxes;
-namespace SupaLidlGame.Entities
+namespace SupaLidlGame.Entities;
+
+public partial class Projectile : RigidBody2D
{
- public partial class Projectile : RigidBody2D
+ public Vector2 Velocity => Direction * Speed;
+
+ [Export]
+ public float Speed { get; set; }
+
+ [Export]
+ public Vector2 Direction { get; set; }
+
+ [Export]
+ public Hitbox Hitbox { get; set; }
+
+ [Export]
+ public double Lifetime { get; set; } = 10;
+
+ public Character Character { get; set; }
+
+ public override void _Process(double delta)
{
- public Vector2 Velocity => Direction * Speed;
-
- [Export]
- public float Speed { get; set; }
-
- [Export]
- public Vector2 Direction { get; set; }
-
- [Export]
- public Hitbox Hitbox { get; set; }
-
- [Export]
- public double Lifetime { get; set; } = 10;
-
- public Character Character { get; set; }
-
- public override void _Process(double delta)
+ if ((Lifetime -= delta) <= 0)
{
- if ((Lifetime -= delta) <= 0)
- {
- QueueFree();
- }
+ QueueFree();
}
+ }
- public override void _PhysicsProcess(double delta)
- {
- Vector2 velocity = Velocity;
- MoveAndCollide(velocity * (float)delta);
- }
+ public override void _PhysicsProcess(double delta)
+ {
+ Vector2 velocity = Velocity;
+ MoveAndCollide(velocity * (float)delta);
+ }
- public void _on_hitbox_hit(BoundingBox box)
+ public void _on_hitbox_hit(BoundingBox box)
+ {
+ if (box is Hurtbox hurtbox)
{
- if (box is Hurtbox hurtbox)
- {
- hurtbox.InflictDamage(
- Hitbox.Damage,
- Character,
- Hitbox.Knockback,
- knockbackVector: Direction
- );
- }
+ hurtbox.InflictDamage(
+ Hitbox.Damage,
+ Character,
+ Hitbox.Knockback,
+ knockbackVector: Direction
+ );
}
}
}
diff --git a/Extensions/AudioStreamPlayer2D.cs b/Extensions/AudioStreamPlayer2D.cs
index 2842d93..23339e7 100644
--- a/Extensions/AudioStreamPlayer2D.cs
+++ b/Extensions/AudioStreamPlayer2D.cs
@@ -2,72 +2,71 @@ using Godot;
using System;
using SupaLidlGame.Utils;
-namespace SupaLidlGame.Extensions
+namespace SupaLidlGame.Extensions;
+
+public static class AudioStreamPlayer2DExtensions
{
- public static class AudioStreamPlayer2DExtensions
+ public static AudioStreamPlayer2D Clone(
+ this AudioStreamPlayer2D audio)
{
- public static AudioStreamPlayer2D Clone(
- this AudioStreamPlayer2D audio)
+ var clone = audio.Duplicate() as AudioStreamPlayer2D;
+ clone.Finished += () =>
{
- var clone = audio.Duplicate() as AudioStreamPlayer2D;
- clone.Finished += () =>
- {
- clone.QueueFree();
- };
- return clone;
+ clone.QueueFree();
+ };
+ return clone;
+ }
+
+ public static AudioStreamPlayer2D On(
+ this AudioStreamPlayer2D audio,
+ Node parent)
+ {
+ var clone = audio.Clone();
+ parent.AddChild(clone);
+ clone.GlobalPosition = audio.GlobalPosition;
+ return clone;
+ }
+
+ public static AudioStreamPlayer2D OnWorld(
+ this AudioStreamPlayer2D audio)
+ {
+ var world = audio.GetTree().Root.GetNode("World/TileMap");
+ if (world is null)
+ {
+ throw new NullReferenceException("World does not exist");
+ }
+ var clone = audio.On(world);
+ clone.GlobalPosition = audio.GlobalPosition;
+ return clone;
+ }
+
+ public static AudioStreamPlayer2D At(
+ this AudioStreamPlayer2D audio,
+ Vector2 globalPosition)
+ {
+ var world = audio.GetTree().Root.GetNode("World/TileMap");
+ if (world is null)
+ {
+ throw new NullReferenceException("World does not exist");
}
- public static AudioStreamPlayer2D On(
- this AudioStreamPlayer2D audio,
- Node parent)
+ var parent = new Node2D();
+ world.AddChild(parent);
+ parent.GlobalPosition = globalPosition;
+
+ var clone = audio.On(world);
+ clone.Finished += () =>
{
- var clone = audio.Clone();
- parent.AddChild(clone);
- clone.GlobalPosition = audio.GlobalPosition;
- return clone;
- }
+ parent.QueueFree();
+ };
+ return clone;
+ }
- public static AudioStreamPlayer2D OnWorld(
- this AudioStreamPlayer2D audio)
- {
- var world = audio.GetTree().Root.GetNode("World/TileMap");
- if (world is null)
- {
- throw new NullReferenceException("World does not exist");
- }
- var clone = audio.On(world);
- clone.GlobalPosition = audio.GlobalPosition;
- return clone;
- }
-
- public static AudioStreamPlayer2D At(
- this AudioStreamPlayer2D audio,
- Vector2 globalPosition)
- {
- var world = audio.GetTree().Root.GetNode("World/TileMap");
- if (world is null)
- {
- throw new NullReferenceException("World does not exist");
- }
-
- var parent = new Node2D();
- world.AddChild(parent);
- parent.GlobalPosition = globalPosition;
-
- var clone = audio.On(world);
- clone.Finished += () =>
- {
- parent.QueueFree();
- };
- return clone;
- }
-
- public static AudioStreamPlayer2D WithPitchDeviation(
- this AudioStreamPlayer2D audio,
- float deviation)
- {
- audio.PitchScale = (float)GD.Randfn(audio.PitchScale, deviation);
- return audio;
- }
+ public static AudioStreamPlayer2D WithPitchDeviation(
+ this AudioStreamPlayer2D audio,
+ float deviation)
+ {
+ audio.PitchScale = (float)GD.Randfn(audio.PitchScale, deviation);
+ return audio;
}
}
diff --git a/Extensions/Node.cs b/Extensions/Node.cs
index 2defb9c..ee52e80 100644
--- a/Extensions/Node.cs
+++ b/Extensions/Node.cs
@@ -1,41 +1,40 @@
using Godot;
-namespace SupaLidlGame.Extensions
+namespace SupaLidlGame.Extensions;
+
+public static class NodeExtensions
{
- public static class NodeExtensions
+ ///
+ /// Iterates through each ancestor until it finds an ancestor of type
+ /// T
+ ///
+ public static T GetAncestor(this Node node) where T : Node
{
- ///
- /// Iterates through each ancestor until it finds an ancestor of type
- /// T
- ///
- public static T GetAncestor(this Node node) where T : Node
+ Node parent;
+
+ while ((parent = node.GetParent()) != null)
{
- Node parent;
-
- while ((parent = node.GetParent()) != null)
+ if (parent is T t)
{
- if (parent is T t)
- {
- return t;
- }
-
- node = parent;
+ return t;
}
- return null;
+ node = parent;
}
- ///
- /// A version GetNode that returns null rather than cause an
- /// exception if the node is not found or is not the same type.
- ///
- ///
- /// null if name does not match
- /// a valid Node
- ///
- public static T GetN(this Node node, string name) where T : Node
- {
- return node.GetNode(name) as T;
- }
+ return null;
+ }
+
+ ///
+ /// A version GetNode that returns null rather than cause an
+ /// exception if the node is not found or is not the same type.
+ ///
+ ///
+ /// null if name does not match
+ /// a valid Node
+ ///
+ public static T GetN(this Node node, string name) where T : Node
+ {
+ return node.GetNode(name) as T;
}
}
diff --git a/Extensions/Node2DExtensions.cs b/Extensions/Node2DExtensions.cs
index 1acaf32..694fb45 100644
--- a/Extensions/Node2DExtensions.cs
+++ b/Extensions/Node2DExtensions.cs
@@ -1,13 +1,12 @@
using Godot;
-namespace SupaLidlGame.Extensions
+namespace SupaLidlGame.Extensions;
+
+public static class Node2DExtensions
{
- public static class Node2DExtensions
+ public static void RayCast(this Node2D node, Vector2 ray)
{
- public static void RayCast(this Node2D node, Vector2 ray)
- {
- //var spaceState = node.GetWorld2d().DirectSpaceState;
- //var result = spaceState.IntersectRay();
- }
+ //var spaceState = node.GetWorld2d().DirectSpaceState;
+ //var result = spaceState.IntersectRay();
}
}
diff --git a/Extensions/Vector2.cs b/Extensions/Vector2.cs
index 070b22e..e8b2d1f 100644
--- a/Extensions/Vector2.cs
+++ b/Extensions/Vector2.cs
@@ -1,41 +1,40 @@
using Godot;
-namespace SupaLidlGame.Extensions
+namespace SupaLidlGame.Extensions;
+
+public static class Vector2Extensions
{
- public static class Vector2Extensions
+ public static Vector2 Midpoint(this Vector2 vector, Vector2 other)
{
- public static Vector2 Midpoint(this Vector2 vector, Vector2 other)
+ return new Vector2((vector.X + other.X) / 2,
+ (vector.Y + other.Y) / 2);
+ }
+
+ public static Vector2 Midpoints(params Vector2[] vectors)
+ {
+ int length = vectors.Length;
+ float x = 0;
+ float y = 0;
+
+ for (int i = 0; i < length; i++)
{
- return new Vector2((vector.X + other.X) / 2,
- (vector.Y + other.Y) / 2);
+ x += vectors[i].X;
+ y += vectors[i].Y;
}
- public static Vector2 Midpoints(params Vector2[] vectors)
- {
- int length = vectors.Length;
- float x = 0;
- float y = 0;
+ return new Vector2(x / length, y / length);
+ }
- for (int i = 0; i < length; i++)
- {
- x += vectors[i].X;
- y += vectors[i].Y;
- }
+ ///
+ /// Returns this vector 90 degrees counter clockwise (x, y) -> (-y, x)
+ ///
+ public static Vector2 Counterclockwise90(this Vector2 vector)
+ {
+ return new Vector2(-vector.Y, vector.X);
+ }
- return new Vector2(x / length, y / length);
- }
-
- ///
- /// Returns this vector 90 degrees counter clockwise (x, y) -> (-y, x)
- ///
- public static Vector2 Counterclockwise90(this Vector2 vector)
- {
- return new Vector2(-vector.Y, vector.X);
- }
-
- public static Vector2 Clockwise90(this Vector2 vector)
- {
- return new Vector2(vector.Y, -vector.X);
- }
+ public static Vector2 Clockwise90(this Vector2 vector)
+ {
+ return new Vector2(vector.Y, -vector.X);
}
}
diff --git a/Items/Inventory.cs b/Items/Inventory.cs
index 5466103..fe50d2f 100644
--- a/Items/Inventory.cs
+++ b/Items/Inventory.cs
@@ -2,145 +2,144 @@ using Godot;
using SupaLidlGame.Characters;
using Godot.Collections;
-namespace SupaLidlGame.Items
+namespace SupaLidlGame.Items;
+
+public partial class Inventory : Node2D
{
- public partial class Inventory : Node2D
+ public Character Character { get; private set; }
+
+ [Export]
+ public Array- Items { get; private set; }
+
+ [Export]
+ public Dictionary InventoryMap { get; set; }
+
+ public const int MaxCapacity = 32;
+
+ private Item _selectedItem;
+
+ private Item _offhandItem;
+
+ public Item SelectedItem
{
- public Character Character { get; private set; }
+ get => _selectedItem;
+ set => EquipItem(value, ref _selectedItem);
+ }
- [Export]
- public Array
- Items { get; private set; }
+ public Item OffhandItem
+ {
+ get => _selectedItem;
+ set => EquipItem(value, ref _offhandItem);
+ }
- [Export]
- public Dictionary InventoryMap { get; set; }
+ public bool IsUsingItem => (SelectedItem?.IsUsing ?? false) ||
+ (OffhandItem?.IsUsing ?? false);
- public const int MaxCapacity = 32;
+ public Inventory()
+ {
+ InventoryMap = new Dictionary();
+ InventoryMap.Add("equip_1", 0);
+ InventoryMap.Add("equip_2", 1);
+ InventoryMap.Add("equip_3", 2);
+ }
- private Item _selectedItem;
-
- private Item _offhandItem;
-
- public Item SelectedItem
+ public override void _Ready()
+ {
+ if (Items is null)
{
- get => _selectedItem;
- set => EquipItem(value, ref _selectedItem);
+ // instantiating a new array will prevent characters from
+ // sharing inventories
+ Items = new Array
- ();
}
-
- public Item OffhandItem
+ Character = GetParent();
+ foreach (Node child in GetChildren())
{
- get => _selectedItem;
- set => EquipItem(value, ref _offhandItem);
- }
-
- public bool IsUsingItem => (SelectedItem?.IsUsing ?? false) ||
- (OffhandItem?.IsUsing ?? false);
-
- public Inventory()
- {
- InventoryMap = new Dictionary();
- InventoryMap.Add("equip_1", 0);
- InventoryMap.Add("equip_2", 1);
- InventoryMap.Add("equip_3", 2);
- }
-
- public override void _Ready()
- {
- if (Items is null)
+ if (child is Item item)
{
- // instantiating a new array will prevent characters from
- // sharing inventories
- Items = new Array
- ();
+ GD.Print("Adding item " + item.Name);
+ AddItem(item);
}
- Character = GetParent();
- foreach (Node child in GetChildren())
- {
- if (child is Item item)
- {
- GD.Print("Adding item " + item.Name);
- AddItem(item);
- }
- }
- base._Ready();
}
+ base._Ready();
+ }
- private bool EquipItem(Item item, ref Item slot)
+ private bool EquipItem(Item item, ref Item slot)
+ {
+ if (item is not null)
{
- if (item is not null)
+ if (item.IsOneHanded)
{
- if (item.IsOneHanded)
+ // we can not equip this if either hand is occupied by
+ // two-handed item
+
+ if (_selectedItem is not null && !_selectedItem.IsOneHanded)
{
- // we can not equip this if either hand is occupied by
- // two-handed item
-
- if (_selectedItem is not null && !_selectedItem.IsOneHanded)
- {
- return false;
- }
-
- if (_offhandItem is not null && !_offhandItem.IsOneHanded)
- {
- return false;
- }
+ return false;
}
- if (!Items.Contains(item))
+ if (_offhandItem is not null && !_offhandItem.IsOneHanded)
{
- GD.PrintErr("Tried to equip an item not in the inventory.");
return false;
}
}
- if (slot is not null)
+ if (!Items.Contains(item))
{
- slot.Unequip(Character);
+ GD.PrintErr("Tried to equip an item not in the inventory.");
+ return false;
}
-
- slot = item;
-
- if (item is not null)
- {
- item.Equip(Character);
- }
-
- return true;
}
- public Item GetItemByMap(string keymap)
+ if (slot is not null)
{
- if (InventoryMap.ContainsKey(keymap))
+ slot.Unequip(Character);
+ }
+
+ slot = item;
+
+ if (item is not null)
+ {
+ item.Equip(Character);
+ }
+
+ return true;
+ }
+
+ public Item GetItemByMap(string keymap)
+ {
+ if (InventoryMap.ContainsKey(keymap))
+ {
+ int idx = InventoryMap[keymap];
+ if (idx < Items.Count)
{
- int idx = InventoryMap[keymap];
- if (idx < Items.Count)
- {
- return Items[InventoryMap[keymap]];
- }
+ return Items[InventoryMap[keymap]];
}
- else GD.Print(keymap + " does not exist");
+ }
+ else GD.Print(keymap + " does not exist");
+ return null;
+ }
+
+ public Item AddItem(Item item)
+ {
+ if (Items.Count >= MaxCapacity)
+ {
return null;
}
- public Item AddItem(Item item)
+ item.CharacterOwner = Character;
+ item.Visible = false;
+ if (!Items.Contains(item))
{
- if (Items.Count >= MaxCapacity)
- {
- return null;
- }
-
- item.CharacterOwner = Character;
- item.Visible = false;
- if (!Items.Contains(item))
- {
- Items.Add(item);
- }
- return item;
+ Items.Add(item);
}
+ return item;
+ }
- public Item DropItem(Item item)
- {
- item.CharacterOwner = null;
- item.Visible = true;
- var e = SelectedItem = item;
- throw new System.NotImplementedException();
- }
+ public Item DropItem(Item item)
+ {
+ item.CharacterOwner = null;
+ item.Visible = true;
+ var e = SelectedItem = item;
+ throw new System.NotImplementedException();
}
}
diff --git a/Items/Item.cs b/Items/Item.cs
index f19a768..d717582 100644
--- a/Items/Item.cs
+++ b/Items/Item.cs
@@ -1,53 +1,52 @@
using Godot;
using SupaLidlGame.Characters;
-namespace SupaLidlGame.Items
+namespace SupaLidlGame.Items;
+
+public abstract partial class Item : Node2D
{
- public abstract partial class Item : Node2D
+ [Export]
+ public string ItemName { get; set; }
+
+ [Export]
+ public string Description { get; set; }
+
+ [Export]
+ public bool CanStack { get; set; } = false;
+
+ public int Count { get; set; } = 1;
+
+ public bool IsOneHanded { get; set; } = false;
+
+ public Character CharacterOwner { get; set; }
+
+ public virtual bool IsUsing => false;
+
+ ///
+ /// Determines if this item can directly stack with other items
+ ///
+ public virtual bool StacksWith(Item item)
{
- [Export]
- public string ItemName { get; set; }
-
- [Export]
- public string Description { get; set; }
-
- [Export]
- public bool CanStack { get; set; } = false;
-
- public int Count { get; set; } = 1;
-
- public bool IsOneHanded { get; set; } = false;
-
- public Character CharacterOwner { get; set; }
-
- public virtual bool IsUsing => false;
-
- ///
- /// Determines if this item can directly stack with other items
- ///
- public virtual bool StacksWith(Item item)
+ if (!CanStack)
{
- if (!CanStack)
- {
- return false;
- }
-
- if (ItemName != item.ItemName)
- {
- return false;
- }
-
- // several more conditions may be added soon
-
- return true;
+ return false;
}
- public abstract void Equip(Character character);
+ if (ItemName != item.ItemName)
+ {
+ return false;
+ }
- public abstract void Unequip(Character character);
+ // several more conditions may be added soon
- public abstract void Use();
-
- public abstract void Deuse();
+ return true;
}
+
+ public abstract void Equip(Character character);
+
+ public abstract void Unequip(Character character);
+
+ public abstract void Use();
+
+ public abstract void Deuse();
}
diff --git a/Items/Weapon.cs b/Items/Weapon.cs
index d8485b9..2d6a497 100644
--- a/Items/Weapon.cs
+++ b/Items/Weapon.cs
@@ -2,109 +2,108 @@ using Godot;
using SupaLidlGame.BoundingBoxes;
using SupaLidlGame.Characters;
-namespace SupaLidlGame.Items
+namespace SupaLidlGame.Items;
+
+public abstract partial class Weapon : Item
{
- public abstract partial class Weapon : Item
+ public double RemainingUseTime { get; protected set; } = 0;
+
+ public override bool IsUsing => RemainingUseTime > 0;
+
+ ///
+ /// How much damage in HP that this weapon deals.
+ ///
+ [Export]
+ public float Damage { get; set; } = 0;
+
+ ///
+ /// The time in seconds it takes for this weapon to become available
+ /// again after using.
+ ///
+ [Export]
+ public double UseTime { get; set; } = 0;
+
+ ///
+ /// The magnitude of the knockback force of the weapon.
+ ///
+ [Export]
+ public float Knockback { get; set; } = 0;
+
+ ///
+ /// The initial velocity of any projectile the weapon may spawn.
+ ///
+ [Export]
+ public float InitialVelocity { get; set; } = 0;
+
+ ///
+ /// Hides the weapon if it is idle (i.e. not being used).
+ ///
+ [Export]
+ public bool ShouldHideIdle { get; set; } = false;
+
+ ///
+ /// Freezes the player's target angle if this weapon is being used.
+ ///
+ [Export]
+ public bool ShouldFreezeAngleOnUse { get; set; } = true;
+
+ [Export]
+ public float MinDistanceHint { get; set; }
+
+ [Export]
+ public float MaxDistanceHint { get; set; }
+
+ public virtual bool IsParryable { get; protected set; } = false;
+
+ public bool IsParried { get; set; }
+
+ public Character Character { get; set; }
+
+ public Vector2 UseDirection { get; set; }
+
+ public override bool StacksWith(Item item) => false;
+
+ public override void Equip(Character character)
{
- public double RemainingUseTime { get; protected set; } = 0;
-
- public override bool IsUsing => RemainingUseTime > 0;
-
- ///
- /// How much damage in HP that this weapon deals.
- ///
- [Export]
- public float Damage { get; set; } = 0;
-
- ///
- /// The time in seconds it takes for this weapon to become available
- /// again after using.
- ///
- [Export]
- public double UseTime { get; set; } = 0;
-
- ///
- /// The magnitude of the knockback force of the weapon.
- ///
- [Export]
- public float Knockback { get; set; } = 0;
-
- ///
- /// The initial velocity of any projectile the weapon may spawn.
- ///
- [Export]
- public float InitialVelocity { get; set; } = 0;
-
- ///
- /// Hides the weapon if it is idle (i.e. not being used).
- ///
- [Export]
- public bool ShouldHideIdle { get; set; } = false;
-
- ///
- /// Freezes the player's target angle if this weapon is being used.
- ///
- [Export]
- public bool ShouldFreezeAngleOnUse { get; set; } = true;
-
- [Export]
- public float MinDistanceHint { get; set; }
-
- [Export]
- public float MaxDistanceHint { get; set; }
-
- public virtual bool IsParryable { get; protected set; } = false;
-
- public bool IsParried { get; set; }
-
- public Character Character { get; set; }
-
- public Vector2 UseDirection { get; set; }
-
- public override bool StacksWith(Item item) => false;
-
- public override void Equip(Character character)
+ if (!ShouldHideIdle || IsUsing)
{
- if (!ShouldHideIdle || IsUsing)
+ Visible = true;
+ }
+ Character = character;
+ }
+
+ public override void Unequip(Character character)
+ {
+ Visible = false;
+ Character = null;
+ }
+
+ public override void Use()
+ {
+ RemainingUseTime = UseTime;
+ }
+
+ public override void Deuse()
+ {
+
+ }
+
+ public override void _Process(double delta)
+ {
+ if (RemainingUseTime > 0)
+ {
+ if ((RemainingUseTime -= delta) <= 0)
{
- Visible = true;
- }
- Character = character;
- }
-
- public override void Unequip(Character character)
- {
- Visible = false;
- Character = null;
- }
-
- public override void Use()
- {
- RemainingUseTime = UseTime;
- }
-
- public override void Deuse()
- {
-
- }
-
- public override void _Process(double delta)
- {
- if (RemainingUseTime > 0)
- {
- if ((RemainingUseTime -= delta) <= 0)
- {
- //Deuse();
- }
- }
- }
-
- public virtual void _on_hitbox_hit(BoundingBox box)
- {
- if (box is Hurtbox hurtbox)
- {
- hurtbox.InflictDamage(Damage, Character, Knockback);
+ //Deuse();
}
}
}
+
+ public virtual void _on_hitbox_hit(BoundingBox box)
+ {
+ if (box is Hurtbox hurtbox)
+ {
+ hurtbox.InflictDamage(Damage, Character, Knockback);
+ }
+ }
}
diff --git a/Items/Weapons/IParryable.cs b/Items/Weapons/IParryable.cs
index 49b9a4c..de14b5e 100644
--- a/Items/Weapons/IParryable.cs
+++ b/Items/Weapons/IParryable.cs
@@ -1,10 +1,9 @@
-namespace SupaLidlGame.Items.Weapons
+namespace SupaLidlGame.Items.Weapons;
+
+public interface IParryable
{
- public interface IParryable
- {
- public bool IsParryable { get; }
- public bool IsParried { get; }
- public ulong ParryTimeOrigin { get; }
- public void Stun();
- }
+ public bool IsParryable { get; }
+ public bool IsParried { get; }
+ public ulong ParryTimeOrigin { get; }
+ public void Stun();
}
diff --git a/Items/Weapons/Railgun.cs b/Items/Weapons/Railgun.cs
index 5946d67..4ebed2a 100644
--- a/Items/Weapons/Railgun.cs
+++ b/Items/Weapons/Railgun.cs
@@ -1,22 +1,21 @@
using Godot;
using SupaLidlGame.Extensions;
-namespace SupaLidlGame.Items.Weapons
+namespace SupaLidlGame.Items.Weapons;
+
+public partial class Railgun : Ranged
{
- public partial class Railgun : Ranged
+ public override void Attack()
{
- public override void Attack()
- {
- // create projectile
- PackedScene scene = GD.Load("res://Entities/RailBeam.tscn");
- GD.Print("lol");
- var projectile = scene.Instantiate();
- projectile.Hitbox.Faction = Character.Faction;
- projectile.Direction = Character.Target;
- projectile.GlobalPosition = GlobalPosition;
- projectile.GlobalRotation = projectile.Direction.Angle();
- this.GetAncestor()
- .Entities.AddChild(projectile);
- }
+ // create projectile
+ PackedScene scene = GD.Load("res://Entities/RailBeam.tscn");
+ GD.Print("lol");
+ var projectile = scene.Instantiate();
+ projectile.Hitbox.Faction = Character.Faction;
+ projectile.Direction = Character.Target;
+ projectile.GlobalPosition = GlobalPosition;
+ projectile.GlobalRotation = projectile.Direction.Angle();
+ this.GetAncestor()
+ .Entities.AddChild(projectile);
}
}
diff --git a/Items/Weapons/Ranged.cs b/Items/Weapons/Ranged.cs
index 79dbbd7..06af707 100644
--- a/Items/Weapons/Ranged.cs
+++ b/Items/Weapons/Ranged.cs
@@ -1,43 +1,42 @@
using Godot;
-namespace SupaLidlGame.Items.Weapons
+namespace SupaLidlGame.Items.Weapons;
+
+public abstract partial class Ranged : Weapon
{
- public abstract partial class Ranged : Weapon
+ [Export]
+ public float AngleDeviation { get; set; }
+
+ [Export]
+ public float ChargeTime { get; set; }
+
+ [Export]
+ public State.Weapon.WeaponStateMachine StateMachine { get; set; }
+
+ public override bool IsUsing => StateMachine.CurrentState
+ is State.Weapon.RangedFireState;
+
+ public bool IsChargeable => ChargeTime > 0;
+
+ public bool IsCharging { get; protected set; }
+
+ public override void Use()
{
- [Export]
- public float AngleDeviation { get; set; }
-
- [Export]
- public float ChargeTime { get; set; }
-
- [Export]
- public State.Weapon.WeaponStateMachine StateMachine { get; set; }
-
- public override bool IsUsing => StateMachine.CurrentState
- is State.Weapon.RangedFireState;
-
- public bool IsChargeable => ChargeTime > 0;
-
- public bool IsCharging { get; protected set; }
-
- public override void Use()
- {
- StateMachine.Use();
- base.Use();
- }
-
- public override void Deuse()
- {
- StateMachine.Deuse();
- base.Deuse();
- }
-
- public override void _Process(double delta)
- {
- StateMachine.Process(delta);
- base._Process(delta);
- }
-
- public abstract void Attack();
+ StateMachine.Use();
+ base.Use();
}
+
+ public override void Deuse()
+ {
+ StateMachine.Deuse();
+ base.Deuse();
+ }
+
+ public override void _Process(double delta)
+ {
+ StateMachine.Process(delta);
+ base._Process(delta);
+ }
+
+ public abstract void Attack();
}
diff --git a/Items/Weapons/Sword.cs b/Items/Weapons/Sword.cs
index 679a830..826116a 100644
--- a/Items/Weapons/Sword.cs
+++ b/Items/Weapons/Sword.cs
@@ -4,234 +4,233 @@ using SupaLidlGame.Characters;
using SupaLidlGame.Extensions;
using SupaLidlGame.State.Weapon;
-namespace SupaLidlGame.Items.Weapons
+namespace SupaLidlGame.Items.Weapons;
+
+public partial class Sword : Weapon, IParryable
{
- public partial class Sword : Weapon, IParryable
+ public bool IsAttacking { get; protected set; }
+
+ public override bool IsUsing => StateMachine.CurrentState
+ is SwordAttackState;
+
+ [Export]
+ public Hitbox Hitbox { get; set; }
+
+ [Export]
+ public AnimationPlayer AnimationPlayer { get; set; }
+
+ [Export]
+ public AnimationTree AnimationTree { get; set; }
+
+ ///
+ /// The time frame in seconds for which the weapon will deal damage.
+ ///
+ ///
+ /// The value of AttackTime should be less than the
+ /// value of UseTime
+ ///
+ [Export]
+ public double AttackTime { get; set; } = 0;
+
+ [Export]
+ public double AttackAnimationDuration { get; set; }
+
+ [Export]
+ public CpuParticles2D ParryParticles { get; set; }
+
+ [Export]
+ public double NPCAnticipateTime { get; set; }
+
+ [Export]
+ public WeaponStateMachine StateMachine { get; set; }
+
+ [Export]
+ public Node2D Anchor { get; set; }
+
+ public override bool IsParryable { get; protected set; }
+
+ public ulong ParryTimeOrigin { get; protected set; }
+
+ private Tween _currentTween;
+
+ private AnimationNodeStateMachinePlayback _playback;
+
+ public override void Equip(Character character)
{
- public bool IsAttacking { get; protected set; }
+ base.Equip(character);
+ Hitbox.Faction = character.Faction; // character is null before base
+ }
- public override bool IsUsing => StateMachine.CurrentState
- is SwordAttackState;
+ public override void Unequip(Character character)
+ {
+ base.Unequip(character);
+ }
- [Export]
- public Hitbox Hitbox { get; set; }
-
- [Export]
- public AnimationPlayer AnimationPlayer { get; set; }
-
- [Export]
- public AnimationTree AnimationTree { get; set; }
-
- ///
- /// The time frame in seconds for which the weapon will deal damage.
- ///
- ///
- /// The value of AttackTime should be less than the
- /// value of UseTime
- ///
- [Export]
- public double AttackTime { get; set; } = 0;
-
- [Export]
- public double AttackAnimationDuration { get; set; }
-
- [Export]
- public CpuParticles2D ParryParticles { get; set; }
-
- [Export]
- public double NPCAnticipateTime { get; set; }
-
- [Export]
- public WeaponStateMachine StateMachine { get; set; }
-
- [Export]
- public Node2D Anchor { get; set; }
-
- public override bool IsParryable { get; protected set; }
-
- public ulong ParryTimeOrigin { get; protected set; }
-
- private Tween _currentTween;
-
- private AnimationNodeStateMachinePlayback _playback;
-
- public override void Equip(Character character)
+ public override void Use()
+ {
+ // we can't use if we're still using the weapon
+ if (RemainingUseTime > 0)
{
- base.Equip(character);
- Hitbox.Faction = character.Faction; // character is null before base
+ //return;
}
- public override void Unequip(Character character)
+ StateMachine.Use();
+
+ /*
+ // reset state of the weapon
+ IsParried = false;
+ IsParryable = true;
+ ParryTimeOrigin = Time.GetTicksMsec();
+
+ _playback.Travel("use");
+ */
+
+ // play animation depending on rotation of weapon
+ /*
+ string anim = "use";
+
+ if (GetNode("Anchor").Rotation > Mathf.DegToRad(50))
{
- base.Unequip(character);
+ anim = "use2";
}
- public override void Use()
+ if (Character is NPC)
{
- // we can't use if we're still using the weapon
- if (RemainingUseTime > 0)
+ // NPCs have a slower attack
+ anim += "-npc";
+ }
+
+ AnimationPlayer.Play(anim);
+ */
+
+ base.Use();
+ }
+
+ public void EnableParry()
+ {
+ IsParried = false;
+ IsParryable = true;
+ ParryTimeOrigin = Time.GetTicksMsec();
+ GD.Print(Character.Name);
+ }
+
+ public void DisableParry()
+ {
+ IsParryable = false;
+ }
+
+ public override void Deuse()
+ {
+ //AnimationPlayer.Stop();
+ Deattack();
+ base.Deuse();
+ }
+
+ public void Attack()
+ {
+ //RemainingAttackTime = AttackTime;
+ IsAttacking = true;
+ Hitbox.IsDisabled = false;
+ }
+
+ public void Deattack()
+ {
+ IsAttacking = false;
+ DisableParry();
+ Hitbox.IsDisabled = true;
+ ProcessHits();
+ Hitbox.ResetIgnoreList();
+ AnimationPlayer.SpeedScale = 1;
+ }
+
+ public override void _Ready()
+ {
+ Hitbox.Damage = Damage;
+ _playback = (AnimationNodeStateMachinePlayback)AnimationTree
+ .Get("parameters/playback");
+ }
+
+ public override void _Process(double delta)
+ {
+ StateMachine.Process(delta);
+ base._Process(delta);
+ }
+
+ public void ProcessHits()
+ {
+ if (IsParried)
+ {
+ return;
+ }
+
+ foreach (BoundingBox box in Hitbox.Hits)
+ {
+ GD.Print("processing hit");
+ if (box is Hurtbox hurtbox)
{
- //return;
+ hurtbox.InflictDamage(Damage, Character, Knockback);
}
+ }
+ }
- StateMachine.Use();
-
- /*
- // reset state of the weapon
- IsParried = false;
- IsParryable = true;
- ParryTimeOrigin = Time.GetTicksMsec();
-
- _playback.Travel("use");
- */
-
- // play animation depending on rotation of weapon
- /*
- string anim = "use";
-
- if (GetNode("Anchor").Rotation > Mathf.DegToRad(50))
+ public void AttemptParry(Weapon otherWeapon)
+ {
+ //if (IsParryable && otherWeapon.IsParryable)
+ if (otherWeapon.IsParryable &&
+ otherWeapon is IParryable otherParryable)
+ {
+ ParryParticles.Emitting = true;
+ if (ParryTimeOrigin < otherParryable.ParryTimeOrigin)
{
- anim = "use2";
+ // our character was parried
}
-
- if (Character is NPC)
+ else
{
- // NPCs have a slower attack
- anim += "-npc";
+ otherParryable.Stun();
}
+ }
+ //this.GetAncestor().AddChild(instance);
+ }
- AnimationPlayer.Play(anim);
- */
+ public void Stun()
+ {
+ IsParried = true;
+ AnimationPlayer.SpeedScale = 0.25f;
+ Character.Stun(1.5f);
+ GetNode("ParrySound").OnWorld().Play();
+ }
- base.Use();
+ public override void _on_hitbox_hit(BoundingBox box)
+ {
+ if (IsParried)
+ {
+ return;
}
- public void EnableParry()
+ if (box is Hitbox hb)
{
- IsParried = false;
- IsParryable = true;
- ParryTimeOrigin = Time.GetTicksMsec();
- GD.Print(Character.Name);
- }
-
- public void DisableParry()
- {
- IsParryable = false;
- }
-
- public override void Deuse()
- {
- //AnimationPlayer.Stop();
- Deattack();
- base.Deuse();
- }
-
- public void Attack()
- {
- //RemainingAttackTime = AttackTime;
- IsAttacking = true;
- Hitbox.IsDisabled = false;
- }
-
- public void Deattack()
- {
- IsAttacking = false;
- DisableParry();
- Hitbox.IsDisabled = true;
- ProcessHits();
- Hitbox.ResetIgnoreList();
- AnimationPlayer.SpeedScale = 1;
- }
-
- public override void _Ready()
- {
- Hitbox.Damage = Damage;
- _playback = (AnimationNodeStateMachinePlayback)AnimationTree
- .Get("parameters/playback");
- }
-
- public override void _Process(double delta)
- {
- StateMachine.Process(delta);
- base._Process(delta);
- }
-
- public void ProcessHits()
- {
- if (IsParried)
+ Weapon w = hb.GetAncestor();
+ if (w is not null)
{
- return;
- }
-
- foreach (BoundingBox box in Hitbox.Hits)
- {
- GD.Print("processing hit");
- if (box is Hurtbox hurtbox)
- {
- hurtbox.InflictDamage(Damage, Character, Knockback);
- }
+ AttemptParry(w);
}
}
- public void AttemptParry(Weapon otherWeapon)
+ if (box is Hurtbox hurt)
{
- //if (IsParryable && otherWeapon.IsParryable)
- if (otherWeapon.IsParryable &&
- otherWeapon is IParryable otherParryable)
+ if (hurt.GetParent() is Character c)
{
- ParryParticles.Emitting = true;
- if (ParryTimeOrigin < otherParryable.ParryTimeOrigin)
- {
- // our character was parried
- }
- else
- {
- otherParryable.Stun();
- }
- }
- //this.GetAncestor().AddChild(instance);
- }
-
- public void Stun()
- {
- IsParried = true;
- AnimationPlayer.SpeedScale = 0.25f;
- Character.Stun(1.5f);
- GetNode("ParrySound").OnWorld().Play();
- }
-
- public override void _on_hitbox_hit(BoundingBox box)
- {
- if (IsParried)
- {
- return;
- }
-
- if (box is Hitbox hb)
- {
- Weapon w = hb.GetAncestor();
- if (w is not null)
+ var item = c.Inventory.SelectedItem;
+ if (item is Weapon w)
{
AttemptParry(w);
}
}
-
- if (box is Hurtbox hurt)
- {
- if (hurt.GetParent() is Character c)
- {
- var item = c.Inventory.SelectedItem;
- if (item is Weapon w)
- {
- AttemptParry(w);
- }
- }
- }
- }
-
- protected void SetAnimationCondition(string condition, bool value)
- {
- AnimationTree.Set("parameters/conditions/" + condition, value);
}
}
+
+ protected void SetAnimationCondition(string condition, bool value)
+ {
+ AnimationTree.Set("parameters/conditions/" + condition, value);
+ }
}
diff --git a/Scenes/Level.tscn b/Scenes/Level.tscn
index f051216..efb08ee 100644
--- a/Scenes/Level.tscn
+++ b/Scenes/Level.tscn
@@ -3,7 +3,6 @@
[ext_resource type="Script" path="res://Utils/World.cs" id="1_1k6ew"]
[ext_resource type="PackedScene" uid="uid://bxtpv6jqodj4v" path="res://Scenes/Maps/Hills.tscn" id="2_juio7"]
-[node name="World" type="Node2D" node_paths=PackedStringArray("CurrentPlayer")]
+[node name="World" type="Node2D"]
script = ExtResource("1_1k6ew")
StartingArea = ExtResource("2_juio7")
-CurrentPlayer = NodePath("")
diff --git a/Scenes/Map.cs b/Scenes/Map.cs
index c4224d9..a51bcdb 100644
--- a/Scenes/Map.cs
+++ b/Scenes/Map.cs
@@ -1,48 +1,47 @@
using Godot;
using System;
-namespace SupaLidlGame.Scenes
+namespace SupaLidlGame.Scenes;
+
+public partial class Map : TileMap
{
- public partial class Map : TileMap
+ [Export]
+ public Node2D Entities { get; set; }
+
+ [Export]
+ public Node2D Areas { get; set; }
+
+ [Export]
+ public Node2D Spawners { get; set; }
+
+ [Export]
+ public Vector2 CameraLowerBound { get; set; }
+
+ [Export]
+ public Vector2 CameraUpperBound { get; set; }
+
+ private bool _active;
+
+ public bool Active
{
- [Export]
- public Node2D Entities { get; set; }
-
- [Export]
- public Node2D Areas { get; set; }
-
- [Export]
- public Node2D Spawners { get; set; }
-
- [Export]
- public Vector2 CameraLowerBound { get; set; }
-
- [Export]
- public Vector2 CameraUpperBound { get; set; }
-
- private bool _active;
-
- public bool Active
+ get
{
- get
- {
- return _active;
- }
- set
- {
- _active = Visible = value;
- SetProcess(value);
- }
+ return _active;
}
-
- public override void _Ready()
+ set
{
- Active = true;
- }
-
- public override void _Process(double delta)
- {
- base._Process(delta);
+ _active = Visible = value;
+ SetProcess(value);
}
}
+
+ public override void _Ready()
+ {
+ Active = true;
+ }
+
+ public override void _Process(double delta)
+ {
+ base._Process(delta);
+ }
}
diff --git a/State/Character/CharacterState.cs b/State/Character/CharacterState.cs
index 8b22a14..08fc94e 100644
--- a/State/Character/CharacterState.cs
+++ b/State/Character/CharacterState.cs
@@ -1,70 +1,69 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public abstract partial class CharacterState : Node, IState
{
- public abstract partial class CharacterState : Node, IState
+ [Export]
+ public Characters.Character Character { get; set; }
+
+ public virtual IState Enter(IState prev) => null;
+
+ public virtual void Exit(IState next)
{
- [Export]
- public Characters.Character Character { get; set; }
- public virtual IState Enter(IState prev) => null;
-
- public virtual void Exit(IState next)
- {
-
- }
-
- public virtual CharacterState Process(double delta)
- {
- if (Character.StunTime > 0)
- {
- Character.StunTime -= delta;
- }
-
- var item = Character.Inventory.SelectedItem;
- var offhand = Character.Inventory.OffhandItem;
-
- // angle towards item use angle or offhand use angle if not used
-
- bool targetTowards(Items.Item item)
- {
- if (item is Items.Weapon weapon)
- {
- if (weapon.IsUsing)
- {
- Character.Target = weapon.UseDirection;
- return true;
- }
- }
- return false;
- }
-
- var _ = targetTowards(item) || targetTowards(offhand);
-
- return null;
- }
-
- public virtual CharacterState PhysicsProcess(double delta)
- {
- Character.Velocity = Character.NetImpulse;
-
- if (Character.NetImpulse.LengthSquared() < Mathf.Pow(Character.Speed, 2))
- {
- Character.Velocity += Character.Direction.Normalized()
- * Character.Speed;
- // we should only modify velocity that is in the player's control
- Character.ModifyVelocity();
- }
-
- Character.NetImpulse = Character.NetImpulse.MoveToward(
- Vector2.Zero,
- (float)delta * Character.Speed * Character.Friction);
-
- Character.MoveAndSlide();
-
- return null;
- }
-
- public virtual CharacterState Input(InputEvent @event) => null;
}
+
+ public virtual CharacterState Process(double delta)
+ {
+ if (Character.StunTime > 0)
+ {
+ Character.StunTime -= delta;
+ }
+
+ var item = Character.Inventory.SelectedItem;
+ var offhand = Character.Inventory.OffhandItem;
+
+ // angle towards item use angle or offhand use angle if not used
+
+ bool targetTowards(Items.Item item)
+ {
+ if (item is Items.Weapon weapon)
+ {
+ if (weapon.IsUsing)
+ {
+ Character.Target = weapon.UseDirection;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ var _ = targetTowards(item) || targetTowards(offhand);
+
+ return null;
+ }
+
+ public virtual CharacterState PhysicsProcess(double delta)
+ {
+ Character.Velocity = Character.NetImpulse;
+
+ if (Character.NetImpulse.LengthSquared() < Mathf.Pow(Character.Speed, 2))
+ {
+ Character.Velocity += Character.Direction.Normalized()
+ * Character.Speed;
+ // we should only modify velocity that is in the player's control
+ Character.ModifyVelocity();
+ }
+
+ Character.NetImpulse = Character.NetImpulse.MoveToward(
+ Vector2.Zero,
+ (float)delta * Character.Speed * Character.Friction);
+
+ Character.MoveAndSlide();
+
+ return null;
+ }
+
+ public virtual CharacterState Input(InputEvent @event) => null;
}
diff --git a/State/Character/CharacterStateMachine.cs b/State/Character/CharacterStateMachine.cs
index 87cde18..1e2af78 100644
--- a/State/Character/CharacterStateMachine.cs
+++ b/State/Character/CharacterStateMachine.cs
@@ -1,40 +1,39 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class CharacterStateMachine : StateMachine
{
- public partial class CharacterStateMachine : StateMachine
+ [Export]
+ public override CharacterState InitialState { get; set; }
+
+ [Export]
+ public Characters.Character Character { get; set; }
+
+ public void Process(double delta)
{
- [Export]
- public override CharacterState InitialState { get; set; }
-
- [Export]
- public Characters.Character Character { get; set; }
-
- public void Process(double delta)
+ var state = CurrentState.Process(delta);
+ if (state is CharacterState)
{
- var state = CurrentState.Process(delta);
- if (state is CharacterState)
- {
- ChangeState(state);
- }
+ ChangeState(state);
}
+ }
- public void PhysicsProcess(double delta)
+ public void PhysicsProcess(double delta)
+ {
+ var state = CurrentState.PhysicsProcess(delta);
+ if (state is CharacterState)
{
- var state = CurrentState.PhysicsProcess(delta);
- if (state is CharacterState)
- {
- ChangeState(state);
- }
+ ChangeState(state);
}
+ }
- public void Input(InputEvent @event)
+ public void Input(InputEvent @event)
+ {
+ var state = CurrentState.Input(@event);
+ if (state is CharacterState)
{
- var state = CurrentState.Input(@event);
- if (state is CharacterState)
- {
- ChangeState(state);
- }
+ ChangeState(state);
}
}
}
diff --git a/State/Character/NPCIdleState.cs b/State/Character/NPCIdleState.cs
index 3024443..617bf06 100644
--- a/State/Character/NPCIdleState.cs
+++ b/State/Character/NPCIdleState.cs
@@ -1,26 +1,25 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class NPCIdleState : NPCState
{
- public partial class NPCIdleState : NPCState
+ [Export]
+ public CharacterState MoveState { get; set; }
+
+ public override CharacterState Process(double delta)
{
- [Export]
- public CharacterState MoveState { get; set; }
-
- public override CharacterState Process(double delta)
+ base.Process(delta);
+ if (Character.Direction.LengthSquared() > 0)
{
- base.Process(delta);
- if (Character.Direction.LengthSquared() > 0)
- {
- return MoveState;
- }
- return null;
+ return MoveState;
}
+ return null;
+ }
- public override IState Enter(IState previousState)
- {
- Character.Sprite.Play("idle");
- return base.Enter(previousState);
- }
+ public override IState Enter(IState previousState)
+ {
+ Character.Sprite.Play("idle");
+ return base.Enter(previousState);
}
}
diff --git a/State/Character/NPCMoveState.cs b/State/Character/NPCMoveState.cs
index 59653fe..4a6879a 100644
--- a/State/Character/NPCMoveState.cs
+++ b/State/Character/NPCMoveState.cs
@@ -1,26 +1,25 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class NPCMoveState : NPCState
{
- public partial class NPCMoveState : NPCState
+ [Export]
+ public CharacterState IdleState { get; set; }
+
+ public override CharacterState Process(double delta)
{
- [Export]
- public CharacterState IdleState { get; set; }
-
- public override CharacterState Process(double delta)
+ base.Process(delta);
+ if (Character.Direction.LengthSquared() == 0)
{
- base.Process(delta);
- if (Character.Direction.LengthSquared() == 0)
- {
- return IdleState;
- }
- return null;
+ return IdleState;
}
+ return null;
+ }
- public override IState Enter(IState prev)
- {
- Character.Sprite.Play("move");
- return base.Enter(prev);
- }
+ public override IState Enter(IState prev)
+ {
+ Character.Sprite.Play("move");
+ return base.Enter(prev);
}
}
diff --git a/State/Character/NPCState.cs b/State/Character/NPCState.cs
index c91397a..f74bce7 100644
--- a/State/Character/NPCState.cs
+++ b/State/Character/NPCState.cs
@@ -1,13 +1,12 @@
-namespace SupaLidlGame.State.Character
-{
- public abstract partial class NPCState : CharacterState
- {
- protected Characters.NPC _npc => Character as Characters.NPC;
+namespace SupaLidlGame.State.Character;
- public override CharacterState Process(double delta)
- {
- _npc.ThinkProcess(delta);
- return base.Process(delta);
- }
+public abstract partial class NPCState : CharacterState
+{
+ protected Characters.NPC _npc => Character as Characters.NPC;
+
+ public override CharacterState Process(double delta)
+ {
+ _npc.ThinkProcess(delta);
+ return base.Process(delta);
}
}
diff --git a/State/Character/PlayerIdleState.cs b/State/Character/PlayerIdleState.cs
index 998c6a3..fcc12f4 100644
--- a/State/Character/PlayerIdleState.cs
+++ b/State/Character/PlayerIdleState.cs
@@ -1,38 +1,37 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class PlayerIdleState : PlayerState
{
- public partial class PlayerIdleState : PlayerState
+ [Export]
+ public CharacterState MoveState { get; set; }
+
+ public override IState Enter(IState previousState)
{
- [Export]
- public CharacterState MoveState { get; set; }
-
- public override IState Enter(IState previousState)
+ GD.Print("Entered idle state");
+ if (previousState is not PlayerMoveState)
{
- GD.Print("Entered idle state");
- if (previousState is not PlayerMoveState)
- {
- if (Character.Direction.LengthSquared() > 0.01f)
- {
- // other states like attacking or rolling can just delegate
- // the work of checking if the player is moving to this idle
- // state, so they do not have to manually check if the player
- // wants to move to switch to the move state.
- return MoveState;
- }
- }
- _player.Animation = "idle";
- return base.Enter(previousState);
- }
-
- public override CharacterState Process(double delta)
- {
- base.Process(delta);
- if (Character.Direction.LengthSquared() > 0)
+ if (Character.Direction.LengthSquared() > 0.01f)
{
+ // other states like attacking or rolling can just delegate
+ // the work of checking if the player is moving to this idle
+ // state, so they do not have to manually check if the player
+ // wants to move to switch to the move state.
return MoveState;
}
- return null;
}
+ _player.Animation = "idle";
+ return base.Enter(previousState);
+ }
+
+ public override CharacterState Process(double delta)
+ {
+ base.Process(delta);
+ if (Character.Direction.LengthSquared() > 0)
+ {
+ return MoveState;
+ }
+ return null;
}
}
diff --git a/State/Character/PlayerMoveState.cs b/State/Character/PlayerMoveState.cs
index 165f6ed..38334e6 100644
--- a/State/Character/PlayerMoveState.cs
+++ b/State/Character/PlayerMoveState.cs
@@ -1,46 +1,45 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class PlayerMoveState : PlayerState
{
- public partial class PlayerMoveState : PlayerState
+ [Export]
+ public PlayerRollState RollState { get; set; }
+
+ public override IState Enter(IState previousState)
{
- [Export]
- public PlayerRollState RollState { get; set; }
+ Godot.GD.Print("Started moving");
+ _player.Animation = "move";
+ return base.Enter(previousState);
+ }
- public override IState Enter(IState previousState)
+ public override CharacterState Process(double delta)
+ {
+ base.Process(delta);
+ if (Character.Direction.LengthSquared() == 0)
{
- Godot.GD.Print("Started moving");
- _player.Animation = "move";
- return base.Enter(previousState);
+ return IdleState;
}
+ return null;
+ }
- public override CharacterState Process(double delta)
+ public override CharacterState Input(InputEvent @event)
+ {
+ if (@event.IsActionPressed("roll"))
{
- base.Process(delta);
- if (Character.Direction.LengthSquared() == 0)
+ if (Character.Inventory.SelectedItem is Items.Weapon weapon)
{
- return IdleState;
- }
- return null;
- }
-
- public override CharacterState Input(InputEvent @event)
- {
- if (@event.IsActionPressed("roll"))
- {
- if (Character.Inventory.SelectedItem is Items.Weapon weapon)
- {
- if (!weapon.IsUsing)
- {
- return RollState;
- }
- }
- else
+ if (!weapon.IsUsing)
{
return RollState;
}
}
- return base.Input(@event);
+ else
+ {
+ return RollState;
+ }
}
+ return base.Input(@event);
}
}
diff --git a/State/Character/PlayerRollState.cs b/State/Character/PlayerRollState.cs
index efafbd6..57b6c87 100644
--- a/State/Character/PlayerRollState.cs
+++ b/State/Character/PlayerRollState.cs
@@ -1,39 +1,38 @@
using Godot;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public partial class PlayerRollState : PlayerState
{
- public partial class PlayerRollState : PlayerState
+ private double _timeLeftToRoll = 0;
+
+ private Vector2 _rollDirection = Vector2.Zero;
+
+ public override IState Enter(IState previousState)
{
- private double _timeLeftToRoll = 0;
+ _timeLeftToRoll = 0.5;
+ // roll the direction we were previously moving in
+ _rollDirection = Character.Direction;
+ Character.Target = Character.Direction;
+ return base.Enter(previousState);
+ }
- private Vector2 _rollDirection = Vector2.Zero;
+ public override void Exit(IState nextState)
+ {
+ // we want to reset our state variables in case we are forced out of
+ // this state (e.g. from death)
+ _timeLeftToRoll = 0;
+ _rollDirection = Character.Direction;
+ base.Exit(nextState);
+ }
- public override IState Enter(IState previousState)
+ public override CharacterState Process(double delta)
+ {
+ Character.Direction = _rollDirection;
+ if ((_timeLeftToRoll -= delta) <= 0)
{
- _timeLeftToRoll = 0.5;
- // roll the direction we were previously moving in
- _rollDirection = Character.Direction;
- Character.Target = Character.Direction;
- return base.Enter(previousState);
- }
-
- public override void Exit(IState nextState)
- {
- // we want to reset our state variables in case we are forced out of
- // this state (e.g. from death)
- _timeLeftToRoll = 0;
- _rollDirection = Character.Direction;
- base.Exit(nextState);
- }
-
- public override CharacterState Process(double delta)
- {
- Character.Direction = _rollDirection;
- if ((_timeLeftToRoll -= delta) <= 0)
- {
- return IdleState;
- }
- return null;
+ return IdleState;
}
+ return null;
}
}
diff --git a/State/Character/PlayerState.cs b/State/Character/PlayerState.cs
index f2ce8c7..648d2e7 100644
--- a/State/Character/PlayerState.cs
+++ b/State/Character/PlayerState.cs
@@ -1,72 +1,71 @@
using Godot;
using SupaLidlGame.Characters;
-namespace SupaLidlGame.State.Character
+namespace SupaLidlGame.State.Character;
+
+public abstract partial class PlayerState : CharacterState
{
- public abstract partial class PlayerState : CharacterState
+ protected Player _player => Character as Player;
+
+ [Export]
+ public PlayerIdleState IdleState { get; set; }
+
+ public override CharacterState Input(InputEvent @event)
{
- protected Player _player => Character as Player;
+ var inventory = Character.Inventory;
- [Export]
- public PlayerIdleState IdleState { get; set; }
-
- public override CharacterState Input(InputEvent @event)
+ if (this is PlayerIdleState or PlayerMoveState &&
+ !_player.Inventory.IsUsingItem)
{
- var inventory = Character.Inventory;
-
- if (this is PlayerIdleState or PlayerMoveState &&
- !_player.Inventory.IsUsingItem)
+ if (@event.IsActionPressed("equip_1"))
{
- if (@event.IsActionPressed("equip_1"))
- {
- inventory.SelectedItem = inventory.GetItemByMap("equip_1");
- }
+ inventory.SelectedItem = inventory.GetItemByMap("equip_1");
}
-
- return base.Input(@event);
}
- public override CharacterState Process(double delta)
+ return base.Input(@event);
+ }
+
+ public override CharacterState Process(double delta)
+ {
+ Character.Direction = Godot.Input.GetVector("ui_left", "ui_right",
+ "ui_up", "ui_down");
+ Character.LookTowardsDirection();
+
+ Vector2 mousePos = Character.GetGlobalMousePosition();
+ Vector2 dirToMouse = Character.GlobalPosition.DirectionTo(mousePos);
+
+ bool targetTowards(Items.Item item)
{
- Character.Direction = Godot.Input.GetVector("ui_left", "ui_right",
- "ui_up", "ui_down");
- Character.LookTowardsDirection();
-
- Vector2 mousePos = Character.GetGlobalMousePosition();
- Vector2 dirToMouse = Character.GlobalPosition.DirectionTo(mousePos);
-
- bool targetTowards(Items.Item item)
+ if (Character.Inventory.SelectedItem is Items.Weapon weapon)
{
- if (Character.Inventory.SelectedItem is Items.Weapon weapon)
+ if (!weapon.IsUsing)
{
- if (!weapon.IsUsing)
+ var isPressed = Godot.Input.IsActionPressed("attack1");
+ var ret = false;
+
+ if (!weapon.ShouldHideIdle || isPressed)
{
- var isPressed = Godot.Input.IsActionPressed("attack1");
- var ret = false;
-
- if (!weapon.ShouldHideIdle || isPressed)
- {
- Character.Target = dirToMouse;
- ret = true;
- }
-
- if (isPressed)
- {
- Character.UseCurrentItem();
- }
-
- return ret;
+ Character.Target = dirToMouse;
+ ret = true;
}
+
+ if (isPressed)
+ {
+ Character.UseCurrentItem();
+ }
+
+ return ret;
}
- return false;
}
-
- var item = Character.Inventory.SelectedItem;
- var offhand = Character.Inventory.OffhandItem;
-
- var _ = targetTowards(item) || targetTowards(offhand);
-
- return base.Process(delta);
+ return false;
}
+
+ var item = Character.Inventory.SelectedItem;
+ var offhand = Character.Inventory.OffhandItem;
+
+ var _ = targetTowards(item) || targetTowards(offhand);
+
+ return base.Process(delta);
}
}
diff --git a/State/IState.cs b/State/IState.cs
index 2d920c3..0f301f7 100644
--- a/State/IState.cs
+++ b/State/IState.cs
@@ -1,23 +1,22 @@
-namespace SupaLidlGame.State
+namespace SupaLidlGame.State;
+
+public interface IState where T : IState
{
- public interface IState where T : IState
- {
- ///
- /// Called when this state is entered
- ///
- ///
- /// This returns a IState in case a state is being
- /// transitioned to but wants to transition to another state. For
- /// example, an attack state can return to an idle state, but that idle
- /// state can override it to the move state immediately when necessary.
- ///
- public IState Enter(IState previousState);
+ ///
+ /// Called when this state is entered
+ ///
+ ///
+ /// This returns a IState in case a state is being
+ /// transitioned to but wants to transition to another state. For
+ /// example, an attack state can return to an idle state, but that idle
+ /// state can override it to the move state immediately when necessary.
+ ///
+ public IState Enter(IState previousState);
- ///
- /// Called when the Character exits this CharacterState.
- ///
- public void Exit(IState nextState);
+ ///
+ /// Called when the Character exits this CharacterState.
+ ///
+ public void Exit(IState nextState);
- public IState Process(double delta) => null;
- }
+ public IState Process(double delta) => null;
}
diff --git a/State/StateMachine.cs b/State/StateMachine.cs
index 99b9349..e204cc9 100644
--- a/State/StateMachine.cs
+++ b/State/StateMachine.cs
@@ -1,41 +1,40 @@
using Godot;
-namespace SupaLidlGame.State
+namespace SupaLidlGame.State;
+
+public abstract partial class StateMachine : Node where T : IState
{
- public abstract partial class StateMachine : Node where T : IState
+ public T CurrentState { get; protected set; }
+
+ public abstract T InitialState { get; set; }
+
+ public override void _Ready()
{
- public T CurrentState { get; protected set; }
+ ChangeState(InitialState);
+ }
- public abstract T InitialState { get; set; }
-
- public override void _Ready()
+ public virtual bool ChangeState(T nextState, bool isProxied = false)
+ {
+ if (nextState is null)
{
- ChangeState(InitialState);
+ return false;
}
- public virtual bool ChangeState(T nextState, bool isProxied = false)
+ if (CurrentState is not null)
{
- if (nextState is null)
- {
- return false;
- }
-
- if (CurrentState is not null)
- {
- CurrentState.Exit(nextState);
- }
-
- CurrentState = nextState;
-
- // if the next state decides it should enter a different state,
- // then we enter that different state instead
- var nextNextState = nextState.Enter(CurrentState);
- if (nextNextState is T t)
- {
- return ChangeState(t, true);
- }
-
- return true;
+ CurrentState.Exit(nextState);
}
+
+ CurrentState = nextState;
+
+ // if the next state decides it should enter a different state,
+ // then we enter that different state instead
+ var nextNextState = nextState.Enter(CurrentState);
+ if (nextNextState is T t)
+ {
+ return ChangeState(t, true);
+ }
+
+ return true;
}
}
diff --git a/State/Weapon/RangedFireState.cs b/State/Weapon/RangedFireState.cs
index 3758672..de65088 100644
--- a/State/Weapon/RangedFireState.cs
+++ b/State/Weapon/RangedFireState.cs
@@ -1,38 +1,37 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class RangedFireState : WeaponState
{
- public partial class RangedFireState : WeaponState
+ [Export]
+ public Items.Weapons.Ranged Weapon { get; set; }
+
+ [Export]
+ public RangedIdleState IdleState { get; set; }
+
+ private double _timeLeft = 0;
+
+ public override IState Enter(IState prev)
{
- [Export]
- public Items.Weapons.Ranged Weapon { get; set; }
+ //_timeLeft
+ _timeLeft = Weapon.UseTime;
+ Weapon.Attack();
+ Weapon.UseDirection = Weapon.Character.Target;
+ return null;
+ }
- [Export]
- public RangedIdleState IdleState { get; set; }
-
- private double _timeLeft = 0;
-
- public override IState Enter(IState prev)
+ public override WeaponState Process(double delta)
+ {
+ if ((_timeLeft -= delta) <= 0)
{
- //_timeLeft
- _timeLeft = Weapon.UseTime;
- Weapon.Attack();
- Weapon.UseDirection = Weapon.Character.Target;
- return null;
+ return IdleState;
}
+ return null;
+ }
- public override WeaponState Process(double delta)
- {
- if ((_timeLeft -= delta) <= 0)
- {
- return IdleState;
- }
- return null;
- }
+ public override void Exit(IState nextState)
+ {
- public override void Exit(IState nextState)
- {
-
- }
}
}
diff --git a/State/Weapon/RangedIdleState.cs b/State/Weapon/RangedIdleState.cs
index 3a26eff..e887307 100644
--- a/State/Weapon/RangedIdleState.cs
+++ b/State/Weapon/RangedIdleState.cs
@@ -1,29 +1,28 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class RangedIdleState : WeaponState
{
- public partial class RangedIdleState : WeaponState
+ [Export]
+ public RangedFireState FireState { get; set; }
+
+ [Export]
+ public Items.Weapons.Ranged Weapon { get; set; }
+
+ public override IState Enter(IState prev)
{
- [Export]
- public RangedFireState FireState { get; set; }
+ Weapon.Visible = !Weapon.ShouldHideIdle;
+ return null;
+ }
- [Export]
- public Items.Weapons.Ranged Weapon { get; set; }
+ public override WeaponState Use()
+ {
+ return FireState;
+ }
- public override IState Enter(IState prev)
- {
- Weapon.Visible = !Weapon.ShouldHideIdle;
- return null;
- }
-
- public override WeaponState Use()
- {
- return FireState;
- }
-
- public override void Exit(IState nextState)
- {
- Weapon.Visible = true;
- }
+ public override void Exit(IState nextState)
+ {
+ Weapon.Visible = true;
}
}
diff --git a/State/Weapon/SwordAnticipateState.cs b/State/Weapon/SwordAnticipateState.cs
index a40ef3b..f393a65 100644
--- a/State/Weapon/SwordAnticipateState.cs
+++ b/State/Weapon/SwordAnticipateState.cs
@@ -1,46 +1,45 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class SwordAnticipateState : WeaponState
{
- public partial class SwordAnticipateState : WeaponState
+ [Export]
+ public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
+
+ [Export]
+ public SwordAttackState AttackState { get; set; }
+
+ private double _anticipateTime;
+
+ public override WeaponState Enter(IState prevState)
{
- [Export]
- public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
-
- [Export]
- public SwordAttackState AttackState { get; set; }
+ Sword.EnableParry();
- private double _anticipateTime;
-
- public override WeaponState Enter(IState prevState)
+ if (Sword.Character is SupaLidlGame.Characters.Player)
{
- Sword.EnableParry();
-
- if (Sword.Character is SupaLidlGame.Characters.Player)
- {
- return AttackState;
- }
-
- if (Sword.Anchor.Rotation > Mathf.DegToRad(50))
- {
- Sword.AnimationPlayer.Play("anticipate_alternate");
- }
- else
- {
- Sword.AnimationPlayer.Play("anticipate");
- }
- _anticipateTime = Sword.NPCAnticipateTime;
- return null;
+ return AttackState;
}
- public override WeaponState Process(double delta)
+ if (Sword.Anchor.Rotation > Mathf.DegToRad(50))
{
- // go into attack state if anticipation time is delta
- if ((_anticipateTime -= delta) <= 0)
- {
- return AttackState;
- }
- return null;
+ Sword.AnimationPlayer.Play("anticipate_alternate");
}
+ else
+ {
+ Sword.AnimationPlayer.Play("anticipate");
+ }
+ _anticipateTime = Sword.NPCAnticipateTime;
+ return null;
+ }
+
+ public override WeaponState Process(double delta)
+ {
+ // go into attack state if anticipation time is delta
+ if ((_anticipateTime -= delta) <= 0)
+ {
+ return AttackState;
+ }
+ return null;
}
}
diff --git a/State/Weapon/SwordAttackState.cs b/State/Weapon/SwordAttackState.cs
index 90d133e..11014c7 100644
--- a/State/Weapon/SwordAttackState.cs
+++ b/State/Weapon/SwordAttackState.cs
@@ -1,89 +1,88 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class SwordAttackState : WeaponState
{
- public partial class SwordAttackState : WeaponState
+ [Export]
+ public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
+
+ [Export]
+ public SwordAnticipateState AnticipateState { get; set; }
+
+ [Export]
+ public SwordIdleState IdleState { get; set; }
+
+ private double _attackDuration = 0;
+
+ private double _useDuration = 0;
+
+ private double _attackAnimDuration = 0;
+
+ private bool _isAlternate = false;
+
+ public override WeaponState Enter(IState prevState)
{
- [Export]
- public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
+ //Sword.AnimationPlayer.Stop();
+ Sword.Attack();
- [Export]
- public SwordAnticipateState AnticipateState { get; set; }
-
- [Export]
- public SwordIdleState IdleState { get; set; }
-
- private double _attackDuration = 0;
-
- private double _useDuration = 0;
-
- private double _attackAnimDuration = 0;
-
- private bool _isAlternate = false;
-
- public override WeaponState Enter(IState prevState)
+ if (_isAlternate)
{
- //Sword.AnimationPlayer.Stop();
- Sword.Attack();
-
- if (_isAlternate)
- {
- Sword.AnimationPlayer.Play("attack_alternate");
- }
- else
- {
- Sword.AnimationPlayer.Play("attack");
- }
-
- _attackDuration = Sword.AttackTime;
- _useDuration = Sword.UseTime;
- _attackAnimDuration = Sword.AttackAnimationDuration;
-
- Sword.Visible = true;
- Sword.UseDirection = Sword.Character.Target;
- return null;
+ Sword.AnimationPlayer.Play("attack_alternate");
+ }
+ else
+ {
+ Sword.AnimationPlayer.Play("attack");
}
- public override void Exit(IState nextState)
+ _attackDuration = Sword.AttackTime;
+ _useDuration = Sword.UseTime;
+ _attackAnimDuration = Sword.AttackAnimationDuration;
+
+ Sword.Visible = true;
+ Sword.UseDirection = Sword.Character.Target;
+ return null;
+ }
+
+ public override void Exit(IState nextState)
+ {
+ Sword.Deattack();
+ }
+
+ public override WeaponState Use()
+ {
+ if (_useDuration <= 0)
{
- Sword.Deattack();
+ // if we are still playing the current attack animation, we should alternate
+ if (_attackAnimDuration > 0)
+ {
+ _isAlternate = !_isAlternate;
+ }
+ return IdleState;
}
- public override WeaponState Use()
- {
- if (_useDuration <= 0)
- {
- // if we are still playing the current attack animation, we should alternate
- if (_attackAnimDuration > 0)
- {
- _isAlternate = !_isAlternate;
- }
- return IdleState;
- }
+ return null;
+ }
- return null;
+ public override WeaponState Process(double delta)
+ {
+ if (_attackDuration > 0)
+ {
+ if ((_attackDuration -= delta) <= 0)
+ {
+ Sword.Deattack();
+ }
}
- public override WeaponState Process(double delta)
+ if ((_attackAnimDuration -= delta) <= 0)
{
- if (_attackDuration > 0)
- {
- if ((_attackDuration -= delta) <= 0)
- {
- Sword.Deattack();
- }
- }
-
- if ((_attackAnimDuration -= delta) <= 0)
- {
- Sword.AnimationPlayer.Play("RESET");
- _isAlternate = false;
- return IdleState;
- }
-
- _useDuration -= delta;
-
- return null;
+ Sword.AnimationPlayer.Play("RESET");
+ _isAlternate = false;
+ return IdleState;
}
+
+ _useDuration -= delta;
+
+ return null;
}
}
diff --git a/State/Weapon/SwordIdleState.cs b/State/Weapon/SwordIdleState.cs
index 1f5b862..bcaf07e 100644
--- a/State/Weapon/SwordIdleState.cs
+++ b/State/Weapon/SwordIdleState.cs
@@ -1,52 +1,51 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class SwordIdleState : WeaponState
{
- public partial class SwordIdleState : WeaponState
+ [Export]
+ public SwordAnticipateState AnticipateState { get; set; }
+
+ [Export]
+ public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
+
+ private double _attackCooldown;
+
+ public override WeaponState Enter(IState prevState)
{
- [Export]
- public SwordAnticipateState AnticipateState { get; set; }
-
- [Export]
- public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
-
- private double _attackCooldown;
-
- public override WeaponState Enter(IState prevState)
+ if (prevState is SwordAttackState)
{
- if (prevState is SwordAttackState)
- {
- _attackCooldown = Sword.UseTime - Sword.AttackTime;
- }
-
- Sword.Visible = !Sword.ShouldHideIdle;
-
- return null;
+ _attackCooldown = Sword.UseTime - Sword.AttackTime;
}
- public override void Exit(IState nextState)
- {
- Sword.Visible = true;
- }
+ Sword.Visible = !Sword.ShouldHideIdle;
- public override WeaponState Use()
- {
- if (_attackCooldown <= 0)
- {
- return AnticipateState;
- }
+ return null;
+ }
+ public override void Exit(IState nextState)
+ {
+ Sword.Visible = true;
+ }
+
+ public override WeaponState Use()
+ {
+ if (_attackCooldown <= 0)
+ {
return AnticipateState;
}
- public override WeaponState Process(double delta)
- {
- if (_attackCooldown > 0)
- {
- _attackCooldown -= delta;
- }
+ return AnticipateState;
+ }
- return null;
+ public override WeaponState Process(double delta)
+ {
+ if (_attackCooldown > 0)
+ {
+ _attackCooldown -= delta;
}
+
+ return null;
}
}
diff --git a/State/Weapon/WeaponState.cs b/State/Weapon/WeaponState.cs
index 2a817e3..e57582f 100644
--- a/State/Weapon/WeaponState.cs
+++ b/State/Weapon/WeaponState.cs
@@ -1,20 +1,19 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public abstract partial class WeaponState : Node, IState
{
- public abstract partial class WeaponState : Node, IState
+ public virtual WeaponState Use() => null;
+
+ public virtual WeaponState Deuse() => null;
+
+ public abstract IState Enter(IState previousState);
+
+ public virtual void Exit(IState nextState)
{
- public virtual WeaponState Use() => null;
- public virtual WeaponState Deuse() => null;
-
- public abstract IState Enter(IState previousState);
-
- public virtual void Exit(IState nextState)
- {
-
- }
-
- public virtual IState Process(double delta) => null;
}
+
+ public virtual IState Process(double delta) => null;
}
diff --git a/State/Weapon/WeaponStateMachine.cs b/State/Weapon/WeaponStateMachine.cs
index 223693b..aefb826 100644
--- a/State/Weapon/WeaponStateMachine.cs
+++ b/State/Weapon/WeaponStateMachine.cs
@@ -1,37 +1,36 @@
using Godot;
-namespace SupaLidlGame.State.Weapon
+namespace SupaLidlGame.State.Weapon;
+
+public partial class WeaponStateMachine : StateMachine
{
- public partial class WeaponStateMachine : StateMachine
+ [Export]
+ public override WeaponState InitialState { get; set; }
+
+ public void Use()
{
- [Export]
- public override WeaponState InitialState { get; set; }
-
- public void Use()
+ var state = CurrentState.Use();
+ if (state is WeaponState)
{
- var state = CurrentState.Use();
- if (state is WeaponState)
- {
- ChangeState(state);
- }
+ ChangeState(state);
}
+ }
- public void Deuse()
+ public void Deuse()
+ {
+ var state = CurrentState.Deuse();
+ if (state is WeaponState)
{
- var state = CurrentState.Deuse();
- if (state is WeaponState)
- {
- ChangeState(state);
- }
+ ChangeState(state);
}
+ }
- public void Process(double delta)
+ public void Process(double delta)
+ {
+ var state = CurrentState.Process(delta);
+ if (state is WeaponState s)
{
- var state = CurrentState.Process(delta);
- if (state is WeaponState s)
- {
- ChangeState(s);
- }
+ ChangeState(s);
}
}
}
diff --git a/Tests/ContextBasedSteering.cs b/Tests/ContextBasedSteering.cs
index 17354c7..5d3d611 100644
--- a/Tests/ContextBasedSteering.cs
+++ b/Tests/ContextBasedSteering.cs
@@ -2,57 +2,56 @@ using Godot;
using SupaLidlGame.Extensions;
using System;
-namespace SupaLidlGame.Prototyping
+namespace SupaLidlGame.Prototyping;
+
+public partial class ContextBasedSteering : Node2D
{
- public partial class ContextBasedSteering : Node2D
+ public float PreferredDistance { get; set; } = 256.0f;
+ Vector2 _direction;
+
+ // Called when the node enters the scene tree for the first time.
+ public override void _Ready()
{
- public float PreferredDistance { get; set; } = 256.0f;
- Vector2 _direction;
+ GD.Print("Started ContextBasedSteering test");
+ }
- // Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
- GD.Print("Started ContextBasedSteering test");
- }
+ // Called every frame. 'delta' is the elapsed time since the previous frame.
+ public override void _Process(double delta)
+ {
+ _direction = GetDirection();
+ QueueRedraw();
+ }
- // Called every frame. 'delta' is the elapsed time since the previous frame.
- public override void _Process(double delta)
- {
- _direction = GetDirection();
- QueueRedraw();
- }
+ public Vector2 GetDirection()
+ {
+ float directWeight;
+ float strafeWeight;
- public Vector2 GetDirection()
- {
- float directWeight;
- float strafeWeight;
+ Vector2 towards = GetGlobalMousePosition() - GlobalPosition;
+ float dist = towards.Length();
- Vector2 towards = GetGlobalMousePosition() - GlobalPosition;
- float dist = towards.Length();
+ Vector2 directDir = towards.Normalized();
+ Vector2 strafeDir = directDir.Clockwise90();
- Vector2 directDir = towards.Normalized();
- Vector2 strafeDir = directDir.Clockwise90();
+ // weights approach 1
+ // dy/dx = 1 - y
+ // y = 1 - e^(-x)
- // weights approach 1
- // dy/dx = 1 - y
- // y = 1 - e^(-x)
+ directWeight = 1 - Mathf.Pow(Mathf.E, -(dist / PreferredDistance));
+ strafeWeight = 1 - directWeight;
- directWeight = 1 - Mathf.Pow(Mathf.E, -(dist / PreferredDistance));
- strafeWeight = 1 - directWeight;
+ /*
+ Vector2 midpoint = (strafeDir * strafeWeight)
+ .Midpoint(directDir * directWeight);
+ */
+ Vector2 midpoint = (directDir * directWeight)
+ .Midpoint(strafeDir * strafeWeight);
- /*
- Vector2 midpoint = (strafeDir * strafeWeight)
- .Midpoint(directDir * directWeight);
- */
- Vector2 midpoint = (directDir * directWeight)
- .Midpoint(strafeDir * strafeWeight);
+ return midpoint.Normalized();
+ }
- return midpoint.Normalized();
- }
-
- public override void _Draw()
- {
- DrawLine(Vector2.Zero, _direction * 256, Colors.Green);
- }
+ public override void _Draw()
+ {
+ DrawLine(Vector2.Zero, _direction * 256, Colors.Green);
}
}
diff --git a/UI/FloatingText.cs b/UI/FloatingText.cs
index b36c31c..6ccb235 100644
--- a/UI/FloatingText.cs
+++ b/UI/FloatingText.cs
@@ -1,51 +1,50 @@
using Godot;
using System;
-namespace SupaLidlGame.UI
+namespace SupaLidlGame.UI;
+
+public partial class FloatingText : Node2D
{
- public partial class FloatingText : Node2D
+ private Label _label;
+
+ [Export]
+ public string Text { get; set; }
+
+ public override void _Ready()
{
- private Label _label;
+ _label = GetNode