using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Lightbug.Utilities
{
///
/// This component is a wrapper for the Rigidbody and Rigidbody2D components, containing not only the most commonly used
/// properties and methods, but also some extra features.
///
public abstract class RigidbodyComponent : MonoBehaviour
{
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
public abstract bool Is2D { get; }
public abstract float Mass { get; set; }
public abstract float LinearDrag { get; set; }
public abstract float AngularDrag { get; set; }
public abstract bool IsKinematic { get; set; }
public abstract bool UseGravity { get; set; }
public abstract bool UseInterpolation { get; set; }
public abstract bool ContinuousCollisionDetection { get; set; }
public abstract RigidbodyConstraints Constraints { get; set; }
protected bool previousContinuousCollisionDetection = false;
protected abstract bool IsUsingContinuousCollisionDetection { get; }
public abstract HitInfo Sweep(Vector3 position, Vector3 direction, float distance);
public event System.Action OnBodyTypeChange;
protected void OnBodyTypeChangeInternal() => OnBodyTypeChange?.Invoke();
///
/// Gets the rigidbody position.
///
public abstract Vector3 Position { get; set; }
///
/// Gets the rigidbody rotation.
///
public abstract Quaternion Rotation { get; set; }
///
/// Gets the rigidbody linear velocity.
///
public abstract Vector3 Velocity { get; set; }
///
/// Gets the rigidbody angular velocity.
///
public abstract Vector3 AngularVelocity { get; set; }
///
/// Sets the rigidbody position and rotation.
///
public void SetPositionAndRotation(Vector3 position, Quaternion rotation)
{
Position = position;
Rotation = rotation;
}
///
/// Interpolates the rigidbody position (equivalent to MovePosition).
///
public abstract void Interpolate(Vector3 position);
///
/// Interpolates the rigidbody rotation (equivalent to MoveRotation).
///
public abstract void Interpolate(Quaternion rotation);
///
/// Interpolates the rigidbody position and rotation (equivalent to MovePosition and MoveRotation).
///
/// the target position
/// the target rotation
public void Interpolate(Vector3 position, Quaternion rotation)
{
Interpolate(position);
Interpolate(rotation);
}
///
/// Automatically moves the rigidbody based on its type. If the rigidbody is kinematic MovePosition will be used.
/// If the rigidbody is dynamic the velocity will be set.
///
/// the target position
public void Move(Vector3 position)
{
if (IsKinematic)
Interpolate(position);
else
Velocity = (position - Position) / Time.deltaTime;
}
///
/// Automatically rotates the rigidbody based on its type. If the rigidbody is kinematic MoveRotation will be used.
/// If the rigidbody is dynamic the angular velocity will be set.
///
/// the target rotation
public void Rotate(Quaternion rotation)
{
if (IsKinematic)
{
Interpolate(rotation);
}
else
{
Vector3 angularDisplacement = Mathf.Deg2Rad * (rotation * Quaternion.Inverse(Rotation)).eulerAngles;
AngularVelocity = angularDisplacement / Time.deltaTime;
}
}
///
/// Uses both Move and Rotate method.
///
public void MoveAndRotate(Vector3 position, Quaternion rotation)
{
Move(position);
Rotate(rotation);
}
///
/// Gets the rigidbody velocity at a specific point in space.
///
public abstract Vector3 GetPointVelocity(Vector3 point);
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
public abstract void AddForceToRigidbody(Vector3 force, ForceMode forceMode = ForceMode.Force);
public abstract void AddExplosionForceToRigidbody(float explosionForce, Vector3 explosionPosition, float explosionRadius, float upwardsModifier = 0f);
// Velocity-based methods ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
///
/// Adds a velocity vector to the rigidbody (simulating AddForce) calculated from a force value.
///
public void AddForce(Vector3 force, bool ignoreMass = false, bool useImpulse = false)
{
if (useImpulse)
{
Vector3 acceleration = force / (ignoreMass ? 1f : Mathf.Max(0.01f, Mass));
Velocity += acceleration * Time.fixedDeltaTime;
}
else
{
Vector3 deltaVelocity = force / (ignoreMass ? 1f : Mathf.Max(0.01f, Mass));
Velocity += deltaVelocity;
}
}
///
/// Adds a velocity vector to the rigidbody (simulating AddExplosionForce) calculated from a force value.
///
public void AddExplosionForce(float explosionForce, Vector3 explosionPosition, float explosionRadius, float upwardsModifier = 0f)
{
Vector3 displacementToTarget = Position - explosionPosition;
float displacementToTargetMagnitude = displacementToTarget.magnitude;
if (displacementToTargetMagnitude > explosionRadius)
return;
// Upwards modifier
explosionPosition -= Vector3.up * upwardsModifier;
displacementToTarget = Position - explosionPosition;
// Magnitude based on the radius (linear).
float forceMagnitude = explosionForce * ((explosionRadius - displacementToTargetMagnitude) / explosionRadius);
Vector3 force = Vector3.Normalize(displacementToTarget) * forceMagnitude;
Vector3 velocity = force / Mathf.Max(0.01f, Mass);
Velocity += velocity;
}
///
/// Adds an angular velocity vector to the rigidbody (simulating AddTorque) calculated from a torque value.
///
public void AddTorque(Vector3 torque, bool ignoreMass = false)
{
Vector3 acceleration = torque / (ignoreMass ? 1f : Mathf.Max(0.01f, Mathf.Max(0.01f, Mass)));
AngularVelocity += acceleration * Time.fixedDeltaTime;
}
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
protected virtual void Awake()
{
}
public static RigidbodyComponent CreateInstance(GameObject gameObject)
{
Rigidbody2D rigidbody2D = gameObject.GetComponent();
Rigidbody rigidbody3D = gameObject.GetComponent();
if (rigidbody2D != null)
return gameObject.GetOrAddComponent();
else if (rigidbody3D != null)
return gameObject.GetOrAddComponent();
return null;
}
}
}