Stash work on refactor of trajecotry

This commit is contained in:
Michal Pikulski
2025-12-04 16:23:53 +01:00
committed by Michal Pikulski
parent e9d528d837
commit a4363fecb3
7 changed files with 644 additions and 65 deletions

View File

@@ -115,6 +115,12 @@ namespace Common.Input
{
launchAnchor = transform;
}
// Auto-find trajectory preview if not assigned
if (trajectoryPreview == null)
{
trajectoryPreview = GetComponent<Common.Visual.TrajectoryPreview>();
}
}
#endregion
@@ -283,21 +289,6 @@ namespace Common.Input
#region Abstract Methods - Subclass Implementation
/// <summary>
/// Update visual feedback during drag (trajectory preview, rubber band, etc.)
/// </summary>
protected abstract void UpdateVisuals(Vector2 currentPosition, Vector2 direction, float force, float dragDistance, float mass);
/// <summary>
/// Show preview visuals when controller is enabled
/// </summary>
protected abstract void ShowPreview();
/// <summary>
/// Hide preview visuals when controller is disabled
/// </summary>
protected abstract void HidePreview();
/// <summary>
/// Perform the actual launch (spawn projectile/airplane, apply force, etc.)
/// </summary>
@@ -305,6 +296,47 @@ namespace Common.Input
#endregion
#region Virtual Methods - Visual Feedback (Override if needed)
/// <summary>
/// Update visual feedback during drag (trajectory preview, rubber band, etc.)
/// Default: Updates trajectory preview using prefab's physics properties.
/// Override for custom visuals.
/// </summary>
protected virtual void UpdateVisuals(Vector2 currentPosition, Vector2 direction, float force, float dragDistance, float mass)
{
if (trajectoryPreview != null && dragDistance > 0.1f)
{
GameObject prefab = GetProjectilePrefab();
if (prefab != null)
{
trajectoryPreview.UpdateTrajectory(launchAnchor.position, direction, force, prefab);
}
}
}
/// <summary>
/// Show preview visuals when controller is enabled.
/// Default: Shows trajectory preview.
/// Override for custom visuals.
/// </summary>
protected virtual void ShowPreview()
{
trajectoryPreview?.Show();
}
/// <summary>
/// Hide preview visuals when controller is disabled.
/// Default: Hides trajectory preview.
/// Override for custom visuals.
/// </summary>
protected virtual void HidePreview()
{
trajectoryPreview?.Hide();
}
#endregion
#region Virtual Methods - Optional Override
/// <summary>

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e8315fa927ac4db4a53e985fac95c178
timeCreated: 1764857542

View File

