// Copyright (C) 2023 Nicholas Maltbie
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using UnityEngine;
namespace nickmaltbie.OpenKCC.Character.Config
{
///
/// Data structure to represent the current grounded state of
/// a given kinematic character controller.
///
[Serializable]
public struct KCCGroundedState : IKCCGrounded
{
///
/// Current distance the player is from the ground.
///
public float DistanceToGround { get; }
///
/// Is the player currently standing on the ground.
///
public bool OnGround { get; }
///
/// Angle between the ground and the player.
///
public float Angle { get; }
///
/// The surface normal vector of the ground the player is standing on.
///
public Vector3 SurfaceNormal { get; }
///
/// The point in which the player is hitting the ground.
///
public Vector3 GroundHitPosition { get; }
///
/// What is the player standing on.
///
public GameObject Floor { get; }
///
/// Is the player currently standing on the ground?
/// Will be true if the hit the ground and the distance to the ground is less than
/// the grounded threshold. NOTE, will be false if the player is overlapping with the
/// ground or another object as it is difficult to tell whether they are stuck in a wall
/// (and would therefore not be on the ground) versus when they are stuck in the floor.
///
public bool StandingOnGround { get; }
///
/// Is the player currently standing on or overlapping with the ground.
///
public bool StandingOnGroundOrOverlap { get; }
///
/// Is the player currently falling? this is true if they are either not standing on
/// the ground or if the angle between them and the ground is grater than the player's
/// ability to walk.
///
public bool Falling { get; }
///
/// Check if a player is sliding for a given max walk angle.
///
/// True if the player is slipping/falling on the slope they are currently standing on.
public bool Sliding { get; }
///
/// Setup a structure of the grounded
/// state for a kinematic character controller.
///
/// Current distance the player is from the ground.
/// Is the player currently standing on the ground.
/// Angle between the ground and the player.
/// The surface normal vector of the ground the player is standing on.
/// The point in which the player is hitting the ground.
/// What is the player standing on.
/// Distance at which the player is considered grounded.
/// The maximum surface angle the player can walk at before sliding.
public KCCGroundedState(
float distanceToGround,
bool onGround,
float angle,
Vector3 surfaceNormal,
Vector3 groundHitPosition,
GameObject floor,
float groundedDistance = 0.01f,
float maxWalkAngle = 60.0f)
{
DistanceToGround = distanceToGround;
OnGround = onGround;
Angle = angle;
SurfaceNormal = surfaceNormal;
GroundHitPosition = groundHitPosition;
Floor = floor;
StandingOnGround = OnGround && DistanceToGround <= groundedDistance && DistanceToGround >= 0;
StandingOnGroundOrOverlap = OnGround && DistanceToGround <= groundedDistance;
Falling = !StandingOnGround;
Sliding = StandingOnGround && maxWalkAngle < Angle;
}
}
}