# How do I predict an orbiting object's trajectory and draw it

0 favourites
• 15 posts
From the Asset Store
Draw It!
\$19 USD
The objective is to correctly guess and complete the missing part of the picture.
• (Not enough space for a ? )

I'm working on a game where you fly around space in a ship, and I would like to draw a path showing your orbit. Do you have any tips?

• ## Try Construct 3

Develop games in your browser. Powerful, performant & highly capable.

Construct 3 users don't see these ads
• Do a search on the forums, there have been plenty of examlpes of similar requests.

• I searched around and didn't find anything similar to my question. Could you give me a link to one?

• It kinda depends on what your "orbit" is like - is it limited to actually orbiting around things? Is it a straight line, a curve?

If it's an actual orbit you could use this neat tutorial to see how to place other objects, say, dots around whatever it is you are orbiting around to show a trajectory: https://www.scirra.com/tutorials/1050/b ... lar-motion

• I should've explained more - there is a star system, with a central star and two planets orbiting it in more or less circular orbits, and you can freely fly around it, while the star and planets constantly affect your trajectory. I'll take a look at this tutorial, thanks!

E: Well, it didn't help much, as I use cos and sin to calculate my trajectory.

• Hey McDonald,

One way you might approach it, is to run a loop every tick, to simulate the next several frames of motion updates on a "ghost" copy of your ship, dropping dots or particles as it goes, to draw the predicted orbital path.

How it would work

Suppose you have your "real" ship, and you have event code that describes how its position and velocity will be updated each tick (C2 frame). I'll call this event code the "update formula".

So, on a tick, you update the "real" ship position and velocity by running the update formula on it, once.

Now, suppose you also have a "ghost" ship. (The ghost ship will be invisible to the player.)

Right after you update the "real" ship's position and velocity, you set the ghost ship to the same position and velocity.

Now you run a loop with 100 iterations,

and in that loop, on each iteration you update the "ghost" ship, by running the update formula on it, and then you place a dot object at the ghost's current location.

Result

Each time you go through a loop iteration, you step the ghost forwards in time, exactly as if the real ship were continuing frame-by-frame on its trajectory.

At the end of the loop's 100 iterations, you have 100 dots tracing a predicted trajectory 100 frames into the future.

Pros & Cons

As a possible concern, depending on the complexity of the update formula, and the specs of the platform you're targeting with this game, this loop could be a rather intensive spot in your code, though on a typical computer I think it shouldn't be a problem at all.

That said, this method has the advantage of using the same update code you've already created for the "real" ship, and as a result, it will be an accurate simulation of the real ship's future motion, not including player control input, of course. :)

Optimizations

If you need to use fewer objects, you can always place a dot every other loop iteration, or every 5th iteration, etc.

Or you could use a canvas object and paste dots (or trace lines) directly into it, which has the advantage of using 1 dot object no matter how many iterations you do.

• I did what you suggested and the ghost doesn't update and follows the real ship instead. This is probably because the tick ends, ghost starts going forwards, but the next tick comes and resets the ghost back to ship's position. I added the loop as a sub-event if that matters.

The "Repeat 100 times" loop causes the ghost ship to just spawn a 100 times more dots in one place, so it seems to be a problem with updating the ghost.

Although now that I think of it, I need player actions to be accounted for instantly, so this isn't the best solution.

• Here's an example of fisholith's idea with some random control scheme. It works quite well.

• Eh, I tried adding it to my game (then just straight up copy-pasting it), but it didn't help. Thanks for help, anyway.

• Hey again McDonald,

Sorry, my explanation, may have been a bit vague in places.

So, here's what should happen in a single tick:

[TICK START]

// First we advance the RealShip by one time-step.

Every tick: RealShip.state = updateFormula( RealShip.state )

// The ship's "state" information is its XY position, and XY velocity.

// Given the current "state", the "updateFormula" computes the new state for the next time-step.

// // I'm using updateFormula as a shorthand here, in your actual code it may be a block of two or more events.

// Now we prepare the ghost ship to execute a simulation of several future time steps.

// First we set the ghost ship to match the real ship's state, (XY position, and XY velocity).

Every tick: Ghost.state = RealShip.state

// Now we're ready to start the simulation.

// We'll run 100 iterations, and with each, the ghost will advance 1 time-step into the future.

// (Note that the tick has not ended yet.)

Loop from 1 to 100:

// We update the Ghost, just as we would update the real ship.

// Critically, we feed the Ghost's state to the updateFormula, and NOT the RealShip's state.

[sub] > (always): Ghost.state = updateFormula( Ghost.state )

[sub] > (always): Ghost spawns a dot object.

// The ghost has now plopped down 100 dots.

[TICK END]

Essentially, you'll be triggering the same time-advancing code that Construct would trigger each tick (frame-draw), but you're not waiting for Construct. You're manually triggering the code 100 times before the tick ends and the frame is drawn. You're just doing it with a ghost copy of your ship.

