1
\$\begingroup\$

I am trying to calculate the y velocity necessary for my player character to jump up and reach a y position within 1 second.

Given that my game engine is at 60fps, I am doing:

velY = (targetY - playerY) / 60

.. However, I need to account for gravity which is being applied to the character on every update, so I am doing:

velY = ((targetY - playerY) / 60) - (gravity * 60)

This results in the player character always jumping significantly higher than expect.

UPDATE

Attempting to try the Equations of Motion approach, I am setting a timestamp when the player character should begin moving to the target position... So then in my update loop, I am calling a function with currentTime - timestamp.

update: function(paceFactor) {
    // paceFactor in this game engine is how many nominal 60FPS game “ticks” have elapsed. So if the game is running at 30FPS, then paceFactor will be 2.0, if it's 60FPS, then 1.0 will be passed in.

  this.timer += paceFactor * (1 / 60);

  if (this.setVelocityAt) {
    this.setVelocityFor(this.timer - this.setVelocityAt, this.targetPoint);
  }

  this.position.x += this.vel.x * this.speed * paceFactor;
  this.position.y += this.vel.y * this.speed * paceFactor;
  this.position.y += (gravity * (paceFactor * paceFactor) * 0.5);
  this.vel.y += gravity * paceFactor;
},

setVelocityFor: function(time, target) {
  if (time > 1) {
    time = 1;
    this.setVelocityAt = undefined;
  }
  this.character.vel.x = (target.x - this.character.position.x) / time;
  this.character.vel.y = (target.y + (0.5 * GRAVITY * time * time) - this.character.position.y) / time;
},

Then later the position and gravity is applied to the character as described in the previous update.

However, the velocity being set is a huge number which is... wrong.

\$\endgroup\$
5
  • \$\begingroup\$ Also, wouldn't hurt to see the code where you apply the velocity to your character's position. \$\endgroup\$
    – mt_
    Dec 12, 2018 at 1:43
  • \$\begingroup\$ Regarding the updated part: your position.y is affected by gravity twice. You should only apply gravity to your velocity and not to the position directly. So you shouldn't do "this.position.y += (gravity * (paceFactor * paceFactor) * 0.5);" because you already affect the velocity by gravity and then you add that velicy to your position. \$\endgroup\$
    – mt_
    Dec 12, 2018 at 4:06
  • \$\begingroup\$ I believe your paceFactor use is also incorrect. If the paceFactor is 1 given 60FPS, then it means that each frame you're applying the full gravity to your velocity which is too much. I think you should instead define a frameTime or timeDelta = paceFactor / 60f; and replace paceFactor with timeDelta in your formulas. \$\endgroup\$
    – mt_
    Dec 12, 2018 at 4:12
  • \$\begingroup\$ @mt_, I updated my question again to reflect the changes I made to your point about applying gravity twice. I was following the section "motion with acceleration" media.readthedocs.org/pdf/flynn/latest/flynn.pdf .. I'm not quite sure about your 2nd point. The behavior of gravity in the game seems to work pretty well as is, but if I do as you suggest then I have to increase my gravity constant to behave similarly, but then the vel.y = -Math.sqrt(2 * (gravity_constant * paceFactor / 60) * Math.abs(targetY - playerY)) still results in the player jumping way higher than desired/expected. \$\endgroup\$
    – patrick
    Dec 12, 2018 at 21:04
  • \$\begingroup\$ Possible duplicate of How to implement deceleration and stopping over a certain distance \$\endgroup\$ Dec 13, 2018 at 22:52

2 Answers 2

2
\$\begingroup\$

You are going to need to use the Equations of Motion.

This is because the velocity is not constant over the time frame. You cannot calculate distance traveled by velocity and time alone.

One way to do this is to calculate the distance at each time step. (The other way would be to use a parametric equation based on the calculated start and end points)

How to do this? You know the initial velocity u, the time step t, and the acceleration g.

Using the equations of motion we will find the final velocity v and the distance travelled s.

s = u * t + 0.5 * g * t * t

v = u + g * t

Now it's the end of the time step, you can translate the player by distance s and set the next initial velocity to be the calculated final velocity.

Edit:

To put it into code, try this to update the y component. It includes the velocity and gravity as well

