Sorry, it’s been a hot minute since I posted some updates but I’ve been busy with work/life and decided to work on some other things in my project but came back to this problem recently.
I modified the script to be much simpler using two spherecasts which works much better than using eccentricity, there is a little bit of improvement that can be done using this to interpolate between the two normals but works fine in testing for now. I have some basic custom gravity setup as well just to keep the agent close to the ground but within some distance.
However I’m still running into that issue where if the target is at a similar height the agent gets stuck recalculating the path and will loop up and down. Any suggestions as to why this might happen?
Here is the new code for anyone interested.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
using Raycasting;
public partial class WallCrawler : AIPath
{
[Header("Grounding")]
public CapsuleCollider capsuleCollider;
[Range(1, 10)]
public float gravityMultiplier;
public LayerMask walkableLayer;
public float gravityOffDistance;
[Header("Ray Adjustments")]
[Range(0.0f, 1.0f)]
public float forwardRayLength;
[Range(0.0f, 1.0f)]
public float downRayLength;
[Range(0.1f, 1.0f)]
public float forwardRaySize = 0.66f;
[Range(0.1f, 1.0f)]
public float downRaySize = 0.9f;
public float downRayRadius;
public float forwardRayRadius;
private Vector3 GroundNormal;
private SphereCast downRay, forwardRay;
private RaycastHit hitInfo;
protected override void OnUpdate (float dt) {
base.OnUpdate(dt);
UpdateMovementPlane();
}
protected override void UpdateMovementPlane () {
if (Physics.SphereCast(transform.TransformPoint(capsuleCollider.center), downRayRadius, -transform.up, out hitInfo, downRayLength, walkableLayer))
{
Debug.Log("Bottom Hit");
GroundNormal = hitInfo.normal.normalized;
}
if (Physics.SphereCast(transform.TransformPoint(capsuleCollider.center), forwardRayRadius, transform.forward, out hitInfo, forwardRayLength, walkableLayer))
{
GroundNormal = hitInfo.normal.normalized;
}
if (GroundNormal != Vector3.zero)
{
var fwd = Vector3.Cross(movementPlane.rotation * Vector3.right, GroundNormal);
movementPlane = new Pathfinding.Util.SimpleMovementPlane(Quaternion.LookRotation(fwd, GroundNormal));
}
}
protected override void ApplyGravity(float deltaTime)
{
// Apply gravity
if (usingGravity) {
// Gravity is relative to the current surface.
// Only the normal direction is well defined however so x and z are ignored.
if (Physics.Raycast(transform.TransformPoint(capsuleCollider.center), -transform.up, out hitInfo, Mathf.Infinity, walkableLayer))
{
if (hitInfo.distance > gravityOffDistance)
{
Debug.Log("Threshold on Gravity Distance Met");
verticalVelocity -= gravityMultiplier;
}
}
} else {
verticalVelocity = 0;
}
}
}