0
\$\begingroup\$

I'm trying to figure out how to express parabolic motion (for example: \$y = x^2\$) using delta time. I thought about deriving it using a differential like \$y' = \frac{1}{2}x\$ but that results in a straight line with a slope of \$\frac{1}{2}\$.

I'm not familiar with using delta time in this context, and I'm confused about the different methods (explicit Euler, implicit Euler, etc.). For reference, I can already write a linearly moving function like y = 2 * x using delta time in love2d. Note: I'm just using love2 is just an example. Anything can be used in the answer.

function love.load() screenWidth, screenHeight = love.graphics.getDimensions() circle = { x = screenWidth * 0.5, y = screenHeight * 0.5, radius = 10, dx = 100, dy = -200, } end function love.update(dt) circle.x = circle.x + circle.dx * dt circle.y = circle.y + circle.dy * dt if circle.x - circle.radius < 0 or circle.x + circle.radius > screenWidth then circle.dx = -circle.dx circle.dy = -circle.dy end circle.x = math.max(circle.radius, math.min(screenWidth - circle.radius, circle.x)) if circle.y - circle.radius < 0 or circle.y + circle.radius > screenHeight then circle.dx = -circle.dx circle.dy = -circle.dy end circle.y = math.max(circle.radius, math.min(screenHeight - circle.radius, circle.y)) end function love.draw() love.graphics.circle("fill", circle.x, circle.y, circle.radius) love.graphics.print(string.format("x: %.1f, y: %.1f", circle.x, circle.y), 10, 10) end 

I was able to create a parabolic motion by using a formula that calculates speed from acceleration, which I found frequently mentioned online.

However, I must admit that I wrote it purely by imitation, and it feels like it's only working by chance.

How can I create a parabolic motion, such as a trajectory following \$y = x^2\$, with the origin at the center of the screen? (For expressing on a computer, anything reasonably complex would be fine (for example, the screen center as the origin seems difficult), but that might make it hard to settle on a single answer. So, this time, I would like to see the code for the behavior of \$x^2\$ centered on the screen.)

A movement that draws lines similar to the image below enter image description here

The coordinates in a computer do not match those in mathematics (as the allmost computer uses the top-left corner as the origin), but adopting the mathematical view would likely result in more complex code (which could lead to a deeper understanding).

The code I attempted:

function love.load() screenWidth, screenHeight = love.graphics.getDimensions() circle = { x = screenWidth * 0.5, y = screenHeight * 0.5, radius = 10, dx = 100, dy = -200, } end function love.update(dt) yAcceleration = 9.8 circle.dy = circle.dy + yAcceleration circle.x = circle.x + circle.dx * dt circle.y = circle.y + circle.dy * dt if circle.x - circle.radius < 0 or circle.x + circle.radius > screenWidth then circle.dx = -circle.dx circle.dy = -circle.dy end circle.x = math.max(circle.radius, math.min(screenWidth - circle.radius, circle.x)) if circle.y - circle.radius < 0 or circle.y + circle.radius > screenHeight then circle.dx = -circle.dx circle.dy = -circle.dy end circle.y = math.max(circle.radius, math.min(screenHeight - circle.radius, circle.y)) end function love.draw() love.graphics.circle("fill", circle.x, circle.y, circle.radius) love.graphics.print(string.format("x: %.1f, y: %.1f", circle.x, circle.y), 10, 10) end 

When I reverse the sign of yAcceleration like circle.dy = circle.dy - yAcceleration, it brings us closer to the ideal (since the sign of the coordinates in mathematics is opposite...) The further the circle moves towards the center, the slower it seems to travel (the reason is not yet clear at this stage).

The width is narrower than I expected. When I tried adjusting the values to widen it (e.g., yAcceleration = 0.8), it shifted away from the center. The speed also seems slower than before I made the changes.

\$\endgroup\$
3
  • \$\begingroup\$ The formulas you have written do not reference time. What do you want a change in the time to do precisely? \$\endgroup\$ Commented Dec 18, 2024 at 13:25
  • \$\begingroup\$ I edited question. I managed to draw the parabolic path using acceleration itself. However, I only understand the concept of using acceleration and am not sure how to implement the desired behavior correctly. I would like to see a program that moves the behavior of x^2 centered on the screen. I believe that looking at such a program could reveal something useful. \$\endgroup\$ Commented Dec 18, 2024 at 13:56
  • \$\begingroup\$ Manually adding "Edit" is discouraged; Stack Exchange keeps a detailed time-stamped edit history for all posts that anyone can review. The separator line / horizontal rule is sufficient to visually indicate that additional material was added. \$\endgroup\$ Commented Dec 18, 2024 at 17:14

1 Answer 1

2
\$\begingroup\$

Disclaimer: You asked many different questions at once, which made your post too broad. Since this site is about making games, and parabolic motion in games is "objects falling due to gravity", here I'm interpreting your question as "How do I use delta time to make gravity affect objects' motion?".