this.position.y += this.vel.y * paceFactor - 0.5 * gravity * paceFactor * paceFactor;
this.vel.y += -gravity * paceFactor;

Edit 2:

Here is a javascript snippet that shows how jumping is supposed to work with gravity. You can change the frame increment (paceFactor in your game) and the jumping will be consistent. There is an update loop that basically only changes the value of y and vel_y.

<html>
<body>
<canvas id="exampleCanvas" width="50" height="300"></canvas>
</body>
<script>
var x = 0;
var y = 0;
var vel_y = 0;
var g = 1;
var c = document.getElementById("exampleCanvas");
var ctx = c.getContext("2d");
var jumpHeight = 250;
var jumpImpulse = Math.sqrt(2 * g * jumpHeight);

function loop(timestamp) {

  // Note that changing update(1) to update(2) changes the speed of the simulation.
  // It does not change how high the player can jump
  update(1);

  // Request the next frame
  window.requestAnimationFrame(loop);
}


function update(t) {

  // Do a jump
  if (y >= 250)
  {
y = 250; // Snap player to the Ground level
vel_y = -jumpImpulse; // Jump speed
  }

  // Do the motion (update y and vel_y)
  var dist = vel_y * t + 0.5 * g * t * t
  vel_y = vel_y + g * t
  y += dist;

  // Draw a square
  ctx.clearRect(0, 0, c.width, c.height);

  ctx.beginPath();
  ctx.rect(x, y, 50, 50);
  ctx.stroke();
}


// Start the loop
window.requestAnimationFrame(loop);

</script>
</html>

\$\endgroup\$
15
  • \$\begingroup\$ I guess that's what I don't quite understand... If I know the distance desired to travel over 1 second, and I know how much gravity is applied over 1 second, then should not the (distance - total_gravity_distance) / 1_second be the velocity? \$\endgroup\$
    – patrick
    Dec 12, 2018 at 19:43
  • \$\begingroup\$ I'm not quite sure I understand what you mean... In reality, the velocity will be changing continuously, so when you simulate it over one second you will overshoot if you use a constant velocity. \$\endgroup\$
    – Jay
    Dec 13, 2018 at 0:56
  • \$\begingroup\$ I updated my question where I am now trying the approach you recommended... Somehow I am getting a really large velocity value which is wrong... \$\endgroup\$
    – patrick
    Dec 13, 2018 at 21:53
  • \$\begingroup\$ Don't use the velocity directly. Use both lines of code, the first one updates the position using velocity and gravity together. The second one updates the velocity. If you are getting too large results it might be to do with the gravity and time values. Are you counting time in seconds or milliseconds? \$\endgroup\$
    – Jay
    Dec 13, 2018 at 23:48
  • \$\begingroup\$ I don't understand what you mean by "don't use the velocity directly." What I am trying to do is similar to this: youtube.com/watch?v=X08oIPJPFX8&t=144s ... Player jumps on a trampoline and has options of platforms to jump onto. So there needs to be a y velocity calculated that will allow the character to reach the ceiling before gravity pulls them back down, and then on the way up, the player can press left/right and it will calculate a velocity that will allow the player to reach the target point for the closest platform. \$\endgroup\$
    – patrick
    Dec 14, 2018 at 4:47
1
\$\begingroup\$

This should work, given that you want to be at 0 speed along y once you reach it:

distY = (targetY - playerY);
velInitialY = Mathf.Sqrt(-2f * gravityY * distY); // Want to make sure what's passed to Sqrt is not negative

This assumes that your gravity that you insert here is signed and that this is how you're updating your actual velocity each frame when in air:

velY += gravityY * timeDelta;
posY += velY * timeDelta;
\$\endgroup\$
3
  • \$\begingroup\$ You know, I also had tried this exact formula previously but could also not get it to work right... It also results in the character moving much higher than they should... I'm so confused at what is going on, I must be doing something else wrong somewhere else... I have updated my original question with how I apply gravity. \$\endgroup\$
    – patrick
    Dec 12, 2018 at 3:47
  • \$\begingroup\$ @patrick Is the engine you're using called Flynn by any chance? \$\endgroup\$
    – mt_
    Dec 12, 2018 at 4:16
  • \$\begingroup\$ yes, it is Flynn. \$\endgroup\$
    – patrick
    Dec 12, 2018 at 17:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .