added a parry button and animation that lets player chose their enemy hit behaviour
This commit is contained in:
@@ -33,6 +33,13 @@ stream_2/stream = ExtResource("3_xfjxc")
|
||||
stream_3/stream = ExtResource("4_ycvo6")
|
||||
stream_4/stream = ExtResource("5_5bvpy")
|
||||
|
||||
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_r7v0u"]
|
||||
random_pitch = 1.0999973
|
||||
streams_count = 3
|
||||
stream_0/stream = ExtResource("14_qnngs")
|
||||
stream_1/stream = ExtResource("15_3j1dm")
|
||||
stream_2/stream = ExtResource("16_hln0b")
|
||||
|
||||
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_i5yri"]
|
||||
random_pitch = 1.1
|
||||
streams_count = 3
|
||||
@@ -68,7 +75,7 @@ stream_0/stream = ExtResource("21_r7v0u")
|
||||
stream_1/stream = ExtResource("22_l756u")
|
||||
|
||||
[resource]
|
||||
clip_count = 10
|
||||
clip_count = 11
|
||||
clip_0/name = &"footsteps"
|
||||
clip_0/stream = SubResource("AudioStreamRandomizer_rs8q3")
|
||||
clip_0/auto_advance = 0
|
||||
@@ -99,6 +106,9 @@ clip_8/auto_advance = 0
|
||||
clip_9/name = &"glide"
|
||||
clip_9/stream = ExtResource("19_5bvpy")
|
||||
clip_9/auto_advance = 0
|
||||
clip_10/name = &"parry"
|
||||
clip_10/stream = SubResource("AudioStreamRandomizer_r7v0u")
|
||||
clip_10/auto_advance = 0
|
||||
_transitions = {
|
||||
Vector2i(-1, -1): {
|
||||
"fade_beats": 1.0,
|
||||
|
||||
@@ -614,12 +614,24 @@ to = NodePath("../../StandardAttack")
|
||||
event = &"standard_attack"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToStandardParry" type="Node" parent="StateChart/Root/Attack/Ready" unique_id=237786700]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../StandardParry")
|
||||
event = &"standard_parry"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToDashAttack" type="Node" parent="StateChart/Root/Attack/Ready" unique_id=505795999]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../DashAttack")
|
||||
event = &"dash_attack"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToDashParry" type="Node" parent="StateChart/Root/Attack/Ready" unique_id=39360094]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../DashParry")
|
||||
event = &"dash_parry"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="StandardAttack" type="Node" parent="StateChart/Root/Attack" unique_id=569485647]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
@@ -644,6 +656,30 @@ to = NodePath("../../Ready")
|
||||
event = &"attack_finished"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="StandardParry" type="Node" parent="StateChart/Root/Attack" unique_id=1244610762]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="ToReady" type="Node" parent="StateChart/Root/Attack/StandardParry" unique_id=472222096]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../Ready")
|
||||
event = &"attack_finished"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToDashParry" type="Node" parent="StateChart/Root/Attack/StandardParry" unique_id=548221621]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../DashParry")
|
||||
event = &"dash_parry"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="DashParry" type="Node" parent="StateChart/Root/Attack" unique_id=898768175]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="ToReady" type="Node" parent="StateChart/Root/Attack/DashParry" unique_id=533843974]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../Ready")
|
||||
event = &"attack_finished"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="Movement" type="Node" parent="StateChart/Root" unique_id=1029421869]
|
||||
script = ExtResource("26_infe6")
|
||||
initial_state = NodePath("Grounded")
|
||||
|
||||
@@ -12,19 +12,16 @@ public partial class PlayerUi : Control
|
||||
public enum TargetState
|
||||
{
|
||||
NoTarget,
|
||||
TargetTooFar,
|
||||
TargetInRange,
|
||||
TargetDashThrough
|
||||
TargetWouldNotKill,
|
||||
TargetWouldKill
|
||||
}
|
||||
|
||||
public record TargetProperties(TargetState State, Vector2 Position);
|
||||
|
||||
[Export]
|
||||
public Color DashThroughColor { get; set; } = new Color("009c8f");
|
||||
public Color WouldKillColor { get; set; } = new Color("009c8f");
|
||||
[Export]
|
||||
public Color DashBlockedColor { get; set; } = new Color("fc001c");
|
||||
[Export]
|
||||
public Color DashOutOfRangeColor { get; set; } = new Color("ffffff");
|
||||
public Color WouldNotKillColor { get; set; } = new Color("fc001c");
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
@@ -49,10 +46,9 @@ public partial class PlayerUi : Control
|
||||
|
||||
var modulation = state switch
|
||||
{
|
||||
TargetState.TargetTooFar => DashOutOfRangeColor,
|
||||
TargetState.TargetInRange => DashBlockedColor,
|
||||
TargetState.TargetDashThrough => DashThroughColor,
|
||||
_ => DashOutOfRangeColor
|
||||
TargetState.TargetWouldNotKill => WouldNotKillColor,
|
||||
TargetState.TargetWouldKill => WouldKillColor,
|
||||
_ => WouldNotKillColor
|
||||
};
|
||||
_enemyTarget.SetVisible(visible);
|
||||
_enemyTarget.SetPosition(position - _enemyTarget.Size / 2);
|
||||
|
||||
@@ -336,6 +336,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
|
||||
private StateChartState _attackStandard;
|
||||
private StateChartState _attackDash;
|
||||
private StateChartState _parryStandard;
|
||||
private StateChartState _parryDash;
|
||||
|
||||
private Transition _onJumpFromWall;
|
||||
private Transition _onJumpFromWallFalling;
|
||||
@@ -481,6 +483,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// Attack states
|
||||
_attackStandard = StateChartState.Of(GetNode("StateChart/Root/Attack/StandardAttack"));
|
||||
_attackDash = StateChartState.Of(GetNode("StateChart/Root/Attack/DashAttack"));
|
||||
_parryStandard = StateChartState.Of(GetNode("StateChart/Root/Attack/StandardParry"));
|
||||
_parryDash = StateChartState.Of(GetNode("StateChart/Root/Attack/DashParry"));
|
||||
|
||||
// State timers
|
||||
_powerCooldownTimer = GetNode<Timer>("PowerCooldown");
|
||||
@@ -597,6 +601,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// Attack states
|
||||
_attackStandard.StateEntered += OnStandardAttackStarted;
|
||||
_attackDash.StateEntered += OnDashAttackStarted;
|
||||
_parryStandard.StateEntered += OnStandardParryStarted;
|
||||
_parryDash.StateEntered += OnDashParryStarted;
|
||||
|
||||
// Testing out kill
|
||||
// GetTree().CreateTimer(2).Timeout += () => Kill(this);
|
||||
@@ -1709,16 +1715,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
///////////////////////////
|
||||
public void OnInputParryPressed()
|
||||
{
|
||||
if (WeaponSystem.FlyingState.Active)
|
||||
{
|
||||
DashToFlyingWeapon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (WeaponSystem.PlantedState.Active)
|
||||
{
|
||||
DashToPlantedWeapon();
|
||||
}
|
||||
var attackToDo = _isEnemyInDashAttackRange ? "dash_parry" : "standard_parry";
|
||||
_playerState.SendEvent(attackToDo);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
@@ -1965,7 +1963,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
|
||||
if (DashSystem.CanDashThroughTarget && DashSystem.CollidedObject is ITargetable dashTarget)
|
||||
{
|
||||
enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
|
||||
enemyTargetState = PlayerUi.TargetState.TargetWouldKill;
|
||||
_targetLocation = dashTarget.GetTargetGlobalPosition();
|
||||
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
@@ -1991,19 +1989,14 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// var targetDistance = _targetLocation.DistanceTo(GlobalPosition);
|
||||
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
|
||||
|
||||
_isEnemyInDashAttackRange = true; //targetDistance < TargetInRangeDistance; // Removing the "almost dash" UI
|
||||
if (_isEnemyInDashAttackRange)
|
||||
var wouldKill = false;
|
||||
if (_targetObject is IHealthable h and IDamageable d)
|
||||
{
|
||||
enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
|
||||
if (_targetObject is IDamageable damageable and IHealthable healthable)
|
||||
{
|
||||
var wouldBeDamage = damageable.ComputeDamage(new DamageRecord(GlobalPosition, RDamage));
|
||||
if (wouldBeDamage.Damage.DamageDealt < healthable.CurrentHealth)
|
||||
enemyTargetState = PlayerUi.TargetState.TargetInRange;
|
||||
}
|
||||
var wouldBeDamage = d.ComputeDamage(new DamageRecord(GlobalPosition, RDamage));
|
||||
if (h.CurrentHealth < wouldBeDamage.Damage.DamageDealt) wouldKill = true;
|
||||
}
|
||||
else enemyTargetState = PlayerUi.TargetState.TargetTooFar;
|
||||
|
||||
_isEnemyInDashAttackRange = true;
|
||||
enemyTargetState = wouldKill ? PlayerUi.TargetState.TargetWouldKill : PlayerUi.TargetState.TargetWouldNotKill;
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
}
|
||||
|
||||
@@ -2041,6 +2034,14 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_audioStream!.SwitchToClipByName("attacks");
|
||||
}
|
||||
|
||||
public void OnStandardParryStarted()
|
||||
{
|
||||
_attackCooldown.Start();
|
||||
HeadSystem.OnParry();
|
||||
_audioStream!.SwitchToClipByName("parry");
|
||||
}
|
||||
|
||||
// TODO: fix repeated code and improve parry knockback
|
||||
private PhysicsDirectSpaceState3D _spaceState;
|
||||
public void OnDashAttackStarted()
|
||||
{
|
||||
@@ -2063,6 +2064,27 @@ public partial class PlayerController : CharacterBody3D,
|
||||
var dashTween = CreatePositionTween(plannedDashLocation, AimedDashTime);
|
||||
dashTween.Finished += OnDashAttackEnded;
|
||||
}
|
||||
public void OnDashParryStarted()
|
||||
{
|
||||
_audioStream!.SwitchToClipByName("parry");
|
||||
|
||||
_isInvincible = true;
|
||||
|
||||
var plannedDashLocation = _targetLocation + Vector3.Down*HeadSystem.Position.Y;
|
||||
|
||||
var query = PhysicsRayQueryParameters3D.Create(HeadSystem.GlobalPosition, plannedDashLocation, DashSystem.DashCast3D.CollisionMask);
|
||||
var result = _spaceState.IntersectRay(query);
|
||||
if (result.Count > 0)
|
||||
{
|
||||
plannedDashLocation = (Vector3) result["position"];
|
||||
}
|
||||
|
||||
var travel = plannedDashLocation - GlobalPosition;
|
||||
_preDashVelocity = Velocity;
|
||||
_dashDirection = travel.Normalized();
|
||||
var dashTween = CreatePositionTween(plannedDashLocation, AimedDashTime);
|
||||
dashTween.Finished += OnDashParryEnded;
|
||||
}
|
||||
|
||||
public void OnDashAttackEnded()
|
||||
{
|
||||
@@ -2071,23 +2093,30 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_hitEnemies.Add(damageable);
|
||||
TriggerDamage();
|
||||
}
|
||||
|
||||
if (_targetObject is IStunnable stunnable)
|
||||
{
|
||||
stunnable.Stun();
|
||||
}
|
||||
|
||||
GlobalPosition = ComputePositionAfterTargetedDash(_targetLocation, _targetHitLocation);
|
||||
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
|
||||
Velocity = _dashDirection * postDashVelocity;
|
||||
_isInvincible = false;
|
||||
_playerState.SendEvent("attack_finished");
|
||||
}
|
||||
public void OnDashParryEnded()
|
||||
{
|
||||
if (_targetObject is IDamageable damageable)
|
||||
{
|
||||
_hitEnemies.Add(damageable);
|
||||
TriggerDamage();
|
||||
}
|
||||
if (_targetObject is IStunnable stunnable)
|
||||
{
|
||||
stunnable.Stun();
|
||||
}
|
||||
|
||||
var shouldKnockback = _targetObject is IHealthable { CurrentHealth: > 0 };
|
||||
if (shouldKnockback)
|
||||
{
|
||||
Velocity = -_dashDirection*RKnockback.Modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalPosition = ComputePositionAfterTargetedDash(_targetLocation, _targetHitLocation);
|
||||
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
|
||||
Velocity = _dashDirection * postDashVelocity;
|
||||
}
|
||||
Velocity = -_dashDirection*RKnockback.Modifier;
|
||||
_isInvincible = false;
|
||||
_playerState.SendEvent("attack_finished");
|
||||
}
|
||||
@@ -2104,6 +2133,17 @@ public partial class PlayerController : CharacterBody3D,
|
||||
ThrowWeapon();
|
||||
return;
|
||||
}
|
||||
if (WeaponSystem.FlyingState.Active)
|
||||
{
|
||||
DashToFlyingWeapon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (WeaponSystem.PlantedState.Active)
|
||||
{
|
||||
DashToPlantedWeapon();
|
||||
return;
|
||||
}
|
||||
|
||||
var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack";
|
||||
_playerState.SendEvent(attackToDo);
|
||||
|
||||
Reference in New Issue
Block a user