Physics uses the equations of motion to describe the movement of bodies in space. We usually work quantities out backwards: we determine an object's velocity by analytically deriving its change of position, and its acceleration by deriving its change of velocity, and so on.

In games, we don't want to reconstruct movement, but rather simulate it. This is usually achieved in a forward fashion, by numerically integrating the equations of motion over time: we sum all external forces to compute the current total acceleration, which is used to update the object's velocity, which in turn is used to update the object's position. This happens over tiny time steps whose duration we call "delta time" or dt.

This too is numerical integration, actually — you are integrating velocity:

function love.update(dt) circle.x = circle.x + circle.dx * dt circle.y = circle.y + circle.dy * dt -- Other code... 

Here the object's constant velocity (whose components are circle.dx and circle.dy) results in uniform linear motion. You must integrate gravity too if you want it to affect the object's motion, thus updating velocity besides position. Integration methods differ in how and when they do so. For example, Euler methods integrate acceleration to update velocity, but Semi-implicit Euler does that before integrating position, whereas Explicit Euler does after:

-- Semi-implicit Euler function integrate(dt) velocity += acceleration * dt position += velocity * dt 
-- Explicit Euler function integrate(dt) position += velocity * dt velocity += acceleration * dt 

Again, in the second code block you shared, you are integrating quantities using Semi-implicit Euler and a constant acceleration:

function love.update(dt) yAcceleration = 9.8 circle.dy = circle.dy + yAcceleration circle.x = circle.x + circle.dx * dt circle.y = circle.y + circle.dy * dt -- Other code... 

You can also disregard forces and accelerations (maybe, they are too complicated to work with in the case of simple motion objects) and set the value of velocity directly; the above methods still yield.

Since numerical methods are not exact but rather cumulate numerical errors, they model systems that may not preserve their internal energy. This is why bouncing balls may jump higher and higher (the system gains energy) or travel slower and slower until stopping to rest (the system loses energy) despite friction not being a feature you actually coded. Integrators come with these and other side effects. You must choose the one that best fits your game's needs.

Further readings you may find helpful in your journey through physics, dynamic and kinematic bodies, delta time, user input, etc.:

  • Integration Basics by GafferOnGames, from his Game Physics series, tells you more about numerical integration in games.
  • Game Loop, from Game Programming Patterns, tells you how and when input, update and rendering take place during the main application loop.

The further the circle moves towards the center, the slower it seems to travel (the reason is not yet clear at this stage).

The reason is simple: acceleration and velocity are vectors, and adding vector quantities (like numerical integrators do) means adding their respective components independently. In uniformly accelerated linear motion, acceleration only affects velocity along the shared axis; in your case, gravity only affects vertical velocity, while horizontal velocity is constant all the time. Velocity at "peak height time" is lower than initial velocity at "jump time" because vertical velocity became zero due to gravity and only horizontal velocity is maintained — that's why the object seems slower: it is.

The width is narrower than I expected. When I tried adjusting the values to widen it (...), it shifted away from the center. The speed also seems slower than before I made the changes.

In game design, the "jump problem" is real. Crafting the perfect jump, i.e. finding the perfect value for jump height, jump width, jump speed, gravity acceleration, air friction... is not a trivial task. In this GDC talk, Kyle Pittman explains how to play around with formulae for Building A Better Jump (title of the talk) rather than relying on the trial-and-error approach.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ One thing to note with this discrete approach: the arc you get corresponds to the arc for continuous physics \$\vec d(t) = \vec d_0 + \vec v_0 \Delta t + \frac 1 2 \vec a \Delta t^2\$ with the initial velocity shifted by half a timestep worth of acceleration - because we're updating the position with the velocity at the start or end of the step, rather than the average over the time step. It's a simple enough difference to correct for in our initial velocity when it matters, but easy to overlook (I haven't seen it mentioned in most guides). \$\endgroup\$ Commented Dec 19, 2024 at 15:13
  • \$\begingroup\$ @DMGregory This is interesting! I knew about the continuous vs. numeric case mismatch but never found a solution to compensate for it. You reminded me of an old article, Hannu's "Doing gravity right", that illustrates a quadrature rule to "fix" Euler integrators' error. Hannu's formula integrates over dt/2 twice: it seems to "subtract half a timestep's worth of acceleration from your initial velocity" while still "using a symplectic Euler integrator with a fixed timestep". Correct? \$\endgroup\$ Commented Dec 19, 2024 at 17:47
  • \$\begingroup\$ upvoted: I've learned some of the things I wanted to know. / Since it's a matter of vector addition, I thought that if there were some general formula (or rather, a related rule) connecting yAcceleration and dx regarding the width, it might be possible to determine dx based on changes to yAcceleration. However, it doesn’t seem to be that simple. \$\endgroup\$ Commented Dec 20, 2024 at 3:51

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.