aim dashing through targetable entities now possible

This commit is contained in:
2026-01-24 13:49:16 +01:00
parent 4d419b9010
commit b84b7e4dd5
6 changed files with 80 additions and 41 deletions

View File

@@ -1,9 +1,10 @@
[gd_scene load_steps=19 format=3 uid="uid://q7uc1h2jpbd2"] [gd_scene load_steps=21 format=3 uid="uid://q7uc1h2jpbd2"]
[ext_resource type="PackedScene" uid="uid://bei4nhkf8lwdo" path="res://player_controller/PlayerController.tscn" id="1_62kkh"] [ext_resource type="PackedScene" uid="uid://bei4nhkf8lwdo" path="res://player_controller/PlayerController.tscn" id="1_62kkh"]
[ext_resource type="Material" uid="uid://31aulub2nqov" path="res://assets/greybox/m_greybox.tres" id="2_3uydm"] [ext_resource type="Material" uid="uid://31aulub2nqov" path="res://assets/greybox/m_greybox.tres" id="2_3uydm"]
[ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="3_3uydm"] [ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="3_3uydm"]
[ext_resource type="PackedScene" uid="uid://cmlud1hwkd6sv" path="res://scenes/enemies/flying_enemy/flying_enemy.tscn" id="5_8fd2t"] [ext_resource type="PackedScene" uid="uid://cmlud1hwkd6sv" path="res://scenes/enemies/flying_enemy/flying_enemy.tscn" id="5_8fd2t"]
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="5_ybosk"]
[ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://components/knockback/RKnockback.cs" id="6_1hrkh"] [ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://components/knockback/RKnockback.cs" id="6_1hrkh"]
[ext_resource type="PackedScene" uid="uid://c305mfrtumcyq" path="res://scenes/spawners/spawner.tscn" id="6_7m3bq"] [ext_resource type="PackedScene" uid="uid://c305mfrtumcyq" path="res://scenes/spawners/spawner.tscn" id="6_7m3bq"]
[ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="7_caohq"] [ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="7_caohq"]
@@ -40,6 +41,11 @@ glow_enabled = true
script = ExtResource("6_1hrkh") script = ExtResource("6_1hrkh")
metadata/_custom_type_script = "uid://b44cse62qru7j" metadata/_custom_type_script = "uid://b44cse62qru7j"
[sub_resource type="Resource" id="Resource_5fa36"]
script = ExtResource("5_ybosk")
GravityModifier = 5.0
metadata/_custom_type_script = "uid://dtpxijlnb2c5"
[sub_resource type="Resource" id="Resource_ybosk"] [sub_resource type="Resource" id="Resource_ybosk"]
script = ExtResource("9_2e4ci") script = ExtResource("9_2e4ci")
StartingHealth = 1.0 StartingHealth = 1.0
@@ -117,26 +123,34 @@ use_collision = true
size = Vector3(6.5, 11, 5.5) size = Vector3(6.5, 11, 5.5)
material = ExtResource("2_3uydm") material = ExtResource("2_3uydm")
[node name="FixedDashthroughTarget" parent="." instance=ExtResource("15_5fa36")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14, 3.5, 2.5)
[node name="Enemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")] [node name="Enemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -16.83681) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -16.83681)
Target = NodePath("../Player") Target = NodePath("../Player")
RKnockback = SubResource("Resource_q21h6") RKnockback = SubResource("Resource_q21h6")
RMovement = SubResource("Resource_5fa36")
[node name="Enemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")] [node name="Enemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, -16.83681) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, -16.83681)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_5fa36")
[node name="Enemy3" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")] [node name="Enemy3" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 0, 0.16319084) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 0, 0.16319084)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_5fa36")
[node name="FlyingEnemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")] [node name="FlyingEnemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 7, -16) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 7, -16)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_5fa36")
[node name="FlyingEnemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")] [node name="FlyingEnemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 7, -16) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 7, -16)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_5fa36")
[node name="GroundedSpawner" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("6_7m3bq")] [node name="GroundedSpawner" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("6_7m3bq")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 2.5, -15) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 2.5, -15)
@@ -155,6 +169,3 @@ HealthInputs = ExtResource("11_2e4ci")
DamageInputs = ExtResource("9_gp7s3") DamageInputs = ExtResource("9_gp7s3")
Target = NodePath("../Player") Target = NodePath("../Player")
IsActiveOnStart = false IsActiveOnStart = false
[node name="FixedDashthroughTarget" parent="." instance=ExtResource("15_5fa36")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 3.5, 0)