As for working with player controls, when the simulation is updating the ghost ship, you can have each loop iteration update the ghost as if the player is continuously holding down the same controls that were used when updating the real ship.

Hope that helps out.

Variation

As an alternative variant of the above approach, you could conceivably run the simulation with your real ship, and not even bother using a ghost ship.

You would need to store the state of the real ship after its update, but before starting the simulation, so that you could recall the real ship back to its proper pre-sim state, before executing any remaining code in the tick.

Thus, even if during the simulation the real ship collides with a lethal object, you'll still be inside the sim loop, and none of your collision handling or ship-exploding code will be running yet. So as long as you put the real ship back, by the time your collision handling code runs, it will never know the ship "time traveled" into a future hazard.

... And witnessed its own death! D:

Also, dang it R0J0hound, how are you always using a newer version of construct than me.

I probably need to enable beta updates, huh.

• Well, I still have a problem - I update the real ship, then update the ghost ship, then loop it 100 times, but the ghost doesn't update and stays in the same place as the real ship, spawning 100 dots every tick. My every tick event looks like this:

Start tick

Do physics stuff and update real ship

Set ghost's state to ship's state

(sub-event)Repeat 100 times

Do physics on ghost

Spawn dot on ghost

End tick

Yet the ghost doesn't update and spews dots in the same place.

• Hm...

I suspect one of two things is happening.

A: The ghost ship is not actually being updated inside the loop.

B: The ghost ship is being updated inside the loop, but to the same spot 100 times.

If the buggy ghost ship is always exactly on top of the real ship, then it's likely that it's situation "A".

If the buggy ghost ship is always exactly 1 time-step ahead of your real ship, then it may be situation "B".

The most likely cause of situation B is that, inside the loop, each loop iteration is setting the ghost.state to

updateFormula( RealShip.state ),

It's hard to say exactly without seeing the events though.

If you can post a screen grab of the events in question, I might be able to figure it out from that.

(In the event sheet, if you select a bunch of events and right-click on the very left edge of an event block, one of the menu options should be "Screenshot Selection.")

• I cut out some irrelevant actions.

• Ah, okay. I think it may be the use of the "Physics" behavior.

I had been thinking you were using a home-made physics system that just did force, velocity and movement. This would mean that you could move an object each iteration of the loop as part of the update process. By contrast, the Physics behavior doesn't expose any kind of "update on command" functionality, to my knowledge.

Here's a deeper explanation of what I think is going on:

By default, C2's Physics behavior is handled by the Box2D physics engine.

(I'll refer to the Physics behavior as "Box2D" from here on, though C2 actually allows other engines as well.)

If I recall correctly, loosely, the way Box2D works in C2 is that, you tell Box2D you want to apply forces to an object, and Box2D will update (move) the object for you. Box2D is hard-coded to do that update after all your events, but before the next tick.

That right there is the problem.

You can't force Box2D to do multiple updates in a single tick. The C2 plugin doesn't give you the ability to force Box2D to update on command.

So, inside a loop, if you add a Box2D force to the ghost, for 100 iterations, it will just pile up the applied forces on each other into a larger and larger single force.

But Box2D won't update the ghost's position at all yet.

So each iteration, the ghost is still in the same place, and all the prediction path dots show up in the same place.

The problem is, Box2D will wait for the loop to end, and it will wait for all your other events to end, and then before the next tick, it will apply that one massive 100X force to the ghost, moving it to who knows where.

(It also doesn't matter where, because the ghost's position will be wrong, and it will also get reset next tick.)

It is theoretically possible to get this path prediction system working with Box2D, if the Physics behavior plugin was modified to provide an "update on command" action, but without being able to force an update, you can't use Box2D to move the ghost on each iteration of the loop.

Sadly, this means that, other things being equal, this prediction method just won't work with Box2D.

One possibility, (that doesn't involve modifying the Physics behavior plugin), is to recreate, in C2 events, the same update formula that Box2D uses. You can then use that to move the ghost ship, each iteration.

Fortunately for your purposes that update formula is probably the simplest part of Box2D to recreate. Basically just, apply force to an object, determine the new velocity, and move the object based on the velocity.

I think by default Box2D uses a frame-rate-dependant mode, so if you know what math Box2D does on each tick, you should be able to exactly recreate it.

As not-so-fun as that might sound, I think it's probably what I would try if I were in the same situation.

One tricky part may be figuring out what Box2D thinks the ship's mass is, because I don't think there's any way to get that info from C2 in the correct units. Though I have seen a few posts on the C2 forums talking about the pixel-to-mass conversion that C2's Box2D uses. I think it was either R0J0hound or Ashley I saw talking about it.

I wish I could offer more help, but I'm not that familiar with Box2D's internals, or how precisely it's integration into C2 affects the behind-the-scenes math.

If I think of something else, I'll let you know.

Best of luck. :)

• 15 posts