149 lines
5.5 KiB
C#
149 lines
5.5 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace Minigames.Airplane.Interactive
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gravity well that pulls airplanes toward its center.
|
|||
|
|
/// Creates challenging "danger zones" that players must avoid or escape from.
|
|||
|
|
/// </summary>
|
|||
|
|
[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<Collider2D>();
|
|||
|
|
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<Core.AirplaneController>();
|
|||
|
|
if (airplane == null || !airplane.IsFlying) return;
|
|||
|
|
|
|||
|
|
var rb = other.GetComponent<Rigidbody2D>();
|
|||
|
|
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<Collider2D>();
|
|||
|
|
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<Collider2D>();
|
|||
|
|
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<Collider2D>();
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|