View File

@@ -105,6 +105,7 @@ script = ExtResource("1_poq2x")
RDamage = SubResource("Resource_cb2lu") RDamage = SubResource("Resource_cb2lu")
RKnockback = SubResource("Resource_abfq8") RKnockback = SubResource("Resource_abfq8")
RHealth = SubResource("Resource_ue7xq") RHealth = SubResource("Resource_ue7xq")
TargetingDistance = 5.0
WalkSpeed = 7.5 WalkSpeed = 7.5
AccelerationFloor = 4.0 AccelerationFloor = 4.0
DecelerationFloor = 3.0 DecelerationFloor = 3.0

View File

@@ -1653,15 +1653,14 @@ public partial class PlayerController : CharacterBody3D,
if (!CanPerformEmpoweredAction()) if (!CanPerformEmpoweredAction())
return; return;
DashSystem.StartPreparingDash(); // DashIndicatorMesh.Visible = true;
DashIndicatorMesh.Visible = true;
if (!isOnFloorCustom()) if (!isOnFloorCustom())
ReduceTimeScaleWhileAiming(); ReduceTimeScaleWhileAiming();
} }
public void HandleAiming(float delta) public void HandleAiming(float delta)
{ {
DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition); // DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition);
DashIndicatorNode.LookAt(DashSystem.PlannedLocation); // DashIndicatorNode.LookAt(DashSystem.PlannedLocation);
if (CanPerformEmpoweredAction()) if (CanPerformEmpoweredAction())
DashSystem.PrepareDash(); DashSystem.PrepareDash();
@@ -1670,7 +1669,7 @@ public partial class PlayerController : CharacterBody3D,
{ {
DashSystem.StopPreparingDash(); DashSystem.StopPreparingDash();
DashIndicatorMesh.Visible = false; // DashIndicatorMesh.Visible = false;
} }
/////////////////////////// ///////////////////////////
@@ -1701,7 +1700,14 @@ public partial class PlayerController : CharacterBody3D,
// feet of the capsule // feet of the capsule
var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius; var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius;
var correctedLocation = DashSystem.PlannedLocation + Vector3.Down * correction; var correctedLocation = DashSystem.PlannedLocation + Vector3.Down * correction;
if (DashSystem.CanDashThroughTarget && DashSystem.CollidedObject is ITargetable targetable)
correctedLocation = ComputePositionAfterTargetedDash(targetable.GetTargetGlobalPosition(), DashSystem.CollisionPoint);
if (DashSystem.CollidedObject is IDamageable damageable)
_hitEnemies.Add(damageable);
// Start invincibility timer for the duration of the dash and a bit more afterwards
OnHitInvincibility();
_preDashVelocity = Velocity; _preDashVelocity = Velocity;
_dashDirection = (correctedLocation - GlobalPosition).Normalized(); _dashDirection = (correctedLocation - GlobalPosition).Normalized();
@@ -1720,6 +1726,8 @@ public partial class PlayerController : CharacterBody3D,
} }
public void OnAimedDashFinished() public void OnAimedDashFinished()
{ {
TriggerDamage();
if (_customMantle) if (_customMantle)
{ {
_playerState.SendEvent("mantle"); _playerState.SendEvent("mantle");
@@ -1829,20 +1837,18 @@ public partial class PlayerController : CharacterBody3D,
MantleSystem.ProcessMantle(_grounded.Active); MantleSystem.ProcessMantle(_grounded.Active);
HandleEnemyTargeting(); HandleEnemyTargeting();
if (_closeEnemyDetector.IsColliding())
// Manage dash target and tutorial specific stuff // Manage dash target and tutorial specific stuff
if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone) // if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone)
{ // {
DashIndicatorMesh.Visible = false; // DashIndicatorMesh.Visible = false;
} // }
if (!WeaponSystem.InHandState.Active && TutorialDone) // if (!WeaponSystem.InHandState.Active && TutorialDone)
{ // {
DashIndicatorMesh.Visible = true; // DashIndicatorMesh.Visible = true;
//
DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2; // DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2;
DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition); // DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition);
} // }
} }
/////////////////////////// ///////////////////////////
@@ -1857,9 +1863,19 @@ public partial class PlayerController : CharacterBody3D,
{ {
_isEnemyInDashAttackRange = false; _isEnemyInDashAttackRange = false;
_closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation()); _closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation());
var enemyTargetState = PlayerUi.TargetState.NoTarget; var enemyTargetState = PlayerUi.TargetState.NoTarget;
var positionOnScreen = Vector2.Zero; var positionOnScreen = Vector2.Zero;
if (DashSystem.CanDashThroughTarget && DashSystem.CollidedObject is ITargetable dashTarget)
{
enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
_targetLocation = dashTarget.GetTargetGlobalPosition();
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
return;
}
if (!_closeEnemyDetector.IsColliding()) if (!_closeEnemyDetector.IsColliding())
{ {
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen)); PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
@@ -1877,8 +1893,8 @@ public partial class PlayerController : CharacterBody3D,
_targetLocation = target.GetTargetGlobalPosition(); _targetLocation = target.GetTargetGlobalPosition();
var targetDistance = _targetLocation.DistanceTo(GlobalPosition); var targetDistance = _targetLocation.DistanceTo(GlobalPosition);
positionOnScreen = _camera.UnprojectPosition(_targetLocation); positionOnScreen = _camera.UnprojectPosition(_targetLocation);
_isEnemyInDashAttackRange = targetDistance < TargetInRangeDistance; _isEnemyInDashAttackRange = true; //targetDistance < TargetInRangeDistance; // Removing the "almost dash" UI
if (_isEnemyInDashAttackRange) if (_isEnemyInDashAttackRange)
{ {
enemyTargetState = PlayerUi.TargetState.TargetDashThrough; enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
@@ -1976,20 +1992,25 @@ public partial class PlayerController : CharacterBody3D,
} }
else else
{ {
var locationOtherSide = _targetLocation + (_targetLocation - _targetHitLocation); GlobalPosition = ComputePositionAfterTargetedDash(_targetLocation, _targetHitLocation);
GlobalPosition = locationOtherSide;
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed; var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
Velocity = _dashDirection * postDashVelocity; Velocity = _dashDirection * postDashVelocity;
} }
_isInvincible = false; _isInvincible = false;
_playerState.SendEvent("attack_finished"); _playerState.SendEvent("attack_finished");
} }
public Vector3 ComputePositionAfterTargetedDash(Vector3 targetLocation, Vector3 targetHitLocation)
{
return targetLocation + (targetLocation - targetHitLocation);
}
public void OnInputHitPressed() public void OnInputHitPressed()
{ {
if (_aiming.Active && WeaponSystem.InHandState.Active) if (_aiming.Active && WeaponSystem.InHandState.Active)
{ {
ThrowWeapon(); ThrowWeapon();
return;
} }
var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack"; var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack";

View File

@@ -60,7 +60,7 @@ RHealth = ExtResource("2_ma2bq")
metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" metadata/_custom_type_script = "uid://bjwrpv3jpsc1e"
[node name="CHealthBar" parent="." instance=ExtResource("7_ykkxn")] [node name="CHealthBar" parent="." instance=ExtResource("7_ykkxn")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.2, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.70000005, 0)
[node name="CDamageable" type="Node" parent="."] [node name="CDamageable" type="Node" parent="."]
script = ExtResource("8_uotso") script = ExtResource("8_uotso")

View File

@@ -1,10 +1,11 @@
using Godot; using Godot;
using Movementtests.interfaces;
namespace Movementtests.systems; namespace Movementtests.systems;
public partial class DashSystem: Node3D public partial class DashSystem: Node3D
{ {
public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal); public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal, GodotObject HitObject = null);
[Export(PropertyHint.Range, "0,0.2,0.01,or_greater")] [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
@@ -13,9 +14,11 @@ public partial class DashSystem: Node3D
public float PostDashSpeed { get; set; } = 0f; public float PostDashSpeed { get; set; } = 0f;
public bool HasHit { get; set; } public bool HasHit { get; set; }
public bool CanDashThroughTarget { get; set; }
public Vector3 TargetLocation { get; set; } public Vector3 TargetLocation { get; set; }
public Vector3 CollisionPoint { get; set; } public Vector3 CollisionPoint { get; set; }
public Vector3 CollisionNormal { get; set; } public Vector3 CollisionNormal { get; set; }
public GodotObject CollidedObject { get; set; }
public Vector3 PlannedLocation { get; set; } public Vector3 PlannedLocation { get; set; }
public bool ShouldMantle { get; set; } public bool ShouldMantle { get; set; }
@@ -84,21 +87,27 @@ public partial class DashSystem: Node3D
var collisionPoint = DashCast3D.GetCollisionPoint(0); var collisionPoint = DashCast3D.GetCollisionPoint(0);
var collisionNormal = DashCast3D.GetCollisionNormal(0); var collisionNormal = DashCast3D.GetCollisionNormal(0);
var collidedObject = DashCast3D.GetCollider(0);
var fraction = DashCast3D.GetClosestCollisionSafeFraction(); var fraction = DashCast3D.GetClosestCollisionSafeFraction();
var globalSweepPath = targetLocation - DashCast3D.GlobalPosition; var globalSweepPath = targetLocation - DashCast3D.GlobalPosition;
var locationAlongPath = DashCast3D.GlobalPosition + globalSweepPath * fraction; var locationAlongPath = DashCast3D.GlobalPosition + globalSweepPath * fraction;
return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal); return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal, collidedObject);
} }
public void PrepareDash() public void PrepareDash()
{ {
DashCast3D.SetRotation(_head.GetGlobalLookRotation()); DashCast3D.SetRotation(_head.GetGlobalLookRotation());
(HasHit, PlannedLocation, CollisionPoint, CollisionNormal) = ComputeDashLocation(); (HasHit, PlannedLocation, CollisionPoint, CollisionNormal, CollidedObject) = ComputeDashLocation();
CanDashThroughTarget = false;
if (CollidedObject is ITargetable targetable)
{
_dashTarget.SetVisible(false);
CanDashThroughTarget = true;
return;
}
// TODO: Position mantle system to planned location, aligned with ground planned and facing the same way as the dash
// Then query it being careful when dashing underneath a platform and such
MantleSystem.SetGlobalPosition(PlannedLocation); MantleSystem.SetGlobalPosition(PlannedLocation);
MantleSystem.SetRotation(new Vector3( MantleSystem.SetRotation(new Vector3(
MantleSystem.Rotation.X, MantleSystem.Rotation.X,
@@ -115,6 +124,7 @@ public partial class DashSystem: Node3D
_dashTarget.SetVisible(true); _dashTarget.SetVisible(true);
var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation; var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation;
_dashTarget.SetGlobalPosition(targetLocation); _dashTarget.SetGlobalPosition(targetLocation);
return;
var shouldShowDropIndicator = !HasHit && !ShouldMantle; var shouldShowDropIndicator = !HasHit && !ShouldMantle;
_dashDropIndicator.SetVisible(shouldShowDropIndicator); _dashDropIndicator.SetVisible(shouldShowDropIndicator);
@@ -141,13 +151,9 @@ public partial class DashSystem: Node3D
public void StopPreparingDash() public void StopPreparingDash()
{ {
CanDashThroughTarget = false;
_dashTarget.SetVisible(false); _dashTarget.SetVisible(false);
_dashDropIndicator.SetVisible(false); _dashDropIndicator.SetVisible(false);
_dashDropLocationIndicator.SetVisible(false); _dashDropLocationIndicator.SetVisible(false);
} }
public void StartPreparingDash()
{
_dashTarget.SetVisible(true);
}
} }

View File

@@ -28,7 +28,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
shape = SubResource("SphereShape3D_jngg2") shape = SubResource("SphereShape3D_jngg2")
target_position = Vector3(0, 0, -12) target_position = Vector3(0, 0, -12)
max_results = 1 max_results = 1
collision_mask = 256 collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1) debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashCastDrop" type="ShapeCast3D" parent="."] [node name="DashCastDrop" type="ShapeCast3D" parent="."]
@@ -36,7 +36,7 @@ transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 1
shape = SubResource("SphereShape3D_jngg2") shape = SubResource("SphereShape3D_jngg2")
target_position = Vector3(0, 0, -50) target_position = Vector3(0, 0, -50)
max_results = 1 max_results = 1
collision_mask = 256 collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1) debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashTarget" type="MeshInstance3D" parent="."] [node name="DashTarget" type="MeshInstance3D" parent="."]