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; } } }