Merge branch 'master' into controller-support
commit
6c5bc4edac
|
@ -1,4 +1,4 @@
|
||||||
[gd_resource type="ParticleProcessMaterial" load_steps=5 format=3 uid="uid://cbfaqolx1ydvv"]
|
[gd_resource type="ParticleProcessMaterial" load_steps=7 format=3 uid="uid://cbfaqolx1ydvv"]
|
||||||
|
|
||||||
[sub_resource type="Gradient" id="Gradient_44upg"]
|
[sub_resource type="Gradient" id="Gradient_44upg"]
|
||||||
offsets = PackedFloat32Array(0, 0.5)
|
offsets = PackedFloat32Array(0, 0.5)
|
||||||
|
@ -7,16 +7,27 @@ colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
[sub_resource type="GradientTexture1D" id="GradientTexture1D_droiy"]
|
[sub_resource type="GradientTexture1D" id="GradientTexture1D_droiy"]
|
||||||
gradient = SubResource("Gradient_44upg")
|
gradient = SubResource("Gradient_44upg")
|
||||||
|
|
||||||
[sub_resource type="Curve" id="Curve_4kf4j"]
|
[sub_resource type="Curve" id="Curve_mx7gl"]
|
||||||
_data = [Vector2(0, 0.5), 0.0, 0.0, 0, 0, Vector2(0.1, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.5), 0.0, 0.0, 0, 0]
|
_data = [Vector2(0, 0.3), 0.0, 0.0, 0, 1, Vector2(1, 0.3), 0.0, 0.0, 1, 0]
|
||||||
point_count = 3
|
point_count = 2
|
||||||
|
|
||||||
[sub_resource type="CurveTexture" id="CurveTexture_qqrjb"]
|
[sub_resource type="Curve" id="Curve_lfa60"]
|
||||||
curve = SubResource("Curve_4kf4j")
|
_data = [Vector2(0.1, 1), 0.0, -1.75, 0, 1, Vector2(0.5, 0.3), -1.75, 0.0, 1, 0]
|
||||||
|
point_count = 2
|
||||||
|
|
||||||
|
[sub_resource type="Curve" id="Curve_3iug1"]
|
||||||
|
_data = [Vector2(0, 1), 0.0, 0.0, 0, 1, Vector2(1, 1), 0.0, 0.0, 1, 0]
|
||||||
|
point_count = 2
|
||||||
|
|
||||||
|
[sub_resource type="CurveXYZTexture" id="CurveXYZTexture_xryvh"]
|
||||||
|
curve_x = SubResource("Curve_mx7gl")
|
||||||
|
curve_y = SubResource("Curve_lfa60")
|
||||||
|
curve_z = SubResource("Curve_3iug1")
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
emission_shape = 1
|
emission_shape = 1
|
||||||
emission_sphere_radius = 4.0
|
emission_sphere_radius = 4.0
|
||||||
|
particle_flag_align_y = true
|
||||||
particle_flag_disable_z = true
|
particle_flag_disable_z = true
|
||||||
spread = 180.0
|
spread = 180.0
|
||||||
gravity = Vector3(0, 0, 0)
|
gravity = Vector3(0, 0, 0)
|
||||||
|
@ -26,7 +37,7 @@ orbit_velocity_min = 0.0
|
||||||
orbit_velocity_max = 0.0
|
orbit_velocity_max = 0.0
|
||||||
linear_accel_min = -512.0
|
linear_accel_min = -512.0
|
||||||
linear_accel_max = -512.0
|
linear_accel_max = -512.0
|
||||||
scale_min = 2.0
|
scale_min = 0.1
|
||||||
scale_max = 2.0
|
scale_max = 0.1
|
||||||
scale_curve = SubResource("CurveTexture_qqrjb")
|
scale_curve = SubResource("CurveXYZTexture_xryvh")
|
||||||
color_ramp = SubResource("GradientTexture1D_droiy")
|
color_ramp = SubResource("GradientTexture1D_droiy")
|
||||||
|
|
|
@ -35,7 +35,6 @@ public partial class ConnectorBox : Area2D
|
||||||
{
|
{
|
||||||
BodyEntered += (Node2D body) =>
|
BodyEntered += (Node2D body) =>
|
||||||
{
|
{
|
||||||
GD.Print(body.Name + " entered");
|
|
||||||
if (body is Player && InteractionTrigger is null)
|
if (body is Player && InteractionTrigger is null)
|
||||||
{
|
{
|
||||||
OnInteraction();
|
OnInteraction();
|
||||||
|
|
|
@ -11,6 +11,7 @@ public partial class Hurtbox : BoundingBox, IFaction
|
||||||
float damage,
|
float damage,
|
||||||
Character inflictor,
|
Character inflictor,
|
||||||
float knockback,
|
float knockback,
|
||||||
|
Items.Weapon weapon = null,
|
||||||
Vector2 knockbackDir = default);
|
Vector2 knockbackDir = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -30,7 +31,6 @@ public partial class Hurtbox : BoundingBox, IFaction
|
||||||
{
|
{
|
||||||
InvincibilityTimer.Timeout += () =>
|
InvincibilityTimer.Timeout += () =>
|
||||||
{
|
{
|
||||||
GD.Print("invincibility off");
|
|
||||||
Monitorable = true;
|
Monitorable = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public partial class Hurtbox : BoundingBox, IFaction
|
||||||
float damage,
|
float damage,
|
||||||
Character inflictor,
|
Character inflictor,
|
||||||
float knockback,
|
float knockback,
|
||||||
|
Items.Weapon weapon = default,
|
||||||
Vector2 knockbackOrigin = default,
|
Vector2 knockbackOrigin = default,
|
||||||
Vector2 knockbackVector = default)
|
Vector2 knockbackVector = default)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +78,6 @@ public partial class Hurtbox : BoundingBox, IFaction
|
||||||
InvincibilityTimer.Start();
|
InvincibilityTimer.Start();
|
||||||
//Monitorable = false;
|
//Monitorable = false;
|
||||||
SetDeferred("monitorable", false);
|
SetDeferred("monitorable", false);
|
||||||
GD.Print("invincible");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitSignal(
|
EmitSignal(
|
||||||
|
@ -85,6 +85,7 @@ public partial class Hurtbox : BoundingBox, IFaction
|
||||||
damage,
|
damage,
|
||||||
inflictor,
|
inflictor,
|
||||||
knockback,
|
knockback,
|
||||||
|
weapon,
|
||||||
knockbackDir);
|
knockbackDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,6 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export]
|
|
||||||
public float Stealth { get; protected set; } = 0;
|
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void HealthChangedEventHandler(Events.HealthChangedArgs args);
|
public delegate void HealthChangedEventHandler(Events.HealthChangedArgs args);
|
||||||
|
|
||||||
|
@ -168,6 +165,9 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the <c>Character</c>'s death.
|
||||||
|
/// </summary>
|
||||||
public virtual void Die()
|
public virtual void Die()
|
||||||
{
|
{
|
||||||
if (HurtAnimation.HasAnimation("death"))
|
if (HurtAnimation.HasAnimation("death"))
|
||||||
|
@ -190,11 +190,20 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
NetImpulse += impulse / Mass;
|
NetImpulse += impulse / Mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stuns the <c>Chararacter</c> for an amount of time. If
|
||||||
|
/// <paramref name="time"/> is less than the <c>Character</c>'s current
|
||||||
|
/// stun time left, it will have no effect.
|
||||||
|
/// </summary>
|
||||||
public virtual void Stun(float time)
|
public virtual void Stun(float time)
|
||||||
{
|
{
|
||||||
StunTime = Mathf.Max(time, StunTime);
|
StunTime = Mathf.Max(time, StunTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws the character so that its sprite and inventory items face the
|
||||||
|
/// character's direction.
|
||||||
|
/// </summary>
|
||||||
protected virtual void DrawTarget()
|
protected virtual void DrawTarget()
|
||||||
{
|
{
|
||||||
Vector2 target = Target;
|
Vector2 target = Target;
|
||||||
|
@ -213,6 +222,10 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
Inventory.Rotation = angle;
|
Inventory.Rotation = angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use the current item the character is using. Prefer to call this over
|
||||||
|
/// <c>Item.Use</c> as it will check if the character is stunned or alive.
|
||||||
|
/// </summary>
|
||||||
public void UseCurrentItem()
|
public void UseCurrentItem()
|
||||||
{
|
{
|
||||||
if (StunTime > 0 || !IsAlive)
|
if (StunTime > 0 || !IsAlive)
|
||||||
|
@ -264,6 +277,9 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override this method to modify the damage the character takes.
|
||||||
|
/// </summary>
|
||||||
protected virtual float ReceiveDamage(
|
protected virtual float ReceiveDamage(
|
||||||
float damage,
|
float damage,
|
||||||
Character inflictor,
|
Character inflictor,
|
||||||
|
@ -285,10 +301,14 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
_curDamageText.ShowText();
|
_curDamageText.ShowText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the character taking damage.
|
||||||
|
/// </summary>
|
||||||
protected virtual void OnReceivedDamage(
|
protected virtual void OnReceivedDamage(
|
||||||
float damage,
|
float damage,
|
||||||
Character inflictor,
|
Character inflictor,
|
||||||
float knockback,
|
float knockback,
|
||||||
|
Weapon weapon = null,
|
||||||
Vector2 knockbackDir = default)
|
Vector2 knockbackDir = default)
|
||||||
{
|
{
|
||||||
if (Health <= 0)
|
if (Health <= 0)
|
||||||
|
@ -325,7 +345,6 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
if (this.GetNode("Effects/HurtSound") is AudioStreamPlayer2D sound)
|
if (this.GetNode("Effects/HurtSound") is AudioStreamPlayer2D sound)
|
||||||
{
|
{
|
||||||
// very small pitch deviation
|
// very small pitch deviation
|
||||||
GD.Print("hurt sound");
|
|
||||||
sound.At(GlobalPosition).WithPitchDeviation(0.125f).PlayOneShot();
|
sound.At(GlobalPosition).WithPitchDeviation(0.125f).PlayOneShot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,11 +353,17 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
Attacker = inflictor,
|
Attacker = inflictor,
|
||||||
OldHealth = oldHealth,
|
OldHealth = oldHealth,
|
||||||
NewHealth = Health,
|
NewHealth = Health,
|
||||||
|
Weapon = weapon,
|
||||||
Damage = damage,
|
Damage = damage,
|
||||||
};
|
};
|
||||||
|
|
||||||
EmitSignal(SignalName.Hurt, args);
|
EmitSignal(SignalName.Hurt, args);
|
||||||
|
|
||||||
|
if (inflictor is Player)
|
||||||
|
{
|
||||||
|
EmitPlayerHitSignal(args);
|
||||||
|
}
|
||||||
|
|
||||||
if (Health <= 0)
|
if (Health <= 0)
|
||||||
{
|
{
|
||||||
EmitSignal(SignalName.Death, args);
|
EmitSignal(SignalName.Death, args);
|
||||||
|
@ -348,6 +373,26 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a HurtArgs to HitArgs if the attacker was a player and emits
|
||||||
|
/// the <c>EventBus.PlayerHit</c> signal.
|
||||||
|
/// </summary>
|
||||||
|
private void EmitPlayerHitSignal(Events.HurtArgs args)
|
||||||
|
{
|
||||||
|
var newArgs = new Events.HitArgs
|
||||||
|
{
|
||||||
|
OldHealth = args.OldHealth,
|
||||||
|
NewHealth = args.NewHealth,
|
||||||
|
Damage = args.Damage,
|
||||||
|
Weapon = args.Weapon,
|
||||||
|
Victim = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
var bus = Events.EventBus.Instance;
|
||||||
|
bus.EmitSignal(Events.EventBus.SignalName.PlayerHit, newArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For debugging purposes
|
/// For debugging purposes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -355,7 +400,12 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
{
|
{
|
||||||
OnReceivedDamage(damage, null, 0);
|
OnReceivedDamage(damage, null, 0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Plays a footstep sound. This should be called through an
|
||||||
|
/// <c>AnimationPlayer</c> to sync sounds with animations.
|
||||||
|
/// </summary>
|
||||||
public virtual void Footstep()
|
public virtual void Footstep()
|
||||||
{
|
{
|
||||||
if (GetNode("Effects/Footstep") is AudioStreamPlayer2D player)
|
if (GetNode("Effects/Footstep") is AudioStreamPlayer2D player)
|
||||||
|
@ -364,6 +414,15 @@ public partial class Character : CharacterBody2D, IFaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the <c>Character</c> has line of sight with
|
||||||
|
/// <paramref name="character"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character">The character to check for LOS</param>
|
||||||
|
/// <param name="excludeClip">
|
||||||
|
/// Determines whether the raycast should pass through world clips (physics
|
||||||
|
/// layer 5)
|
||||||
|
/// </param>
|
||||||
public bool HasLineOfSight(Character character, bool excludeClip = false)
|
public bool HasLineOfSight(Character character, bool excludeClip = false)
|
||||||
{
|
{
|
||||||
var exclude = new Godot.Collections.Array<Godot.Rid>();
|
var exclude = new Godot.Collections.Array<Godot.Rid>();
|
||||||
|
|
|
@ -96,29 +96,9 @@ public partial class NPC : Character
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Draw()
|
/// <summary>
|
||||||
{
|
/// Finds the NPC's best character to target.
|
||||||
#if DEBUG
|
/// </summary>
|
||||||
for (int i = 0; i < 16; 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);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
base._Draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Character FindBestTarget()
|
public virtual Character FindBestTarget()
|
||||||
{
|
{
|
||||||
float bestScore = float.MaxValue;
|
float bestScore = float.MaxValue;
|
||||||
|
@ -136,21 +116,9 @@ public partial class NPC : Character
|
||||||
|
|
||||||
float score = 0;
|
float score = 0;
|
||||||
score += Position.DistanceTo(character.Position);
|
score += Position.DistanceTo(character.Position);
|
||||||
score *= (character.Stealth + 1);
|
|
||||||
|
|
||||||
// if the character has enough stealth, the dot product of the
|
|
||||||
// enemy's current direction and to the character will affect
|
|
||||||
// the score
|
|
||||||
// TODO: implement
|
|
||||||
|
|
||||||
if (score < bestScore)
|
if (score < bestScore)
|
||||||
{
|
{
|
||||||
// if the character has enough stealth, they won't be
|
|
||||||
// targeted if the NPC is not able to see
|
|
||||||
if (!HasLineOfSight(character) && character.Stealth >= 1)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bestScore = score;
|
bestScore = score;
|
||||||
bestChar = character;
|
bestChar = character;
|
||||||
}
|
}
|
||||||
|
@ -170,132 +138,4 @@ public partial class NPC : Character
|
||||||
ThinkerStateMachine.PhysicsProcess(delta);
|
ThinkerStateMachine.PhysicsProcess(delta);
|
||||||
base._PhysicsProcess(delta);
|
base._PhysicsProcess(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ThinkProcess(double delta)
|
|
||||||
{
|
|
||||||
if ((_thinkTimeElapsed += delta) > ThinkTime)
|
|
||||||
{
|
|
||||||
_thinkTimeElapsed = 0;
|
|
||||||
Think();
|
|
||||||
#if DEBUG_NPC
|
|
||||||
QueueRedraw();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ShouldMove || (!ShouldMoveWhenUsingItem && Inventory.IsUsingItem))
|
|
||||||
{
|
|
||||||
Direction = Vector2.Zero;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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<Godot.Rid>();
|
|
||||||
exclude.Add(this.GetRid());
|
|
||||||
|
|
||||||
// calculate weights based on distance
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
};
|
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
if (i == j)
|
|
||||||
{
|
|
||||||
_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 < 1600 && CanAttack)
|
|
||||||
{
|
|
||||||
if (Inventory.SelectedItem is Weapon weapon)
|
|
||||||
{
|
|
||||||
UseCurrentItem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ public sealed partial class Player : Character
|
||||||
{
|
{
|
||||||
private string _spriteAnim;
|
private string _spriteAnim;
|
||||||
|
|
||||||
|
public Vector2 DesiredTarget { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public PlayerCamera Camera { get; set; }
|
public PlayerCamera Camera { get; set; }
|
||||||
|
|
||||||
|
@ -25,11 +27,6 @@ public sealed partial class Player : Character
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
InteractionRay = GetNode<InteractionRay>("Direction2D/InteractionRay");
|
InteractionRay = GetNode<InteractionRay>("Direction2D/InteractionRay");
|
||||||
Death += async (Events.HurtArgs args) =>
|
|
||||||
{
|
|
||||||
HurtAnimation.Play("death");
|
|
||||||
await ToSignal(HurtAnimation, "animation_finished");
|
|
||||||
};
|
|
||||||
|
|
||||||
base._Ready();
|
base._Ready();
|
||||||
|
|
||||||
|
@ -51,10 +48,6 @@ public sealed partial class Player : Character
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
|
|
||||||
var mod = Sprite.SelfModulate;
|
|
||||||
mod.A = 1 - (Stealth / 2);
|
|
||||||
Sprite.SelfModulate = mod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Input(InputEvent @event)
|
public override void _Input(InputEvent @event)
|
||||||
|
@ -65,6 +58,9 @@ public sealed partial class Player : Character
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Respawns the player with full health and plays spawn animation
|
||||||
|
/// </summary>
|
||||||
public void Spawn()
|
public void Spawn()
|
||||||
{
|
{
|
||||||
Health = 100;
|
Health = 100;
|
||||||
|
@ -87,6 +83,7 @@ public sealed partial class Player : Character
|
||||||
float damage,
|
float damage,
|
||||||
Character inflictor,
|
Character inflictor,
|
||||||
float knockback,
|
float knockback,
|
||||||
|
Items.Weapon weapon = null,
|
||||||
Vector2 knockbackDir = default)
|
Vector2 knockbackDir = default)
|
||||||
{
|
{
|
||||||
if (damage >= 10 && IsAlive)
|
if (damage >= 10 && IsAlive)
|
||||||
|
@ -97,21 +94,22 @@ public sealed partial class Player : Character
|
||||||
GetNode<GpuParticles2D>("Effects/HurtParticles")
|
GetNode<GpuParticles2D>("Effects/HurtParticles")
|
||||||
.SetDirection(knockbackDir);
|
.SetDirection(knockbackDir);
|
||||||
|
|
||||||
base.OnReceivedDamage(damage, inflictor, knockback, knockbackDir);
|
base.OnReceivedDamage(damage,
|
||||||
|
inflictor,
|
||||||
|
knockback,
|
||||||
|
weapon,
|
||||||
|
knockbackDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Die()
|
public override void Die()
|
||||||
{
|
{
|
||||||
GD.Print("died");
|
HurtAnimation.Play("death");
|
||||||
//base.Die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DrawTarget()
|
protected override void DrawTarget()
|
||||||
{
|
{
|
||||||
base.DrawTarget();
|
base.DrawTarget();
|
||||||
DirectionMarker.GlobalRotation = DirectionMarker.GlobalPosition
|
DirectionMarker.GlobalRotation = DesiredTarget.Angle();
|
||||||
.DirectionTo(GetGlobalMousePosition())
|
|
||||||
.Angle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Footstep()
|
public override void Footstep()
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
[gd_scene load_steps=63 format=3 uid="uid://b2254pup8k161"]
|
[gd_scene load_steps=66 format=3 uid="uid://b2254pup8k161"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
|
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
|
||||||
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_ngsgt"]
|
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_ngsgt"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dpepm54hjuyga" path="res://Assets/Sprites/Characters/forsen-hand.png" id="3_3dqh7"]
|
[ext_resource type="Texture2D" uid="uid://dpepm54hjuyga" path="res://Assets/Sprites/Characters/forsen-hand.png" id="3_3dqh7"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bej8thq7ruyty" path="res://Assets/Sprites/Characters/forsen2.png" id="4_5vird"]
|
[ext_resource type="Texture2D" uid="uid://bej8thq7ruyty" path="res://Assets/Sprites/Characters/forsen2.png" id="4_5vird"]
|
||||||
|
[ext_resource type="Script" path="res://Utils/PlayerStats.cs" id="4_06oya"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cl56eadpklnbo" path="res://Utils/PlayerCamera.tscn" id="4_ym125"]
|
[ext_resource type="PackedScene" uid="uid://cl56eadpklnbo" path="res://Utils/PlayerCamera.tscn" id="4_ym125"]
|
||||||
[ext_resource type="Script" path="res://State/Character/CharacterStateMachine.cs" id="5_rgckv"]
|
[ext_resource type="Script" path="res://State/Character/CharacterStateMachine.cs" id="5_rgckv"]
|
||||||
|
[ext_resource type="Script" path="res://Utils/Values/DoubleValue.cs" id="5_txl0r"]
|
||||||
[ext_resource type="Script" path="res://State/Character/CharacterDashState.cs" id="6_rft7p"]
|
[ext_resource type="Script" path="res://State/Character/CharacterDashState.cs" id="6_rft7p"]
|
||||||
|
[ext_resource type="Script" path="res://Utils/Values/IntValue.cs" id="6_sunc5"]
|
||||||
[ext_resource type="Script" path="res://State/Character/PlayerIdleState.cs" id="6_wkfdm"]
|
[ext_resource type="Script" path="res://State/Character/PlayerIdleState.cs" id="6_wkfdm"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dvqap2uhcah63" path="res://Items/Weapons/Sword.tscn" id="7_4rxuv"]
|
[ext_resource type="PackedScene" uid="uid://dvqap2uhcah63" path="res://Items/Weapons/Sword.tscn" id="7_4rxuv"]
|
||||||
[ext_resource type="Script" path="res://State/Character/PlayerMoveState.cs" id="7_dfqd8"]
|
[ext_resource type="Script" path="res://State/Character/PlayerMoveState.cs" id="7_dfqd8"]
|
||||||
|
@ -331,6 +334,15 @@ StateMachine = NodePath("StateMachine")
|
||||||
Hurtbox = NodePath("Hurtbox")
|
Hurtbox = NodePath("Hurtbox")
|
||||||
Faction = 1
|
Faction = 1
|
||||||
|
|
||||||
|
[node name="Stats" type="Node" parent="."]
|
||||||
|
script = ExtResource("4_06oya")
|
||||||
|
|
||||||
|
[node name="XP" type="Node" parent="Stats"]
|
||||||
|
script = ExtResource("5_txl0r")
|
||||||
|
|
||||||
|
[node name="Level" type="Node" parent="Stats"]
|
||||||
|
script = ExtResource("6_sunc5")
|
||||||
|
|
||||||
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
|
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
|
||||||
script = ExtResource("5_rgckv")
|
script = ExtResource("5_rgckv")
|
||||||
InitialState = NodePath("Idle")
|
InitialState = NodePath("Idle")
|
||||||
|
|
|
@ -71,7 +71,6 @@ public partial class DynamicDoor : StaticBody2D
|
||||||
{
|
{
|
||||||
if (anim.TrackGetPath(i) == nodePath)
|
if (anim.TrackGetPath(i) == nodePath)
|
||||||
{
|
{
|
||||||
GD.Print($"Disabled anim for {nodePath}");
|
|
||||||
anim.TrackSetEnabled(i, isEnabled);
|
anim.TrackSetEnabled(i, isEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,11 @@ public partial class Projectile : RigidBody2D
|
||||||
[Export]
|
[Export]
|
||||||
public double Delay { get; set; } = 0;
|
public double Delay { get; set; } = 0;
|
||||||
|
|
||||||
|
[System.Obsolete]
|
||||||
public Character Character { get; set; }
|
public Character Character { get; set; }
|
||||||
|
|
||||||
|
public Items.Weapon Weapon { get; set; }
|
||||||
|
|
||||||
public bool IsDead { get; set; }
|
public bool IsDead { get; set; }
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
|
@ -87,8 +90,9 @@ public partial class Projectile : RigidBody2D
|
||||||
{
|
{
|
||||||
hurtbox.InflictDamage(
|
hurtbox.InflictDamage(
|
||||||
Hitbox.Damage,
|
Hitbox.Damage,
|
||||||
Character,
|
Hitbox.Inflictor,
|
||||||
Hitbox.Knockback,
|
Hitbox.Knockback,
|
||||||
|
weapon: Weapon,
|
||||||
knockbackVector: Direction
|
knockbackVector: Direction
|
||||||
);
|
);
|
||||||
EmitSignal(SignalName.Hit, box);
|
EmitSignal(SignalName.Hit, box);
|
||||||
|
|
|
@ -63,6 +63,7 @@ public partial class ShungiteSpike : Projectile
|
||||||
float damage,
|
float damage,
|
||||||
Characters.Character inflictor,
|
Characters.Character inflictor,
|
||||||
float knockback,
|
float knockback,
|
||||||
|
Items.Weapon weapon,
|
||||||
Vector2 knockbackDir)
|
Vector2 knockbackDir)
|
||||||
{
|
{
|
||||||
// if we were hit by the player before the spike freezes,
|
// if we were hit by the player before the spike freezes,
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace SupaLidlGame.Events;
|
||||||
|
|
||||||
public partial class EventBus : Node
|
public partial class EventBus : Node
|
||||||
{
|
{
|
||||||
|
public static EventBus Instance { get; private set; }
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void RequestMoveToAreaEventHandler(RequestAreaArgs args);
|
public delegate void RequestMoveToAreaEventHandler(RequestAreaArgs args);
|
||||||
|
|
||||||
|
@ -16,6 +18,15 @@ public partial class EventBus : Node
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void PlayerHurtEventHandler(HurtArgs args);
|
public delegate void PlayerHurtEventHandler(HurtArgs args);
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
public delegate void PlayerHitEventHandler(HitArgs args);
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
public delegate void PlayerXPChangedEventHandler(double xp);
|
||||||
|
|
||||||
|
[Signal]
|
||||||
|
public delegate void PlayerLevelChangedEventHandler(int level);
|
||||||
|
|
||||||
[Signal]
|
[Signal]
|
||||||
public delegate void PlayerHealthChangedEventHandler(HealthChangedArgs args);
|
public delegate void PlayerHealthChangedEventHandler(HealthChangedArgs args);
|
||||||
|
|
||||||
|
@ -37,5 +48,10 @@ public partial class EventBus : Node
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
ProcessMode = ProcessModeEnum.Always;
|
ProcessMode = ProcessModeEnum.Always;
|
||||||
|
if (Instance is not null)
|
||||||
|
{
|
||||||
|
throw new MultipleSingletonsException();
|
||||||
|
}
|
||||||
|
Instance = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace SupaLidlGame.Events;
|
||||||
|
|
||||||
|
public partial class HitArgs : HurtArgs
|
||||||
|
{
|
||||||
|
public Characters.Character Victim { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public class MultipleSingletonsException : System.Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -64,7 +64,6 @@ public partial class Inventory : Node2D
|
||||||
{
|
{
|
||||||
if (child is Item item)
|
if (child is Item item)
|
||||||
{
|
{
|
||||||
GD.Print("Adding item " + item.Name);
|
|
||||||
AddItem(item);
|
AddItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,12 @@ public abstract partial class Item : Node2D
|
||||||
|
|
||||||
public Character CharacterOwner { get; set; }
|
public Character CharacterOwner { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the item is being used. This property determines if
|
||||||
|
/// a character can use another item or not.
|
||||||
|
/// See <see cref="Character.UseCurrentItem"/>
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
public virtual bool IsUsing => false;
|
public virtual bool IsUsing => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -60,6 +60,9 @@ public abstract partial class Weapon : Item
|
||||||
[Export]
|
[Export]
|
||||||
public float MaxDistanceHint { get; set; }
|
public float MaxDistanceHint { get; set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float PlayerLevelGain { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public Sprite2D HandAnchor { get; set; }
|
public Sprite2D HandAnchor { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=21 format=3 uid="uid://p7oijq6dbvvk"]
|
[gd_scene load_steps=22 format=3 uid="uid://p7oijq6dbvvk"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_1oyma"]
|
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_1oyma"]
|
||||||
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_c41ov"]
|
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_c41ov"]
|
||||||
|
@ -6,6 +6,7 @@
|
||||||
[ext_resource type="Script" path="res://State/Weapon/SwordAnticipateState.cs" id="4_t7af2"]
|
[ext_resource type="Script" path="res://State/Weapon/SwordAnticipateState.cs" id="4_t7af2"]
|
||||||
[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_i5v42"]
|
[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_i5v42"]
|
||||||
[ext_resource type="Texture2D" uid="uid://o7enu13gvji5" path="res://Assets/Sprites/doc-lance.png" id="6_7t87o"]
|
[ext_resource type="Texture2D" uid="uid://o7enu13gvji5" path="res://Assets/Sprites/doc-lance.png" id="6_7t87o"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://d75jkoev5v3w" path="res://Assets/Sprites/Particles/circle-64.png" id="8_gufhv"]
|
||||||
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_y2qyn"]
|
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_y2qyn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="9_buajm"]
|
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="9_buajm"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="11_46l1i"]
|
[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="11_46l1i"]
|
||||||
|
@ -34,7 +35,7 @@ orbit_velocity_max = 0.0
|
||||||
scale_min = 2.0
|
scale_min = 2.0
|
||||||
scale_max = 2.0
|
scale_max = 2.0
|
||||||
scale_curve = SubResource("CurveTexture_383y7")
|
scale_curve = SubResource("CurveTexture_383y7")
|
||||||
color = Color(1, 0, 1, 1)
|
color = Color(0.560784, 0.145098, 0.180392, 1)
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_b7327"]
|
[sub_resource type="Animation" id="Animation_b7327"]
|
||||||
length = 0.001
|
length = 0.001
|
||||||
|
@ -239,17 +240,15 @@ texture = ExtResource("6_7t87o")
|
||||||
|
|
||||||
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
modulate = Color(1.2, 1.2, 1.2, 1)
|
modulate = Color(1.2, 1.2, 1.2, 1)
|
||||||
position = Vector2(-0.221825, -3.12132)
|
position = Vector2(0, -3)
|
||||||
rotation = 0.785398
|
rotation = 0.785398
|
||||||
emitting = false
|
emitting = false
|
||||||
amount = 16
|
amount = 16
|
||||||
process_material = ExtResource("8_y2qyn")
|
process_material = ExtResource("8_y2qyn")
|
||||||
|
texture = ExtResource("8_gufhv")
|
||||||
lifetime = 2.0
|
lifetime = 2.0
|
||||||
one_shot = true
|
one_shot = true
|
||||||
explosiveness = 1.0
|
explosiveness = 1.0
|
||||||
trail_enabled = true
|
|
||||||
trail_lifetime = 0.1
|
|
||||||
trail_sections = 4
|
|
||||||
|
|
||||||
[node name="GPUParticles2D" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
[node name="GPUParticles2D" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
position = Vector2(-2.28882e-05, -6)
|
position = Vector2(-2.28882e-05, -6)
|
||||||
|
|
|
@ -49,6 +49,9 @@ public partial class ProjectileSpawner : Ranged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
projectile.Hitbox.Inflictor = Character;
|
||||||
|
projectile.Weapon = this;
|
||||||
|
|
||||||
if (projectile is Utils.ITarget target)
|
if (projectile is Utils.ITarget target)
|
||||||
{
|
{
|
||||||
if (Character is Characters.NPC npc)
|
if (Character is Characters.NPC npc)
|
||||||
|
@ -92,7 +95,6 @@ public partial class ProjectileSpawner : Ranged
|
||||||
for (int i = 0; i < ProjectileCount; i++)
|
for (int i = 0; i < ProjectileCount; i++)
|
||||||
{
|
{
|
||||||
float curDeviation = -i + maxAngleDeviations;
|
float curDeviation = -i + maxAngleDeviations;
|
||||||
GD.Print(curDeviation);
|
|
||||||
SpawnProjectile(map, target.Rotated(curDeviation * theta));
|
SpawnProjectile(map, target.Rotated(curDeviation * theta));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=28 format=3 uid="uid://5y1acxl4j4n7"]
|
[gd_scene load_steps=29 format=3 uid="uid://5y1acxl4j4n7"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mai31"]
|
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mai31"]
|
||||||
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_5ramr"]
|
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_5ramr"]
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
[ext_resource type="Texture2D" uid="uid://dfpe74vxvuwal" path="res://Assets/Sprites/Items/pugio.png" id="6_d28k5"]
|
[ext_resource type="Texture2D" uid="uid://dfpe74vxvuwal" path="res://Assets/Sprites/Items/pugio.png" id="6_d28k5"]
|
||||||
[ext_resource type="Script" path="res://State/Weapon/SwordBlockState.cs" id="6_yvm8x"]
|
[ext_resource type="Script" path="res://State/Weapon/SwordBlockState.cs" id="6_yvm8x"]
|
||||||
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_we1sv"]
|
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_we1sv"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://d75jkoev5v3w" path="res://Assets/Sprites/Particles/circle-64.png" id="9_3p5s2"]
|
||||||
[ext_resource type="AudioStream" uid="uid://m1sbk3c4eask" path="res://Assets/Sounds/metal-bash2.wav" id="9_b6yro"]
|
[ext_resource type="AudioStream" uid="uid://m1sbk3c4eask" path="res://Assets/Sounds/metal-bash2.wav" id="9_b6yro"]
|
||||||
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="9_qimey"]
|
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="9_qimey"]
|
||||||
[ext_resource type="AudioStream" uid="uid://kao8wbfaum27" path="res://Assets/Sounds/metal-bash3.wav" id="10_istfq"]
|
[ext_resource type="AudioStream" uid="uid://kao8wbfaum27" path="res://Assets/Sounds/metal-bash3.wav" id="10_istfq"]
|
||||||
|
@ -386,6 +387,7 @@ Damage = 20.0
|
||||||
UseTime = 0.55
|
UseTime = 0.55
|
||||||
UseAltTime = 1.5
|
UseAltTime = 1.5
|
||||||
Knockback = 64.0
|
Knockback = 64.0
|
||||||
|
PlayerLevelGain = 1.0
|
||||||
HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
|
HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
|
||||||
|
|
||||||
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
||||||
|
@ -435,17 +437,14 @@ texture = ExtResource("6_d28k5")
|
||||||
|
|
||||||
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
modulate = Color(1.2, 1.2, 1.2, 1)
|
modulate = Color(1.2, 1.2, 1.2, 1)
|
||||||
position = Vector2(-0.221825, -3.12132)
|
position = Vector2(0, -3)
|
||||||
rotation = 0.785398
|
rotation = 0.785398
|
||||||
emitting = false
|
|
||||||
amount = 16
|
amount = 16
|
||||||
process_material = ExtResource("8_we1sv")
|
process_material = ExtResource("8_we1sv")
|
||||||
|
texture = ExtResource("9_3p5s2")
|
||||||
lifetime = 2.0
|
lifetime = 2.0
|
||||||
one_shot = true
|
one_shot = true
|
||||||
explosiveness = 1.0
|
explosiveness = 1.0
|
||||||
trail_enabled = true
|
|
||||||
trail_lifetime = 0.1
|
|
||||||
trail_sections = 4
|
|
||||||
|
|
||||||
[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
|
[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
position = Vector2(-2.52724e-05, 7)
|
position = Vector2(-2.52724e-05, 7)
|
||||||
|
|
|
@ -258,6 +258,7 @@ StateMachine = NodePath("State")
|
||||||
Damage = 12.0
|
Damage = 12.0
|
||||||
UseTime = 1.5
|
UseTime = 1.5
|
||||||
InitialVelocity = 220.0
|
InitialVelocity = 220.0
|
||||||
|
PlayerLevelGain = 0.5
|
||||||
|
|
||||||
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
||||||
script = ExtResource("2_ag6rd")
|
script = ExtResource("2_ag6rd")
|
||||||
|
|
|
@ -7,6 +7,9 @@ using SupaLidlGame.State.Weapon;
|
||||||
|
|
||||||
namespace SupaLidlGame.Items.Weapons;
|
namespace SupaLidlGame.Items.Weapons;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A basic melee weapon.
|
||||||
|
/// </summary>
|
||||||
public partial class Sword : Weapon, IParryable
|
public partial class Sword : Weapon, IParryable
|
||||||
{
|
{
|
||||||
public bool IsAttacking { get; protected set; }
|
public bool IsAttacking { get; protected set; }
|
||||||
|
@ -77,6 +80,9 @@ public partial class Sword : Weapon, IParryable
|
||||||
EnableParry(Time.GetTicksMsec());
|
EnableParry(Time.GetTicksMsec());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes this melee weapon be able to parry and be parried.
|
||||||
|
/// </summary>
|
||||||
public void EnableParry(ulong parryTimeOrigin)
|
public void EnableParry(ulong parryTimeOrigin)
|
||||||
{
|
{
|
||||||
IsParried = false;
|
IsParried = false;
|
||||||
|
@ -84,6 +90,9 @@ public partial class Sword : Weapon, IParryable
|
||||||
ParryTimeOrigin = parryTimeOrigin;
|
ParryTimeOrigin = parryTimeOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes this melee weapon be able to parry and be parried.
|
||||||
|
/// </summary>
|
||||||
public void DisableParry()
|
public void DisableParry()
|
||||||
{
|
{
|
||||||
IsParryable = false;
|
IsParryable = false;
|
||||||
|
@ -113,6 +122,10 @@ public partial class Sword : Weapon, IParryable
|
||||||
base.DeuseAlt();
|
base.DeuseAlt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables the weapon's hitbox. Prefer to call this from a state machine
|
||||||
|
/// rather than managing state through the weapon script.
|
||||||
|
/// </summary>
|
||||||
public void Attack()
|
public void Attack()
|
||||||
{
|
{
|
||||||
//RemainingAttackTime = AttackTime;
|
//RemainingAttackTime = AttackTime;
|
||||||
|
@ -120,6 +133,9 @@ public partial class Sword : Weapon, IParryable
|
||||||
Hitbox.IsDisabled = false;
|
Hitbox.IsDisabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disables the weapon's hitbox and processes all hurtboxes it hit.
|
||||||
|
/// </summary>
|
||||||
public void Deattack()
|
public void Deattack()
|
||||||
{
|
{
|
||||||
IsAttacking = false;
|
IsAttacking = false;
|
||||||
|
@ -161,6 +177,9 @@ public partial class Sword : Weapon, IParryable
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes all hits and applies damages to hurtboxes.
|
||||||
|
/// </summary>
|
||||||
public void ProcessHits()
|
public void ProcessHits()
|
||||||
{
|
{
|
||||||
if (IsParried)
|
if (IsParried)
|
||||||
|
@ -172,7 +191,11 @@ public partial class Sword : Weapon, IParryable
|
||||||
{
|
{
|
||||||
if (box is Hurtbox hurtbox)
|
if (box is Hurtbox hurtbox)
|
||||||
{
|
{
|
||||||
hurtbox.InflictDamage(Damage, Character, Knockback);
|
hurtbox.InflictDamage(
|
||||||
|
Damage,
|
||||||
|
Character,
|
||||||
|
Knockback,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,6 +222,10 @@ public partial class Sword : Weapon, IParryable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stuns the wepaon holder. This is unique to swords and melee weapons
|
||||||
|
/// if they can parry.
|
||||||
|
/// </summary>
|
||||||
public void Stun()
|
public void Stun()
|
||||||
{
|
{
|
||||||
IsParried = true;
|
IsParried = true;
|
||||||
|
@ -238,9 +265,4 @@ public partial class Sword : Weapon, IParryable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetAnimationCondition(string condition, bool value)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=36 format=3 uid="uid://dvqap2uhcah63"]
|
[gd_scene load_steps=37 format=3 uid="uid://dvqap2uhcah63"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mlo73"]
|
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mlo73"]
|
||||||
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_vwirq"]
|
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_vwirq"]
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_hmisb"]
|
[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_hmisb"]
|
||||||
[ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="6_8nxjm"]
|
[ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="6_8nxjm"]
|
||||||
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_10gir"]
|
[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_10gir"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://d75jkoev5v3w" path="res://Assets/Sprites/Particles/circle-64.png" id="9_o34ry"]
|
||||||
[ext_resource type="Shape2D" uid="uid://dw4e4r2yxwk1b" path="res://Items/Weapons/SwordCollisionShape.tres" id="9_wsprl"]
|
[ext_resource type="Shape2D" uid="uid://dw4e4r2yxwk1b" path="res://Items/Weapons/SwordCollisionShape.tres" id="9_wsprl"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="10_672jv"]
|
[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="10_672jv"]
|
||||||
[ext_resource type="AudioStream" uid="uid://qvthq6tppp63" path="res://Assets/Sounds/whoosh.wav" id="10_mfnl7"]
|
[ext_resource type="AudioStream" uid="uid://qvthq6tppp63" path="res://Assets/Sounds/whoosh.wav" id="10_mfnl7"]
|
||||||
|
@ -369,6 +370,7 @@ Damage = 20.0
|
||||||
UseTime = 0.55
|
UseTime = 0.55
|
||||||
Knockback = 64.0
|
Knockback = 64.0
|
||||||
ShouldHideIdle = true
|
ShouldHideIdle = true
|
||||||
|
PlayerLevelGain = 1.0
|
||||||
HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
|
HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
|
||||||
|
|
||||||
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
||||||
|
@ -414,23 +416,22 @@ y_sort_enabled = true
|
||||||
position = Vector2(0, -8)
|
position = Vector2(0, -8)
|
||||||
texture = ExtResource("3_r75ni")
|
texture = ExtResource("3_r75ni")
|
||||||
|
|
||||||
|
[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
|
position = Vector2(-2.52724e-05, 7)
|
||||||
|
rotation = 1.5708
|
||||||
|
|
||||||
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
|
||||||
modulate = Color(1.2, 1.2, 1.2, 1)
|
modulate = Color(1.2, 1.2, 1.2, 1)
|
||||||
position = Vector2(-0.221825, -3.12132)
|
position = Vector2(0, -3)
|
||||||
rotation = 0.785398
|
rotation = 0.785398
|
||||||
emitting = false
|
emitting = false
|
||||||
amount = 16
|
amount = 16
|
||||||
process_material = ExtResource("8_10gir")
|
process_material = ExtResource("8_10gir")
|
||||||
|
texture = ExtResource("9_o34ry")
|
||||||
lifetime = 2.0
|
lifetime = 2.0
|
||||||
one_shot = true
|
one_shot = true
|
||||||
explosiveness = 1.0
|
explosiveness = 1.0
|
||||||
trail_enabled = true
|
fixed_fps = 16
|
||||||
trail_lifetime = 0.1
|
|
||||||
trail_sections = 4
|
|
||||||
|
|
||||||
[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
|
|
||||||
position = Vector2(-2.52724e-05, 7)
|
|
||||||
rotation = 1.5708
|
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||||
libraries = {
|
libraries = {
|
||||||
|
|
17
README.md
17
README.md
|
@ -4,7 +4,22 @@ Forsen-related game
|
||||||
|
|
||||||
![](./Assets/Sprites/Characters/forsen2-portrait.png)
|
![](./Assets/Sprites/Characters/forsen2-portrait.png)
|
||||||
|
|
||||||
![](https://i.ibb.co/t367kD4/baj.gif)
|
## Building
|
||||||
|
|
||||||
|
This is currently being developed on a custom dev branch of Godot 4.1.1:
|
||||||
|
https://github.com/ryze312/godot/tree/x11_event_fix
|
||||||
|
|
||||||
|
Try to avoid using newer versions of Godot as they are unstable with C#.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The tilde key (`~`) can open the developer console. This allows access to
|
||||||
|
singletons --- an instance of `Utils.World` can be accessed through `World`,
|
||||||
|
and the player character can be accessed through `World.CurrentPlayer`.
|
||||||
|
|
||||||
|
The default starting scene is `res://Scenes/ArenaExterior.tscn`, and running a
|
||||||
|
non-map scene may spill out errors from `SupaLidlGame.Utils.World`. Eventually
|
||||||
|
this will be fixed to allow main menu scenes.
|
||||||
|
|
||||||
## Attributions
|
## Attributions
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#+TITLE: SupaLidlGame
|
|
||||||
|
|
||||||
Forsen-related game
|
|
||||||
|
|
||||||
#+attr_html: :style margin-left: auto; margin-right: auto;
|
|
||||||
[[./Assets/Sprites/Characters/forsen2-portrait.png]]
|
|
||||||
|
|
||||||
[[https://i.ibb.co/t367kD4/baj.gif]]
|
|
|
@ -42,7 +42,6 @@ public abstract partial class PlayerState : CharacterState
|
||||||
if (@event.IsActionPressed("interact"))
|
if (@event.IsActionPressed("interact"))
|
||||||
{
|
{
|
||||||
// if looking at a trigger then interact with it
|
// if looking at a trigger then interact with it
|
||||||
GD.Print("interacting");
|
|
||||||
player.InteractionRay.Trigger?.InvokeInteraction();
|
player.InteractionRay.Trigger?.InvokeInteraction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,28 @@ public abstract partial class StateMachine<T> : Node where T : Node, IState<T>
|
||||||
ChangeState(InitialState);
|
ChangeState(InitialState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the state of the <c>StateMachine</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nextState">The next state to transition to.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="nextState" /> is a
|
||||||
|
/// valid state, otherwise <see langword="false" />
|
||||||
|
/// </returns>
|
||||||
public virtual bool ChangeState(T nextState)
|
public virtual bool ChangeState(T nextState)
|
||||||
{
|
{
|
||||||
return ChangeState(nextState, out Stack<T> _);
|
return ChangeState(nextState, out Stack<T> _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the state of the <c>StateMachine</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nextState">The next state to transition to.</param>
|
||||||
|
/// <param name="finalState">The actual state.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="nextState" /> is a
|
||||||
|
/// valid state, otherwise <see langword="false" />
|
||||||
|
/// </returns>
|
||||||
public bool ChangeState(T nextState, out T finalState)
|
public bool ChangeState(T nextState, out T finalState)
|
||||||
{
|
{
|
||||||
var status = ChangeState(nextState, out Stack<T> states);
|
var status = ChangeState(nextState, out Stack<T> states);
|
||||||
|
@ -30,6 +47,15 @@ public abstract partial class StateMachine<T> : Node where T : Node, IState<T>
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the state of the <c>StateMachine</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nextState">The next state to transition to.</param>
|
||||||
|
/// <param name="states">Stack of all states that transitioned/proxied.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="nextState" /> is a
|
||||||
|
/// valid state, otherwise <see langword="false" />
|
||||||
|
/// </returns>
|
||||||
public bool ChangeState(T nextState, out Stack<T> states)
|
public bool ChangeState(T nextState, out Stack<T> states)
|
||||||
{
|
{
|
||||||
states = new Stack<T>();
|
states = new Stack<T>();
|
||||||
|
@ -71,14 +97,35 @@ public abstract partial class StateMachine<T> : Node where T : Node, IState<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the current state to a state of type U which must inherit from T.
|
/// Changes the state of the <c>StateMachine</c> of type
|
||||||
|
/// <typeparamref name="U" /> which must inherit from
|
||||||
|
/// <typeparamref name="T" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The type of the state to transition to.</typeparam>
|
||||||
|
/// <param name="state">The resulting state to be transitioned to.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="nextState" /> is a
|
||||||
|
/// valid state, otherwise <see langword="false" />
|
||||||
|
/// </returns>
|
||||||
public bool ChangeState<U>(out U state) where U : T
|
public bool ChangeState<U>(out U state) where U : T
|
||||||
{
|
{
|
||||||
state = this.FindChildOfType<U>();
|
state = this.FindChildOfType<U>();
|
||||||
return ChangeState(state);
|
return ChangeState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the state of the <c>StateMachine</c> with node name
|
||||||
|
/// <paramref name="name" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The type of the state to transition to.</typeparam>
|
||||||
|
/// <param name="name">
|
||||||
|
/// The name of the <typeparamref name="T" /> node.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="state">The resulting state to be transitioned to.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="nextState" /> is a
|
||||||
|
/// valid state, otherwise <see langword="false" />
|
||||||
|
/// </returns>
|
||||||
public bool ChangeState(string name, out T state)
|
public bool ChangeState(string name, out T state)
|
||||||
{
|
{
|
||||||
state = GetNode<T>(name);
|
state = GetNode<T>(name);
|
||||||
|
|
21
UI/Base.tscn
21
UI/Base.tscn
|
@ -1,9 +1,10 @@
|
||||||
[gd_scene load_steps=7 format=3 uid="uid://c271rdjhd1gfo"]
|
[gd_scene load_steps=8 format=3 uid="uid://c271rdjhd1gfo"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://73jm5qjy52vq" path="res://Dialogue/balloon.tscn" id="1_atjb1"]
|
[ext_resource type="PackedScene" uid="uid://73jm5qjy52vq" path="res://Dialogue/balloon.tscn" id="1_atjb1"]
|
||||||
[ext_resource type="Script" path="res://UI/UIController.cs" id="2_b4b6l"]
|
[ext_resource type="Script" path="res://UI/UIController.cs" id="2_b4b6l"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bxo553hblp6nf" path="res://UI/HealthBar.tscn" id="3_j1j6h"]
|
[ext_resource type="PackedScene" uid="uid://bxo553hblp6nf" path="res://UI/HealthBar.tscn" id="3_j1j6h"]
|
||||||
[ext_resource type="PackedScene" uid="uid://01d24ij5av1y" path="res://UI/BossBar.tscn" id="4_igi28"]
|
[ext_resource type="PackedScene" uid="uid://01d24ij5av1y" path="res://UI/BossBar.tscn" id="4_igi28"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cr7tkxctmyags" path="res://UI/LevelBar.tscn" id="4_rcekd"]
|
||||||
[ext_resource type="PackedScene" uid="uid://c77754nvmckn" path="res://UI/LocationDisplay.tscn" id="5_cr6vo"]
|
[ext_resource type="PackedScene" uid="uid://c77754nvmckn" path="res://UI/LocationDisplay.tscn" id="5_cr6vo"]
|
||||||
[ext_resource type="PackedScene" uid="uid://d3q1yu3n7cqfj" path="res://UI/SceneTransition.tscn" id="6_j0nhv"]
|
[ext_resource type="PackedScene" uid="uid://d3q1yu3n7cqfj" path="res://UI/SceneTransition.tscn" id="6_j0nhv"]
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ BossBar = NodePath("Bottom/BossBar")
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 10
|
anchors_preset = 10
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
offset_bottom = 40.0
|
offset_bottom = 64.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top"]
|
[node name="Margin" type="MarginContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top"]
|
||||||
|
@ -55,9 +56,21 @@ layout_mode = 2
|
||||||
theme_override_constants/margin_left = 16
|
theme_override_constants/margin_left = 16
|
||||||
theme_override_constants/margin_top = 16
|
theme_override_constants/margin_top = 16
|
||||||
|
|
||||||
[node name="HealthBar" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top/Margin" instance=ExtResource("3_j1j6h")]
|
[node name="VBoxContainer" type="VBoxContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top/Margin"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="HealthBar" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top/Margin/VBoxContainer" instance=ExtResource("3_j1j6h")]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="LevelBar" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top/Margin/VBoxContainer" instance=ExtResource("4_rcekd")]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Margin2" type="MarginContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main/Top/Margin/VBoxContainer"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 16
|
||||||
|
theme_override_constants/margin_top = 16
|
||||||
|
|
||||||
[node name="Bottom" type="HBoxContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main"]
|
[node name="Bottom" type="HBoxContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main"]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Godot;
|
||||||
|
using SupaLidlGame.Events;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.UI;
|
||||||
|
|
||||||
|
public partial class LevelBar : Control
|
||||||
|
{
|
||||||
|
public TextureProgressBar XPBar { get; set; }
|
||||||
|
|
||||||
|
private TextureProgressBar[] _levelBars = new TextureProgressBar[4];
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
XPBar = GetNode<TextureProgressBar>("%XPBar");
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
_levelBars[i] = GetNode<TextureProgressBar>($"%Level{i + 1}Bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBus.Instance.PlayerXPChanged += (xp) =>
|
||||||
|
{
|
||||||
|
XPBar.Value = xp;
|
||||||
|
};
|
||||||
|
|
||||||
|
EventBus.Instance.PlayerLevelChanged += (level) =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _levelBars.Length; i++)
|
||||||
|
{
|
||||||
|
// level 0: 0 is not less than 0
|
||||||
|
// level 1: 0 is less than 1
|
||||||
|
_levelBars[i].Value = i < level ? 1 : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://cr7tkxctmyags"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://UI/LevelBar.cs" id="1_eqetx"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b75oak1nd2q6x" path="res://Assets/Sprites/UI/over-under-bar.png" id="2_f332l"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://co7xm7i5f6n51" path="res://Assets/Sprites/UI/progress-bar.png" id="3_arvub"]
|
||||||
|
|
||||||
|
[node name="LevelBar" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
|
offset_right = 128.0
|
||||||
|
offset_bottom = 8.0
|
||||||
|
script = ExtResource("1_eqetx")
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
offset_right = 128.0
|
||||||
|
offset_bottom = 8.0
|
||||||
|
|
||||||
|
[node name="XPBar" type="TextureProgressBar" parent="HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
max_value = 4.0
|
||||||
|
step = 0.01
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
texture_under = ExtResource("2_f332l")
|
||||||
|
texture_progress = ExtResource("3_arvub")
|
||||||
|
|
||||||
|
[node name="Level1Bar" type="TextureProgressBar" parent="HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 2
|
||||||
|
max_value = 1.0
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
texture_under = ExtResource("2_f332l")
|
||||||
|
texture_progress = ExtResource("3_arvub")
|
||||||
|
|
||||||
|
[node name="Level2Bar" type="TextureProgressBar" parent="HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 2
|
||||||
|
max_value = 1.0
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
texture_under = ExtResource("2_f332l")
|
||||||
|
texture_progress = ExtResource("3_arvub")
|
||||||
|
|
||||||
|
[node name="Level3Bar" type="TextureProgressBar" parent="HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 2
|
||||||
|
max_value = 1.0
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
texture_under = ExtResource("2_f332l")
|
||||||
|
texture_progress = ExtResource("3_arvub")
|
||||||
|
|
||||||
|
[node name="Level4Bar" type="TextureProgressBar" parent="HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
texture_filter = 1
|
||||||
|
layout_mode = 2
|
||||||
|
max_value = 1.0
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
texture_under = ExtResource("2_f332l")
|
||||||
|
texture_progress = ExtResource("3_arvub")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_constants/separation = 4
|
|
@ -23,12 +23,9 @@ public static class Physics
|
||||||
var relVel = relIdle + relDir * speed;
|
var relVel = relIdle + relDir * speed;
|
||||||
var relSpeed = relVel.Length();
|
var relSpeed = relVel.Length();
|
||||||
|
|
||||||
GD.Print("Relative velocity: " + relVel);
|
|
||||||
|
|
||||||
// get t = time to travel
|
// get t = time to travel
|
||||||
// = (|s2| - |s1|)/(|v2| - |v1|)
|
// = (|s2| - |s1|)/(|v2| - |v1|)
|
||||||
time = position.DistanceTo(targetPosition) / relSpeed;
|
time = position.DistanceTo(targetPosition) / relSpeed;
|
||||||
GD.Print("Time: " + time);
|
|
||||||
|
|
||||||
// predict target's position after time t
|
// predict target's position after time t
|
||||||
return targetPosition + targetVelocity * time;
|
return targetPosition + targetVelocity * time;
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
using Godot;
|
||||||
|
using SupaLidlGame.Events;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Utils;
|
||||||
|
|
||||||
|
public partial class PlayerStats : Node
|
||||||
|
{
|
||||||
|
public const int MAX_XP_PER_LEVEL = 4;
|
||||||
|
|
||||||
|
public const int MAX_LEVELS = 4;
|
||||||
|
|
||||||
|
public DoubleValue XP { get; set; }
|
||||||
|
|
||||||
|
public IntValue Level { get; set; }
|
||||||
|
|
||||||
|
public double XPDecayVelocity { get; set; } = 1;
|
||||||
|
|
||||||
|
protected bool _shouldDecayXP = true;
|
||||||
|
|
||||||
|
protected Timer _xpDecayTimer;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
XP = GetNode<DoubleValue>("XP");
|
||||||
|
Level = GetNode<IntValue>("Level");
|
||||||
|
|
||||||
|
_xpDecayTimer = new Timer();
|
||||||
|
_xpDecayTimer.Timeout += () => _shouldDecayXP = true;
|
||||||
|
_xpDecayTimer.Stop();
|
||||||
|
AddChild(_xpDecayTimer);
|
||||||
|
|
||||||
|
var bus = EventBus.Instance;
|
||||||
|
XP.Changed += (oldValue, newValue) =>
|
||||||
|
{
|
||||||
|
bus.EmitSignal(EventBus.SignalName.PlayerXPChanged, newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
Level.Changed += (oldValue, newValue) =>
|
||||||
|
{
|
||||||
|
bus.EmitSignal(EventBus.SignalName.PlayerLevelChanged, newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
bus.PlayerHit += (args) =>
|
||||||
|
{
|
||||||
|
double xp = XP.Value;
|
||||||
|
xp += args.Weapon?.PlayerLevelGain ?? 0;
|
||||||
|
|
||||||
|
if (xp >= MAX_XP_PER_LEVEL)
|
||||||
|
{
|
||||||
|
int deltaLevel = (int)(xp / MAX_XP_PER_LEVEL);
|
||||||
|
xp %= MAX_XP_PER_LEVEL;
|
||||||
|
Level.Value = Mathf.Min(Level.Value + deltaLevel, MAX_LEVELS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Level.Value == MAX_LEVELS)
|
||||||
|
{
|
||||||
|
// if max level, can only go up to 1 xp
|
||||||
|
xp = Mathf.Min(xp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XP.Value = xp;
|
||||||
|
|
||||||
|
_shouldDecayXP = false;
|
||||||
|
_xpDecayTimer.Start(1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
if (_shouldDecayXP)
|
||||||
|
{
|
||||||
|
XP.Value = Mathf.MoveToward(XP.Value, 1, XPDecayVelocity * delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public partial class DoubleValue : Node, IValue<double>
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void ChangedEventHandler(double oldValue, double newValue);
|
||||||
|
|
||||||
|
protected double _value = default;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double Value
|
||||||
|
{
|
||||||
|
get => _value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
EmitSignal(SignalName.Changed, _value, value);
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public partial class FloatValue : Node, IValue<float>
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void ChangedEventHandler(float oldValue, float newValue);
|
||||||
|
|
||||||
|
protected float _value = default;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float Value
|
||||||
|
{
|
||||||
|
get => _value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
EmitSignal(SignalName.Changed, _value, value);
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public interface IValue<T>
|
||||||
|
{
|
||||||
|
public delegate void ChangedEventHandler(T oldValue, T newValue);
|
||||||
|
|
||||||
|
public T Value { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public partial class IntValue : Node, IValue<int>
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void ChangedEventHandler(int oldValue, int newValue);
|
||||||
|
|
||||||
|
protected int _value = default;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public int Value
|
||||||
|
{
|
||||||
|
get => _value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
EmitSignal(SignalName.Changed, _value, value);
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -327,8 +327,6 @@ public partial class World : Node
|
||||||
public void SpawnPlayer()
|
public void SpawnPlayer()
|
||||||
{
|
{
|
||||||
// TODO: add max health property
|
// TODO: add max health property
|
||||||
//CurrentPlayer.Health = 100;
|
|
||||||
//CurrentPlayer.Sprite.Visible = true;
|
|
||||||
if (CurrentMap.SceneFilePath != GlobalState.Stats.SaveMapKey)
|
if (CurrentMap.SceneFilePath != GlobalState.Stats.SaveMapKey)
|
||||||
{
|
{
|
||||||
LoadScene(GlobalState.Stats.SaveMapKey);
|
LoadScene(GlobalState.Stats.SaveMapKey);
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
#+TITLE: SupaLidlGame To-do List
|
|
||||||
|
|
||||||
* STARTED Campfires
|
|
||||||
DEADLINE: <2022-12-03 Sat>
|
|
||||||
|
|
||||||
* DONE Enemy Spawning
|
|
||||||
|
|
||||||
* DONE Handle Character Death
|
|
||||||
DEADLINE: <2022-12-04 Sun>
|
|
||||||
|
|
||||||
* Doc Boss
|
|
||||||
|
|
||||||
** DONE Reset possible attacks after each cycle
|
|
||||||
CLOSED: [2023-07-21 Fri]
|
|
||||||
|
|
||||||
** DONE Attack animations
|
|
||||||
CLOSED: [2023-07-20 Thu]
|
|
||||||
|
|
||||||
** DONE Boss Music
|
|
||||||
CLOSED: [2023-07-24 Mon]
|
|
||||||
|
|
||||||
* TODO Boss cards
|
|
||||||
|
|
||||||
* DONE Dialog
|
|
||||||
CLOSED: [2023-07-25 Tue]
|
|
||||||
|
|
||||||
* TODO Short arena entrance
|
|
||||||
CLOSED: [2023-08-02 Wed]
|
|
||||||
|
|
||||||
* DONE Video demonstration
|
|
||||||
CLOSED: [2023-07-25 Tue]
|
|
||||||
|
|
||||||
* TODO Combo Attacks ("Level system")
|
|
||||||
|
|
||||||
** TODO Healing
|
|
||||||
|
|
||||||
** TODO Alt attack
|
|
||||||
|
|
||||||
** TODO Max level
|
|
|
@ -206,4 +206,5 @@ locale/translations_pot_files=PackedStringArray("res://Assets/Dialog/doc.dialogu
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
textures/canvas_textures/default_texture_filter=0
|
textures/canvas_textures/default_texture_filter=0
|
||||||
|
renderer/rendering_method="gl_compatibility"
|
||||||
environment/defaults/default_clear_color=Color(0.301961, 0.301961, 0.301961, 1)
|
environment/defaults/default_clear_color=Color(0.301961, 0.301961, 0.301961, 1)
|
||||||
|
|
Loading…
Reference in New Issue