Intro
Abstract
The ProjectileVisualizer class simulates and visualizes projectile motion, line-of-sight, and intercept geometry using Raycast checks.
![]()
Visualized Elements
| Element | Equation | Color |
|---|---|---|
| Trajectory | , | Yellow |
| LOS | Blue | |
| Perpendicular to LOS | White | |
| Missed target | Red |
Interpretation/ Debug Heuristics
From the visualizations the following becomes more intuitive:
-
LOS misses target but trajectory hits → Gravity compensation is working
-
LOS hits but trajectory misses low → Underestimating gravity or time
-
LOS too high → Aim direction is fundamentally wrong
-
Early green (collision) → Obstruction → don’t throw
-
Red segments after passing target → Overshoot → too much velocity or wrong timing
Calculations
1️⃣ Line of Sight (LOS) – DrawLineOfSight
Goal: Show the projectile’s pointing direction ignoring gravity.
Math:
Where:
- = initial projectile position
- = projectile velocity
- = arbitrary length for visualization (e.g., 100 units)
Purpose:
- Visualize aiming direction.
- Draws a straight line ignoring gravity.
2️⃣ Trajectory Simulation – DrawTrajectory
Goal: Show the projectile’s actual path under gravity and detect collisions.
Time discretization:
Euler integration:
Where:
- = position at step
- = velocity at step
- = gravity
Collision detection:
- Each trajectory segment: check for obstacles using raycast along
Segment colors:
| Condition | Color | Meaning |
|---|---|---|
| Hit obstacle | Green | Collision detected |
| Overshot target | Red | Missed target |
| Normal flight | Yellow | Projectile in air |
3️⃣ Perpendicular to LOS – DrawLosToTarget
Goal: Draw shortest distance from target to projectile’s LOS.
Math:
- LOS direction:
- Vector from projectile to target:
- Projection length along LOS:
- Closest point on LOS:
- Perpendicular vector from LOS to target:
Purpose:
- Draws a white line from the target to LOS.
- Shows how high/low the LOS is relative to the target.
Overshoot condition
Where:
Code Implementation
ProjectileVisualizer.csusing UnityEditor; using UnityEngine; public static class ProjectileVisualizer { // Visualize where projectile is aiming as a straight blue line public static void DrawLineOfSight(Vector3 projectileInitPos, Vector3 projectileVelocity) { Vector3 direction = projectileVelocity.normalized; // Aim/ Line of Sight NO gravity Vector3 endPoint = projectileInitPos + 100f*direction; Debug.DrawLine(projectileInitPos, endPoint, Color.blue); } // Visualize simulation of projectile trajectory under gravity public static void DrawTrajectory(Vector3 projectileInitPos, Vector3 projectileVelocity, Vector3 projectileGravity, Vector3 targetPosition) { Vector3 vf = projectileVelocity; Vector3 currentPos = projectileInitPos; Vector3 nextPos; float t = 0.02f; // timestep int n = 50; // 50 * 0.02s timesteps = 1 sec for (int i = 0; i < 50; i++) { nextPos = currentPos + vf*t; // Get velocity at next timestep: v_f = v0 + a*t vf = vf + projectileGravity*t; // Do trajectory raycast Vector3 segment = nextPos - currentPos; RaycastHit hit; if (Physics.Raycast(currentPos, segment.normalized, out hit, segment.magnitude)) { // Debug.DrawLine(currentPos, nextPos, Color.green, 0.1f); Debug.DrawLine(currentPos, hit.point, Color.green); Debug.Log("Obstacle detected: " + hit.collider.name); break; } // Check whether projection of projectile progress onto target direction > distance to target else if (Vector3.Dot((nextPos - projectileInitPos), (targetPosition - projectileInitPos).normalized ) > (targetPosition - projectileInitPos).magnitude) { Debug.DrawLine(currentPos, nextPos, Color.red, 0.1f); Debug.Log("Missed target!"); } else { Debug.DrawLine(currentPos, nextPos, Color.yellow, 0.1f); // Draw small segment of trajectory } currentPos = nextPos; } } // Draw a white line from the LOS to the target public static void DrawLosToTarget(Vector3 projectileInitPos ,Vector3 projectileVelocity, Vector3 targetPosition, float interceptT) { Vector3 direction = projectileVelocity.normalized; Vector3 ProjectileToTarget = targetPosition - projectileInitPos; float projectionLength = Vector3.Dot(ProjectileToTarget, direction); // ProjectileToTarget projected onto LOS Vector3 endPoint = projectileInitPos + projectionLength*direction; // Draw perpendicular line Debug.DrawLine(targetPosition, endPoint, Color.white, interceptT*0.01f); } }



