# Emulating 3d trajectory in top-down 2d game?

As the title suggests, I am wondering if it's possible to emulate a 3d arrow trajectory to a top-down 2d game? If you would look at this clip of Age of Empires 2 game, especially when archers are firing from bottom to top. Can the parabola/arc of the trajectory (in that certain view angle) be emulated in a 2d orthographic, top-down game? So that the arrows would look like they're in 3d space. I know it's tricky but I wonder if there's some computation available for this.

If you could point me in the right direction or some sample code I would be very grateful. I've only implemented this projectile motion in a side-scroll view.

• There's a similar question answered on StackOverflow that may be of use to you here. The main insight is that projectile movement doesn't care about your rendering perspective. Looking at your scene top-down, side-on, full 3D perspective, etc. does not change the laws of physics or alter how projectiles move. All it changes is the rendering logic for where you draw the image on the screen. A projection matrix can handle this transformation from logical world simulation space to rendered screen space. Nov 28, 2019 at 16:43
• Thank you very much for the insight, I'll check that link and study the answer there. Nov 29, 2019 at 7:58

I created this version which uses a target position and t (time 0-1).

I would loop this function in an update function if (t < 1) t would increase by projectileSpeed * deltaTime in the update after the function was called:

AS THE PROJECTILE

const float projectileHeight = 10f;
const float projectileSpeed = 5f;

Vector3 startPos;
Vector3 endPos;
float fireLerp = 1;

void FireProjectile(Vector3 firePoint, Vector3 targetPos)
{
startPos = firePoint;
endPos = targetPos;

// Setting the fire lerp to 0 will begin the fire animation
fireLerp = 0;
}

void Update()
{
if (fireLerp < 1)
{
Vector3 newProjectilePos = CalculateTrajectory(startPos, endPos, fireLerp);
transform.position = newProjectilePos;

fireLerp += projectileSpeed * Time.deltaTime;
}
}

Vector3 CalculateTrajectory(Vector3 firePos, Vector3 targetPos, float t)
{
Vector3 linearProgress = Vector3.Lerp(firePos, targetPos, t);
float perspectiveOffset = Mathf.Sin(t * Mathf.PI) * projectileHeight;

Vector3 trajectoryPos = linearProgress + (Vector3.up * perspectiveOffset);
return trajectoryPos;
}


Store the Z coordinate and move object as if it was in 3D space. When drawing on screen, add object's Z to Y (you can multiply Z by some constant to make world look 'flatter').