How can I have a projectile follow a multi-part flight path?

Greetings,

Currently, I’m using transform.translate to throw a projectile down the Z axis, and would like to curve it as such:

I’ve broken these three parts into what I think needs to be done.

My questions are:

  1. Can I use a simple curve function (X=Y*4 for example) to give me a trajectory, and then have the script change trajectories when a certain elapsed time has passed?

  2. Is there a simpler, built in way to draw a wire frame and have that used for shots?

  3. Is there a function that represents a j-curve, that anyone knows? I’m going to play around on a graphing calculator, but would this even work to control my X direction based off Y coordinates?

Thanks for any help!

If anyone is stuck on something like this, the thread below seems pretty on point, I’m going to try this code as soon as I get home.

Still, any advice or experience is appreciated.

1 Like

You linked to this thread. Lol

I mean, sure, you could set up an array of trajectories that complete a complex path and have your object follow each trajectory up to a certain timespan, but I think a better question is “Why is my projectile following this path?” If you can lay down some simple rules that are being followed to determine the path then your algorithm for determining movement will be that much simpler and more true-to-model.

For instance, if your projectile is following this arc because it should be attracted to the center of the group of boxes, then it would be much simpler to average the group’s position and create an “attraction point” that will accelerate your projectile toward it every frame, thus creating the desired arc via “homing effect”.

Fixed the link, good call.

And true, but the mechanic I want is curved shots relative to the ship, which moves up down left and right, so honestly it could be as simple as making a curve that follows the same path every time, from where the nose of the ship is when the button was pressed. I don’t know if that makes sense, but the point would be to shoot almost boomerang-like shots.

The only other conditions I would apply then would be to flip the curve along the Z axis (left and right) to shoot from one side of the ship depending on which half of the screen you’re on, and the ability for different upgrades to lengthen/shorten the arc of the curve, and modify the speed of the projectile, all of which seem trivial once I figure out what formula to use, I think!

What sort of algorithm did you mean? As simple as the curves we plotted in algebra on an x-y grid? X=y^2 and such?

Hmmmm, I think I see where you’re coming from. I too hit this hurdle once upon a time.

takes a deep breath Hoo boy! Here we go :smile:

You need to bring your formulas into “game space” and away from “math space”. Where “math space” defines each dimension in relation to each other. So, X is defined using Y, and Y is defined using X.

x=y^2 is a great equation and all, but in game space you need to introduce a key variable… time. You then need to solve for each of your variables with respect to time, and not necessarily in relation to each other.
Where is X at time t? Where then is Y at time t? Figure that out and you’ve already got your game space formulas!

For example, let’s take your x=y^2 formula. This is a “math space” formula because it defines both dimensions with respect to each other. We don’t want that! We want each one individually with respect to time! This makes a nice parabola, but it’s only defining the path.
That’s step 1, check!
From there we assume that our object will be moving along the path starting at the origin. This tells us that at t=0, both X and Y should also be 0. But what about at t=1? Well, we need to introduce time into the equation to find out! This is where we must make a conscious decision, because our path is split into the positive and negative directions. We could make this dependent on something, or choose one explicitly. We could make it depend on the side of the screen you’re on :wink: I’ll carry on assuming we’re going with the positive direction. I want to say that for my game, it makes the most sense that after 1 second, the projectile will be at x=1 and y=1. Great! Now after 2 seconds, the projectile should be at x=2 and y=Sqrt(2). That is the trend I want to follow, because it matches our original equation. For this to be true, then x=t must be true. That’s pretty simple! X formula, check! For that to be true, then y=Sqrt(t) must also be true. Also pretty straight forward! Y formula, check!

We can then take those formulas and plug them straight into our game!

transform.x = Time.time;
transform.y = Math.sqrt(Time.time);

That’s seriously oversimplifying the code, but that’s the gist of where this is going. In more practical code you would capture the time at which the projectile was fired and use (Time.time - startTime) to find the projectile’s “current time”.

BUT!

All of that aside, I don’t think you want to take this approach! What this sort of implementation will do is only make you dependent upon a cold, hard, rigid math equation. That’s not cool. No body really wants to sit around and write up complicated curve equations so their objects can curve all badass-like in different scenarios! Especially not when there’s an easier approach

This comes back to my question of “Why is my projectile following this curve?”

In most games where projectiles follow a curve, it’s not because they are bound to hard y=x^2 “math space” equations. It’s most likely because they are moving due to their velocity and being accelerated. Even if the system isn’t using a full-on physics engine to handle it, fluid curves in object motion almost always means: the object is moving Vx amount every frame, and Vx is also changing. Hell, a boomerang is just accelerating toward its owner 9/10 times.

The actual path formulas for an object under the influence of multiple forces plus gravity is stupidly complicated! (Not to mention the horrible framerate from lots of Sqrt’s) It makes no sense for us to lay down a calculated path defining all dimensions in relation to one another as you would in math class. This is a video game! Video games don’t care about graphs unless the player has to care about the graphs too! They care about moments in time. Physics!

So, approach your desired curve from a “moment in time” perspective. What happens to my object “at this moment in time”?

I know what path the projectile should roughly take. Let’s put ourselves in the perspective of the projectile at time 0. The moment I am launched, I’m ejected to the side slightly as I accelerate forward! Deploy-Rocket-style! (I seriously brain storm like this, no joke) This means my “sideways motion” (we’ll say it’s X-velocity) needs to increase the moment I am launched. We call this “initial velocity”. However, I haven’t accelerated yet, so my “forward motion” (Y-velocity) should start out at 0.

Cool, initial velocity of (x=1, y=0) check!

After I’ve been launched, I accelerate straight forward! So every frame, my Y-velocity should increase by some amount. Now, I’m just a missile, so I’m not very good at maths, so we’ll just say I’m going to be moving 1 “velocity unit” faster, every second! – in the Y direction!

float forwardVelocity = 0.0f;
float sideVelocity = 1.0f;

...

void FixedUpdate()
{
    forwardVelocity += 1 * Time.fixedDeltaTime;  // fixedDeltaTime lets us scale our "every second" value of 1 down to what it should be for the amount of time that has actually passed. Only to be used inside of FixedUpdate

    rigidbody.velocity.x = sideVelocity;
    rigidbody.velocity.y = forwardVelocity;
}

I suppose we could put some “drag” on the X-velocity by constantly multiplying it with 0.5 or something.

But hopefully you get the picture.

This implementation achieves a similar curve as x=y^2, but no exponents or square roots to be found. It is more intuitively flexible. For example, you can change the steepness of the curve without having to dive into scaling your exponent, and which power are you even going to? Maybe this is a curve better suited for y^3? That doesn’t matter anymore, because the basic underlying IDEA of what the projectile should be doing has been defined and is being followed, despite circumstance!