added ground profiles
This commit is contained in:
parent
73a23861a4
commit
fd75d7e2d2
@ -14,22 +14,22 @@ namespace Intrepid.Core.Entities
|
||||
[GroupInjections, SerializeField] private Entity entity;
|
||||
[GroupConfigurations, SerializeField] private LayerMask groundMask;
|
||||
|
||||
[GroupConfigurations, SerializeField] private bool inheritGroundMotionY;
|
||||
[GroupConfigurations, SerializeField] private float groundCheckHeight = 1.0f;
|
||||
[GroupConfigurations, SerializeField] private float groundCheckDistance = 3.0f;
|
||||
[GroupConfigurations, SerializeField] private float groundOffset;
|
||||
[GroupConfigurations, SerializeField] private float maxSlopeAngle = 45f;
|
||||
[GroupConfigurations, SerializeField] private float groundProbeRadiusGrounded = 0.5f;
|
||||
[GroupConfigurations, SerializeField] private float groundProbeRadiusFalling = 0.2f;
|
||||
[GroupConfigurations, SerializeField] private float fallingGroundCheckDistance = 20f;
|
||||
[GroupConfigurations, SerializeField] private float fallingGroundCheckDistance = 150f;
|
||||
[GroupConfigurations, SerializeField] private float minFallHeight = 0.25f;
|
||||
[GroupConfigurations, SerializeField] private float fallAcceleration = 35f;
|
||||
[GroupConfigurations, SerializeField] private float maxFallSpeed = 18f;
|
||||
|
||||
|
||||
|
||||
private Vector3 Origin { get; set; }
|
||||
private Vector3 End { get; set; }
|
||||
private bool HasHit { get; set; }
|
||||
|
||||
private GroundProfiles _currentGroundProfiles = GroundProfiles.None;
|
||||
private float _fallVerticalSpeed;
|
||||
private RaycastHit _groundHit;
|
||||
private float GroundProbeRadius => IsFalling || IsFallingToAbyss
|
||||
@ -48,6 +48,7 @@ namespace Intrepid.Core.Entities
|
||||
{
|
||||
IsFalling = false;
|
||||
IsFallingToAbyss = false;
|
||||
_currentGroundProfiles = GroundProfiles.None;
|
||||
}
|
||||
|
||||
public void Move(
|
||||
@ -60,9 +61,9 @@ namespace Intrepid.Core.Entities
|
||||
|
||||
if (IsFallingToAbyss)
|
||||
{
|
||||
return; // there is no movement from here....
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (IsFalling)
|
||||
{
|
||||
var nextFalling = ResolveFallingPosition(current, deltaTime);
|
||||
@ -71,19 +72,29 @@ namespace Intrepid.Core.Entities
|
||||
}
|
||||
|
||||
var movementVelocity = ResolveMovementVelocity(velocity);
|
||||
var next = current + movementVelocity * deltaTime;
|
||||
if (TryGetGroundSurfaceAt(next, out _groundHit, out var nextNormal))
|
||||
var groundMotionDelta = ResolveGroundMotionDelta();
|
||||
|
||||
var next = current
|
||||
+ groundMotionDelta
|
||||
+ movementVelocity * deltaTime;
|
||||
|
||||
if (TryGetGroundSurfaceAt(next, out _groundHit, out var nextNormal, out var groundProfiles))
|
||||
{
|
||||
IsGrounded = true;
|
||||
IsFallingToAbyss = false;
|
||||
|
||||
|
||||
_currentGroundProfiles = groundProfiles;
|
||||
|
||||
RegisterStableGroundNormal(nextNormal);
|
||||
|
||||
next.y = _groundHit.point.y + groundOffset;
|
||||
|
||||
LastSafeGroundPosition = new Vector3(
|
||||
next.x,
|
||||
_groundHit.point.y + groundOffset,
|
||||
next.y,
|
||||
next.z
|
||||
);
|
||||
|
||||
if (IsFalling)
|
||||
{
|
||||
IsFalling = false;
|
||||
@ -93,17 +104,14 @@ namespace Intrepid.Core.Entities
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (options.KeepHeightWhenNoGround) // that is probable an ability like sentinel dash, or enemy jump...
|
||||
else if (options.KeepHeightWhenNoGround)
|
||||
{
|
||||
IsGrounded = false;
|
||||
IsFalling = false;
|
||||
IsFallingToAbyss = false;
|
||||
// Important:
|
||||
// Do not set next.y = current.y here.
|
||||
// The Y value has already been produced by the velocity projected onto the last stable ground normal.
|
||||
// While crossing gaps, the entity keeps moving along the last GroundSurface plane.
|
||||
_currentGroundProfiles = GroundProfiles.None;
|
||||
}
|
||||
else if (TryAnyGroundSurfaceBelowAt(next, out var fallHit, out _)
|
||||
else if (TryAnyGroundSurfaceBelowAt(next, out var fallHit, out _, out _)
|
||||
&& IsGroundMeaningfullyBelow(current, fallHit))
|
||||
{
|
||||
BeginFall();
|
||||
@ -118,6 +126,23 @@ namespace Intrepid.Core.Entities
|
||||
ApplyMove(body, next);
|
||||
}
|
||||
|
||||
private Vector3 ResolveGroundMotionDelta()
|
||||
{
|
||||
if (!IsGrounded || !_currentGroundProfiles.TryGetGroundProfileMotion(out var motion))
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
var delta = motion.DeltaPosition;
|
||||
|
||||
if (inheritGroundMotionY)
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
return new Vector3(delta.x, 0f, delta.z);
|
||||
}
|
||||
|
||||
private Vector3 ResolveFallingPosition(Vector3 current, float deltaTime)
|
||||
{
|
||||
IsGrounded = false;
|
||||
@ -131,7 +156,10 @@ namespace Intrepid.Core.Entities
|
||||
var next = current;
|
||||
next.y -= _fallVerticalSpeed * deltaTime;
|
||||
|
||||
if (!TryAnyGroundSurfaceBelowAt(next, out var fallHit, out var fallNormal))
|
||||
if (!TryAnyGroundSurfaceBelowAt(next,
|
||||
out var fallHit,
|
||||
out var fallNormal,
|
||||
out var fallProfiles))
|
||||
{
|
||||
BeginFallToAbyss();
|
||||
return current; // or next?
|
||||
@ -148,17 +176,12 @@ namespace Intrepid.Core.Entities
|
||||
|
||||
RegisterStableGroundNormal(fallNormal);
|
||||
|
||||
// LastSafeGroundPosition = new Vector3(
|
||||
// next.x,
|
||||
// targetY,
|
||||
// next.z
|
||||
// );
|
||||
|
||||
IsGrounded = true;
|
||||
IsFalling = false;
|
||||
IsFallingToAbyss = false;
|
||||
_fallVerticalSpeed = 0f;
|
||||
|
||||
_currentGroundProfiles = fallProfiles;
|
||||
|
||||
Proxy.Instance.EventBus.Raise(new EntityRecoverStableGroundEvent
|
||||
{
|
||||
EntityId = entity.Id,
|
||||
@ -178,7 +201,8 @@ namespace Intrepid.Core.Entities
|
||||
IsFalling = true;
|
||||
IsFallingToAbyss = false;
|
||||
_fallVerticalSpeed = 0f;
|
||||
|
||||
_currentGroundProfiles = GroundProfiles.None;
|
||||
|
||||
Proxy.Instance.EventBus.Raise(new EntityLeaveStableGroundEvent
|
||||
{
|
||||
EntityId = entity.Id,
|
||||
@ -198,6 +222,7 @@ namespace Intrepid.Core.Entities
|
||||
IsFalling = false;
|
||||
IsFallingToAbyss = true;
|
||||
_fallVerticalSpeed = 0f;
|
||||
_currentGroundProfiles = GroundProfiles.None;
|
||||
|
||||
Proxy.Instance.EventBus.Raise(new EntityFaillingToAbyssEvent
|
||||
{
|
||||
@ -219,12 +244,15 @@ namespace Intrepid.Core.Entities
|
||||
|
||||
public void RefreshStableGroundNormalAt(Vector3 position)
|
||||
{
|
||||
if (!TryGetGroundSurfaceAt(position, out _, out var normal))
|
||||
if (!TryGetGroundSurfaceAt(position, out _, out var normal, out var groundProfiles))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterStableGroundNormal(normal);
|
||||
if (groundProfiles.IsSafe)
|
||||
{
|
||||
RegisterStableGroundNormal(normal);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 ResolveMovementVelocity(Vector3 velocity)
|
||||
@ -258,15 +286,17 @@ namespace Intrepid.Core.Entities
|
||||
|
||||
public bool HasGroundSurfaceAt(Vector3 position)
|
||||
{
|
||||
return TryGetGroundSurfaceAt(position, out _, out _);
|
||||
return TryGetGroundSurfaceAt(position, out _, out _, out _);
|
||||
}
|
||||
|
||||
private bool TryGetGroundSurfaceAt(
|
||||
Vector3 position,
|
||||
out RaycastHit hit,
|
||||
out Vector3 normal)
|
||||
out Vector3 normal,
|
||||
out GroundProfiles groundProfiles)
|
||||
{
|
||||
normal = default;
|
||||
groundProfiles = GroundProfiles.None;
|
||||
|
||||
if (!TryGetGroundAt(position, out hit))
|
||||
{
|
||||
@ -287,6 +317,8 @@ namespace Intrepid.Core.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
groundProfiles = surface.GroundProfiles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -311,9 +343,11 @@ namespace Intrepid.Core.Entities
|
||||
private bool TryAnyGroundSurfaceBelowAt(
|
||||
Vector3 position,
|
||||
out RaycastHit hit,
|
||||
out Vector3 normal)
|
||||
out Vector3 normal,
|
||||
out GroundProfiles groundProfiles)
|
||||
{
|
||||
normal = default;
|
||||
groundProfiles = GroundProfiles.None;
|
||||
|
||||
var origin = position + Vector3.up * groundCheckHeight;
|
||||
|
||||
@ -341,7 +375,14 @@ namespace Intrepid.Core.Entities
|
||||
|
||||
normal = surface.Normal;
|
||||
|
||||
return IsWalkable(normal);
|
||||
if (!IsWalkable(normal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
groundProfiles = surface.GroundProfiles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsWalkable(Vector3 normal)
|
||||
|
||||
9
Assets/Scripts/Intrepid/Core/Grounding/GroundProfile.cs
Normal file
9
Assets/Scripts/Intrepid/Core/Grounding/GroundProfile.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using Intrepid.Utilities;
|
||||
|
||||
namespace Intrepid.Core.Grounding
|
||||
{
|
||||
public abstract class GroundProfile : Identification
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdc7306926734d3bb5b74cc1107abb58
|
||||
timeCreated: 1781275820
|
||||
@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Intrepid.Core.Grounding
|
||||
{
|
||||
public abstract class GroundProfileMotion : GroundProfile
|
||||
{
|
||||
public abstract Vector3 Velocity { get; }
|
||||
public abstract Vector3 DeltaPosition { get; }
|
||||
public abstract bool IsMoving { get; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0bf2067f5ce4269a39772ba51ee47e2
|
||||
timeCreated: 1781275853
|
||||
35
Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs
Normal file
35
Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Intrepid.Core.Grounding
|
||||
{
|
||||
public readonly struct GroundProfiles
|
||||
{
|
||||
public static readonly GroundProfiles None = new(false);
|
||||
|
||||
public bool IsSafe { get; }
|
||||
private GroundProfileMotion GroundProfileMotion { get; }
|
||||
|
||||
public GroundProfiles(bool isSafe, GroundProfileMotion groundProfileMotion = null)
|
||||
{
|
||||
IsSafe = isSafe;
|
||||
GroundProfileMotion = groundProfileMotion;
|
||||
}
|
||||
|
||||
private bool TryGet<T>(T value, out T profile) where T: GroundProfile
|
||||
{
|
||||
if (value.IsNull())
|
||||
{
|
||||
profile = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
profile = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetGroundProfileMotion(out GroundProfileMotion profile)
|
||||
{
|
||||
return TryGet(GroundProfileMotion, out profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bcaf8255e9847b8b25727c33769f037
|
||||
timeCreated: 1781276176
|
||||
@ -12,21 +12,33 @@ namespace Intrepid.Core.Grounding
|
||||
public class GroundSurface : MonoBehaviour
|
||||
{
|
||||
[GroupInjections, SerializeField] private BoxCollider boxCollider;
|
||||
[GroupConfigurations("Profiles"), SerializeField] private bool safe = true;
|
||||
[GroupConfigurations("Profiles"), SerializeField] private GroundProfileMotion groundProfileMotion;
|
||||
|
||||
|
||||
[GroupDebug, ShowInInspector, ReadOnly] public Vector3 Position { get; private set; }
|
||||
[GroupDebug, ShowInInspector, ReadOnly] public Vector3 Normal { get; private set; }
|
||||
public GroundProfiles GroundProfiles { get; private set; } = GroundProfiles.None;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (boxCollider.IsNull()) return;
|
||||
DetectPosition();
|
||||
DetectNormal();
|
||||
RefreshProfiles();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
DetectPosition();
|
||||
DetectNormal();
|
||||
RefreshProfiles();
|
||||
}
|
||||
|
||||
[GroupDebug, Button(ButtonSizes.Medium)]
|
||||
private void RefreshProfiles()
|
||||
{
|
||||
GroundProfiles = new GroundProfiles(safe, groundProfileMotion);
|
||||
}
|
||||
|
||||
[Button(ButtonSizes.Medium)]
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
namespace Intrepid.Core.Grounding
|
||||
{
|
||||
public class MovingGroundSurface : GroundSurface
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 488d97fcd10d484b8d9e50393014a05c
|
||||
timeCreated: 1781271534
|
||||
Loading…
x
Reference in New Issue
Block a user