using UnityEngine;
namespace Minigames.Airplane.Interactive
{
///
/// Gravity well that pulls airplanes toward its center.
/// Creates challenging "danger zones" that players must avoid or escape from.
///
[RequireComponent(typeof(Collider2D))]
public class AirplaneGravityWell : MonoBehaviour
{
[Header("Gravity Configuration")]
[SerializeField] private float pullStrength = 5f;
[SerializeField] private bool useInverseSquare = false;
[SerializeField] private float minPullDistance = 0.5f;
[Header("Optional Modifiers")]
[SerializeField] private float maxPullForce = 15f;
[SerializeField] private AnimationCurve pullFalloff = AnimationCurve.Linear(0, 1, 1, 0);
[Header("Visual Feedback (Optional)")]
[SerializeField] private ParticleSystem gravityParticles;
[SerializeField] private SpriteRenderer centerSprite;
[SerializeField] private float rotationSpeed = 90f;
[Header("Debug")]
[SerializeField] private bool showDebugLogs;
[SerializeField] private bool drawDebugLines = true;
private Vector2 centerPosition;
private void Awake()
{
// Ensure collider is trigger
var collider = GetComponent();
if (collider != null)
{
collider.isTrigger = true;
}
centerPosition = transform.position;
}
private void Update()
{
// Rotate center visual if present
if (centerSprite != null)
{
centerSprite.transform.Rotate(0, 0, rotationSpeed * Time.deltaTime);
}
}
private void OnTriggerStay2D(Collider2D other)
{
// Check if it's an airplane
var airplane = other.GetComponent();
if (airplane == null || !airplane.IsFlying) return;
var rb = other.GetComponent();
if (rb == null) return;
// Calculate direction and distance to center
Vector2 airplanePos = rb.position;
Vector2 toCenter = centerPosition - airplanePos;
float distance = toCenter.magnitude;
// Prevent division by zero
if (distance < minPullDistance)
{
distance = minPullDistance;
}
// Calculate pull force
float forceMagnitude;
if (useInverseSquare)
{
// Realistic gravity-like force (inverse square law)
forceMagnitude = pullStrength / (distance * distance);
}
else
{
// Linear falloff based on distance
var collider = GetComponent();
float maxDistance = collider != null ? collider.bounds.extents.magnitude : 5f;
float normalizedDistance = Mathf.Clamp01(distance / maxDistance);
float falloff = pullFalloff.Evaluate(1f - normalizedDistance);
forceMagnitude = pullStrength * falloff;
}
// Clamp force
forceMagnitude = Mathf.Min(forceMagnitude, maxPullForce);
// Apply force toward center
Vector2 pullForce = toCenter.normalized * forceMagnitude;
rb.AddForce(pullForce, ForceMode2D.Force);
if (showDebugLogs && Time.frameCount % 30 == 0) // Log every 30 frames
{
Debug.Log($"[AirplaneGravityWell] Pulling {other.name}: force={forceMagnitude:F2}, distance={distance:F2}");
}
}
private void OnDrawGizmos()
{
// Visualize gravity well in editor
Gizmos.color = new Color(1f, 0f, 1f, 0.3f); // Magenta transparent
var collider = GetComponent();
if (collider != null)
{
// Draw zone bounds
Gizmos.DrawWireSphere(collider.bounds.center, collider.bounds.extents.magnitude);
// Draw center point
Gizmos.color = Color.magenta;
Gizmos.DrawWireSphere(transform.position, 0.5f);
// Draw pull strength indicator
Gizmos.DrawRay(transform.position, Vector3.up * pullStrength * 0.2f);
}
}
private void OnDrawGizmosSelected()
{
if (!drawDebugLines) return;
// Draw pull force visualization at multiple points
var collider = GetComponent();
if (collider == null) return;
float radius = collider.bounds.extents.magnitude;
int samples = 8;
for (int i = 0; i < samples; i++)
{
float angle = (i / (float)samples) * 360f * Mathf.Deg2Rad;
Vector2 offset = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
Vector3 samplePoint = transform.position + (Vector3)offset;
Vector3 direction = (transform.position - samplePoint).normalized;
Gizmos.color = Color.yellow;
Gizmos.DrawLine(samplePoint, samplePoint + direction * 2f);
}
}
}
}