@@ -0,0 +1,237 @@
using Core;
using UnityEngine;
namespace Common.Visual
{
/// <summary>
/// Common trajectory preview component for slingshot-style mechanics.
/// Displays a line showing the predicted arc of a launched projectile.
/// Supports multiple API overloads for different use cases.
/// </summary>
[RequireComponent(typeof(LineRenderer))]
public class TrajectoryPreview : MonoBehaviour
{
[Header("Trajectory Settings")]
[Tooltip("Number of points in trajectory line")]
[SerializeField] private int trajectoryPoints = 50;
[Tooltip("Time step between trajectory points (seconds)")]
[SerializeField] private float timeStep = 0.1f;
[Tooltip("Ground level Y position (trajectory stops here)")]
[SerializeField] private float groundLevel = -10f;
[Header("Visual")]
[Tooltip("Color of trajectory line")]
[SerializeField] private Color lineColor = Color.yellow;
[Tooltip("Width of trajectory line")]
[SerializeField] private float lineWidth = 0.1f;
private LineRenderer _lineRenderer;
private bool _isLocked;
private float _lockTimer;
private float _lockDuration;
#region Unity Lifecycle
private void Awake()
{
_lineRenderer = GetComponent<LineRenderer>();
if (_lineRenderer != null)
{
_lineRenderer.startWidth = lineWidth;
_lineRenderer.endWidth = lineWidth;
_lineRenderer.startColor = lineColor;
_lineRenderer.endColor = lineColor;
_lineRenderer.positionCount = trajectoryPoints;
_lineRenderer.enabled = false;
}
}
private void Update()
{
if (_isLocked)
{
_lockTimer += Time.deltaTime;
if (_lockTimer >= _lockDuration)
{
_isLocked = false;
Hide();
}
}
}
#endregion
#region Public API - Visibility
/// <summary>
/// Show the trajectory preview line
/// </summary>
public void Show()
{
if (_lineRenderer != null)
{
_lineRenderer.enabled = true;
}
}
/// <summary>
/// Hide the trajectory preview line (unless locked)
/// </summary>
public void Hide()
{
if (_isLocked) return;
if (_lineRenderer != null)
{
_lineRenderer.enabled = false;
}
}
/// <summary>
/// Lock the trajectory display for a duration (keeps showing after launch)
/// </summary>
public void LockTrajectory(float duration)
{
_isLocked = true;
_lockTimer = 0f;
_lockDuration = duration;
if (_lineRenderer != null)
{
_lineRenderer.enabled = true;
}
}
#endregion
#region Public API - Update Trajectory (Multiple Overloads)
/// <summary>
/// Update trajectory from velocity and gravity directly.
/// Most explicit - caller calculates everything.
/// </summary>
public void UpdateTrajectory(Vector2 startPos, Vector2 velocity, float gravity)
{
if (_lineRenderer == null) return;
CalculateAndSetTrajectory(startPos, velocity, gravity);
}
/// <summary>
/// Update trajectory from launch force and mass.
/// Calculates velocity as: v = (direction * force) / mass
/// </summary>
public void UpdateTrajectory(Vector2 startPos, Vector2 direction, float force, float mass, float gravity)
{
if (_lineRenderer == null) return;
if (mass <= 0f)
{
Logging.Warning("[TrajectoryPreview] Cannot calculate trajectory with zero or negative mass!");
return;
}
Vector2 velocity = (direction * force) / mass;
CalculateAndSetTrajectory(startPos, velocity, gravity);
}
/// <summary>
/// Update trajectory from prefab's Rigidbody2D properties.
/// Reads mass and gravityScale from prefab, calculates gravity automatically.
/// </summary>
public void UpdateTrajectory(Vector2 startPos, Vector2 direction, float force, GameObject prefab)
{
if (_lineRenderer == null || prefab == null) return;
var rb = prefab.GetComponent<Rigidbody2D>();
if (rb == null)
{
Logging.Warning($"[TrajectoryPreview] Prefab '{prefab.name}' has no Rigidbody2D!");
return;
}
float mass = rb.mass;
float gravity = Physics2D.gravity.magnitude * rb.gravityScale;
if (mass <= 0f)
{
Logging.Warning($"[TrajectoryPreview] Prefab '{prefab.name}' has zero mass!");
return;
}
Vector2 velocity = (direction * force) / mass;
CalculateAndSetTrajectory(startPos, velocity, gravity);
}
#endregion
#region Internal Calculation
/// <summary>
/// Calculate and set trajectory points using kinematic formula.
/// Uses: y = y0 + v*t - 0.5*g*t^2
/// </summary>
private void CalculateAndSetTrajectory(Vector2 startPos, Vector2 velocity, float gravity)
{
Vector3[] points = new Vector3[trajectoryPoints];
for (int i = 0; i < trajectoryPoints; i++)
{
float time = i * timeStep;
// Kinematic equations
float x = startPos.x + velocity.x * time;
float y = startPos.y + velocity.y * time - 0.5f * gravity * time * time;
points[i] = new Vector3(x, y, 0);
// Stop at ground level
if (y <= groundLevel)
{
// Fill remaining points at ground level
for (int j = i; j < trajectoryPoints; j++)
{
float tGround = j * timeStep;
float xGround = startPos.x + velocity.x * tGround;
points[j] = new Vector3(xGround, groundLevel, 0);
}
break;
}
}
_lineRenderer.positionCount = trajectoryPoints;
_lineRenderer.SetPositions(points);
}
#endregion
#region Configuration
/// <summary>
/// Set the number of trajectory points (for performance tuning)
/// </summary>
public void SetTrajectoryPoints(int points)
{
trajectoryPoints = Mathf.Max(5, points);
if (_lineRenderer != null)
{
_lineRenderer.positionCount = trajectoryPoints;
}
}
/// <summary>
/// Set the time step between points
/// </summary>
public void SetTimeStep(float step)
{
timeStep = Mathf.Max(0.01f, step);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b86a4cd82d4a47de9d1e4d97ffd01f5e
timeCreated: 1764857542

View File

@@ -44,12 +44,8 @@ namespace Minigames.Airplane.Core
[Tooltip("Airplane prefab to spawn")]
[SerializeField] private GameObject airplanePrefab;
[Header("Visual Feedback")]
[Tooltip("Line renderer for trajectory preview (optional)")]
[SerializeField] private LineRenderer trajectoryLine;
[Tooltip("Visual indicator for launch anchor (optional)")]
[SerializeField] private GameObject anchorVisual;
// Note: Trajectory preview is handled by base DragLaunchController class
// It will auto-find TrajectoryPreview component on this GameObject
#endregion
@@ -81,17 +77,7 @@ namespace Minigames.Airplane.Core
}
}
// Setup trajectory line
if (trajectoryLine != null)
{
trajectoryLine.enabled = false;
}
// Hide anchor visual initially
if (anchorVisual != null)
{
anchorVisual.SetActive(false);
}
// Base class handles trajectory preview setup
}
#endregion
@@ -211,11 +197,7 @@ namespace Minigames.Airplane.Core
// Launch the airplane
_activeAirplane.Launch(direction, force);
// Hide trajectory preview
if (trajectoryLine != null)
{
trajectoryLine.enabled = false;
}
// Trajectory preview is automatically hidden by base class
if (showDebugLogs)
{

View File

@@ -112,11 +112,6 @@ namespace Minigames.FortFight.Core
#region Override Methods
protected override float GetProjectileMass()
{
return _currentAmmo?.GetMass() ?? base.GetProjectileMass();
}
protected override void StartDrag(Vector2 worldPosition)
{
// Check ammo before starting drag
@@ -129,29 +124,6 @@ namespace Minigames.FortFight.Core
base.StartDrag(worldPosition);
}
#endregion
#region Abstract Method Implementations
protected override void ShowPreview()
{
trajectoryPreview?.Show();
}
protected override void HidePreview()
{
trajectoryPreview?.Hide();
}
protected override void UpdateVisuals(Vector2 currentPosition, Vector2 direction,
float force, float dragDistance, float mass)
{
if (trajectoryPreview != null)
{
trajectoryPreview.UpdateTrajectory(launchAnchor.position, direction, force, mass);
}
}
protected override void PerformLaunch(Vector2 direction, float force)
{
LaunchProjectile(direction, force);