99 lines
3.7 KiB
C#
99 lines
3.7 KiB
C#
using Godot;
|
|
using RustyOptions;
|
|
|
|
namespace Movementtests.systems;
|
|
|
|
public partial class MantleSystem: Node3D
|
|
{
|
|
[Export(PropertyHint.Range, "0,2,0.01,suffix:m,or_greater")]
|
|
public float MantleEndLocationDistanceFromWall { get; set; } = 1f;
|
|
[Export(PropertyHint.Range, "0,10,0.1,suffix:m,or_greater")]
|
|
public float MantleHeightCastStart { get; set; } = 2f;
|
|
[Export(PropertyHint.Range, "0,10,0.01,suffix:m,or_greater")]
|
|
public float MaxStepHeight = 0.5f;
|
|
|
|
private ShapeCast3D _wallInFrontCast3D;
|
|
private ShapeCast3D _mantleCast3D;
|
|
|
|
private ShapeCast3D _inAirWallDetect;
|
|
private ShapeCast3D _groundedWallDetect;
|
|
public Curve3D MantleCurve { get; private set; }
|
|
public Vector3 FirstMantleProfilePoint { get; private set; } = Vector3.Zero;
|
|
|
|
public bool IsMantlePossible { get; private set; } = false;
|
|
public const int WallProfileCastCount = 7;
|
|
|
|
private ShapeCast3D[] _wallProfileShapecasts = new ShapeCast3D[WallProfileCastCount];
|
|
|
|
public void Init()
|
|
{
|
|
_wallInFrontCast3D = GetNode<ShapeCast3D>("WallInFrontCast3D");
|
|
_mantleCast3D = GetNode<ShapeCast3D>("MantleCast3D");
|
|
|
|
_inAirWallDetect = GetNode<ShapeCast3D>("InAirWallDetect");
|
|
_groundedWallDetect = GetNode<ShapeCast3D>("GroundedWallDetect");
|
|
for (int i = 0; i < _wallProfileShapecasts.Length; i++)
|
|
{
|
|
_wallProfileShapecasts[i] = GetNode<ShapeCast3D>($"WallProfileShapeCasts/ShapeCast{i + 1}");
|
|
}
|
|
}
|
|
|
|
private void SetCastsEnabled(bool enabled)
|
|
{
|
|
foreach (var wallProfileShapecast in _wallProfileShapecasts)
|
|
{
|
|
wallProfileShapecast.SetEnabled(enabled);
|
|
}
|
|
}
|
|
|
|
public void ProcessMantle(bool isGrounded)
|
|
{
|
|
_inAirWallDetect.SetEnabled(!isGrounded);
|
|
_groundedWallDetect.SetEnabled(isGrounded);
|
|
var isColliding = _inAirWallDetect.IsColliding() || _groundedWallDetect.IsColliding();
|
|
SetCastsEnabled(isColliding);
|
|
|
|
// Reset state
|
|
IsMantlePossible = false;
|
|
if (!isColliding) return;
|
|
|
|
// Check if collide with wall
|
|
var collisionNormal = isGrounded ? _groundedWallDetect.GetCollisionNormal(0) : _inAirWallDetect.GetCollisionNormal(0);
|
|
if (collisionNormal.Y > 0.9f) return;
|
|
|
|
MantleCurve = new Curve3D();
|
|
MantleCurve.AddPoint(Vector3.Zero);
|
|
var hasFirstProfileHit = false;
|
|
foreach (var wallProfileShapecast in _wallProfileShapecasts)
|
|
{
|
|
// Haven't met the wall yet
|
|
if (!wallProfileShapecast.IsColliding() && !hasFirstProfileHit) continue;
|
|
|
|
var globalTargetPosition = wallProfileShapecast.GlobalPosition + wallProfileShapecast.TargetPosition;
|
|
|
|
// Got to the other side of the wall, we stop there
|
|
if (!wallProfileShapecast.IsColliding())
|
|
{
|
|
MantleCurve.AddPoint(ToLocal(globalTargetPosition));
|
|
break;
|
|
}
|
|
|
|
var profilePoint = wallProfileShapecast.GetCollisionPoint(0);
|
|
var profileNormal = wallProfileShapecast.GetCollisionNormal(0);
|
|
|
|
// Check if we collided parallel to a wall
|
|
var isCollisionSameAsTarget = globalTargetPosition.IsEqualApprox(profilePoint);
|
|
var isCollidingWithWall = profileNormal.Y < 0.1f;
|
|
if (isCollisionSameAsTarget || isCollidingWithWall) continue;
|
|
|
|
// We have a valid collision
|
|
if (!hasFirstProfileHit) FirstMantleProfilePoint = profilePoint;
|
|
hasFirstProfileHit = true;
|
|
MantleCurve.AddPoint(ToLocal(profilePoint));
|
|
}
|
|
if (MantleCurve.PointCount == 1) return;
|
|
|
|
IsMantlePossible = true;
|
|
}
|
|
}
|