2025-11-25 08:19:33 -05:00
|
|
|
|
using System;
|
|
|
|
|
|
using Sirenix.OdinInspector;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame.Characters
|
|
|
|
|
|
{
|
|
|
|
|
|
public class GroundDetector
|
|
|
|
|
|
{
|
|
|
|
|
|
[ShowInInspector]
|
|
|
|
|
|
private CharacterBase character;
|
|
|
|
|
|
[ShowInInspector]
|
|
|
|
|
|
private Transform characterTransform;
|
|
|
|
|
|
|
|
|
|
|
|
public bool isOnGround;
|
|
|
|
|
|
public float groundedLength;
|
|
|
|
|
|
public float groundedRadius;
|
|
|
|
|
|
public float groundedOffset;
|
|
|
|
|
|
public LayerMask groundLayers;
|
|
|
|
|
|
|
|
|
|
|
|
public GroundDetector()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public GroundDetector(CharacterBase character, float groundedLength, float groundedRadius, float groundedOffset, LayerMask groundLayers)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.character = character;
|
|
|
|
|
|
this.characterTransform = character.transform;
|
|
|
|
|
|
|
|
|
|
|
|
this.groundedLength = groundedLength;
|
|
|
|
|
|
this.groundedRadius = groundedRadius;
|
|
|
|
|
|
this.groundedOffset = groundedOffset;
|
|
|
|
|
|
this.groundLayers = groundLayers;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
private bool CheckOnGround(float length, float radius = -1f)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
radius = radius < 0 ? groundedRadius : radius;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
Vector3 centerPosition = characterTransform.position - new Vector3(0, groundedOffset, 0);
|
2026-02-13 09:22:11 -05:00
|
|
|
|
Vector3 startPosition = centerPosition + new Vector3(0, length / 2, 0);
|
|
|
|
|
|
Vector3 endPosition = centerPosition - new Vector3(0, length / 2, 0);
|
|
|
|
|
|
return Physics.CheckCapsule(startPosition, endPosition, radius, groundLayers, QueryTriggerInteraction.Ignore);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool DetectGround()
|
|
|
|
|
|
{
|
|
|
|
|
|
float predictDistance = -character.movementSc.finalMovementVelocity.y;
|
|
|
|
|
|
float adjustedGroundedLength = groundedLength + Mathf.Max(0, predictDistance);
|
|
|
|
|
|
return isOnGround = CheckOnGround(adjustedGroundedLength);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
public bool DetectGround(float multiplier, float offset = 0f)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
float predictDistance = -character.movementSc.finalMovementVelocity.y;
|
|
|
|
|
|
float adjustedGroundedLength = (groundedLength + Mathf.Max(0, predictDistance)) * multiplier;
|
|
|
|
|
|
return CheckOnGround(adjustedGroundedLength + offset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool DetectGroundByFixedLength(float fixedLength, bool withPrediction = false, float overrideRadius = -1f)
|
|
|
|
|
|
{
|
|
|
|
|
|
float adjustedGroundedLength = fixedLength;
|
|
|
|
|
|
if (withPrediction)
|
|
|
|
|
|
{
|
|
|
|
|
|
float predictDistance = -character.movementSc.finalMovementVelocity.y;
|
|
|
|
|
|
adjustedGroundedLength = fixedLength + Mathf.Max(0, predictDistance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return CheckOnGround(adjustedGroundedLength, overrideRadius);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取一个实体到地面的距离,如果返回Infinity则说明实体的下方没有地面
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>实体到地面的距离</returns>
|
|
|
|
|
|
public float GetDistanceToGround()
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 rayOrigin = characterTransform.position - new Vector3(0, groundedOffset, 0);
|
|
|
|
|
|
Ray ray = new Ray(rayOrigin, Vector3.down);
|
|
|
|
|
|
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, groundLayers))
|
|
|
|
|
|
{
|
|
|
|
|
|
return hit.distance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Mathf.Infinity;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 忽略空中高度,获取一个实体在地面上的位置,如果返回false则说明实体的下方没有地面
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="groundPosition">返回地面位置</param>
|
|
|
|
|
|
/// <returns>实体下方是否有地面</returns>
|
|
|
|
|
|
public bool GetGroundPosition(out Vector3 groundPosition)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isOnGround)
|
|
|
|
|
|
{
|
|
|
|
|
|
groundPosition = characterTransform.position;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Vector3 rayOrigin = characterTransform.position - new Vector3(0, groundedOffset, 0);
|
|
|
|
|
|
Ray ray = new Ray(rayOrigin, Vector3.down);
|
|
|
|
|
|
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, groundLayers))
|
|
|
|
|
|
{
|
|
|
|
|
|
groundPosition = hit.point;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
groundPosition = characterTransform.position;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|