I suggest building it in such a way that is super-convenient to start with, but will be easy enough to switch to a fully custom solution should the need arise.
Something like this:
// This wil create a GameObject with a sprite (i.e. the projectile sprite)
ProjectileManager.CreateProjectile( ProjectileType.RedFireball, lifeTime, projectilePos, projectileRotation, ProjectileMotionType.CurveRadius, projectileMotionRadius);
Because this doesn't directly interface with gameObjects, etc. you can later switch fairly quickly to any other solution.
Attach a monobehaviour to the projectile which has a few parameters and an update function.
startTime = Time.time; // assign time when projectile is created
normalizedProjectileTime = (Time.time - startTime) / lifeTime;
if (normalizedProjectileTime > 1.0f) KillProjectile();
transform.position = Interpolate(projectileStartPos, projectileEndPos, normalizedProjectileTime);
This can later be executed on an entire array without having the gameObjects.
You should now have moving projectiles. Using gameObjects, but very easily switchable to a fully custom solution later.
The important concept here is that the projectile motion types are fixed, containted within the enum ProjectileMotionType. What this gives you is fully deterministic projectile motion with no accumulation error. This also lets you create a chain of projectiles "in the past", which is super important for a chain of projectiles emiting from a source. Otherwise, you end up with non-uniformly staggered projectiles. You can apply all sorts of easing functions to this to make it look nicer at very little cost.
Additionally, because the motion is procedural, collision detection becomes considerably easier to perform later. Post again later if you decide to try this out and I'll go into more detail for the subsequent stages.