using UnityEngine;
namespace NWH.DWP2.ShipController
{
///
/// Approximates the behavior of a real anchor by keeping the object near the anchored position, but
/// allowing for some movement.
///
public class Anchor : MonoBehaviour
{
///
/// Should the anchor be dropped at start?
///
[Tooltip("Should the anchor be dropped at start?")]
public bool dropOnStart = true;
///
/// Coefficient by which the force will be multiplied when the object starts pulling on the anchor.
///
[Tooltip("Coefficient by which the force will be multiplied when the object starts pulling on the anchor.")]
public float forceCoefficient = 10f;
///
/// Radius around anchor in which the chain/rope is slack and in which no force will be applied.
///
[Tooltip("Radius around anchor in which the chain/rope is slack and in which no force will be applied.")]
public float zeroForceRadius = 2f;
///
/// Maximum force that can be applied to anchor before it starts to drag.
///
[Tooltip("Maximum force that can be applied to anchor before it starts to drag.")]
public float dragForce = 500f;
///
/// Point in coordinates local to the object this script is attached to.
///
[Tooltip("Point in coordinates local to the object this script is attached to.")]
public Vector3 localAnchorPoint = Vector3.zero;
private Vector3 _force;
private Vector3 _distance;
private Vector3 _prevDistance;
///
/// Rigidbody to which the force will be applied.
///
public Rigidbody ParentRigidbody { get; private set; }
public Vector3 AnchorPoint
{
get { return transform.TransformPoint(localAnchorPoint); }
}
///
/// Position of the anchor.
///
public Vector3 AnchorPosition { get; set; }
///
/// Has the anchor been dropped?
///
public bool Dropped { get; private set; }
///
/// Is the anchor dragging on the floor?
///
public bool IsDragging { get; private set; }
private void Start()
{
ParentRigidbody = GetComponentInParent();
if (ParentRigidbody == null)
{
Debug.LogError(
$"No rigidbody found on object {name} or its parents. Anchor script needs rigidbody to function.");
}
if (dropOnStart)
{
Drop();
}
}
private void FixedUpdate()
{
if (!Dropped)
{
return;
}
_prevDistance = _distance;
_distance = AnchorPoint - AnchorPosition;
_distance.y = 0;
float distMag = _distance.magnitude - zeroForceRadius;
if (distMag < 0)
{
return;
}
_force = distMag * distMag * 100f * forceCoefficient * -_distance.normalized;
IsDragging = false;
if (_force.magnitude > dragForce)
{
IsDragging = true;
_force = _force.normalized * dragForce;
AnchorPosition += _distance - _prevDistance;
}
ParentRigidbody.AddForceAtPosition(_force, AnchorPoint);
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawSphere(AnchorPoint, 0.2f);
if (Dropped)
{
Gizmos.color = Color.white;
Gizmos.DrawLine(AnchorPoint, AnchorPosition);
}
}
///
/// Drops the anchor. Opposite of Weigh()
///
public void Drop()
{
if (Dropped)
{
return;
}
Dropped = true;
AnchorPosition = AnchorPoint;
}
///
/// Weighs (retracts) the anchor.
///
public void Weigh()
{
if (!Dropped)
{
return;
}
Dropped = false;
}
}
}