2
\$\begingroup\$

In my game, I currently move the player by directly setting its velocity on key press events. This makes the game feel very responsive and allows the user to quickly change direction.

However, I would like to implement knockback and elements like conveyor belts that should push the player around. My first idea was to add a bool underControl; variable that was set to false when the player was under the effect of an external force, but it didn't work well in practice.

Then I thought of another way: how about adding the exact required force to move/stop the player at a desired velocity instead of acting on the velocity itself? It would allow the user to move and stop like if velocity itself was being set, but also allow external forces to act on the player.

Basically I want this:

if(someKeyPressed()) player.setVelocityX(100); else player.setVelocityX(0);

to be expressed like this:

if(someKeyPressed()) 
    player.applyForce(getForceRequiredToReach(100, player.getVelocityX());
else
    player.applyForce(getForceRequiredToReach(0, player.getVelocityX());

Vec2f getForceRequiredToReach(float mDesiredVelocity, float mCurrentVelocity)
{
    // What goes in here?
}

How can I implement the getForceRequiredToReach function?

\$\endgroup\$
  • \$\begingroup\$ Velocity always apply on X ? If yes, then the force required is the difference between current and desired: mCurrentVelocity - mDesiredVelocity. However this will do instant stop, so you may want to apply a fraction of this result each frame to smooth the stop \$\endgroup\$ – Jonathan Muller Nov 19 '13 at 14:28
  • \$\begingroup\$ @Koren: Velocity is both on X and Y. I showed X just as an example. I'll try using the difference, as I want an instant stop. \$\endgroup\$ – Vittorio Romeo Nov 19 '13 at 14:38
  • \$\begingroup\$ @Koren: it doesn't seem to work - the player accelerates at unexpectedly high velocities \$\endgroup\$ – Vittorio Romeo Nov 19 '13 at 14:44
  • \$\begingroup\$ @Koren: sorry for the triple post: it's the other way around: mDesiredVelocity - mCurrentVelocity. It seems to work well! Post it as an answer, I'll accept it. \$\endgroup\$ – Vittorio Romeo Nov 19 '13 at 14:46
  • 1
    \$\begingroup\$ Glad it worked ! Sorry for the inversion \$\endgroup\$ – Jonathan Muller Nov 19 '13 at 14:47
3
\$\begingroup\$

As discussed in comments,

float getForceRequiredToReach(float mDesiredVelocity, float mCurrentVelocity)
{
    return mDesiredVelocity - mCurrentVelocity;
}
\$\endgroup\$
  • \$\begingroup\$ This is not returning a force. It is returning a velocity. If you ever starting using proper physics in your games, these things will become an issue. Looking again, I fail to see how this works at all, unless you're getting lucky. \$\endgroup\$ – Almo Nov 19 '13 at 15:05
  • \$\begingroup\$ @Almo: my objects are massless: every frame I add computer force to acceleration, add acceleration to velocity and clear acceleration. \$\endgroup\$ – Vittorio Romeo Nov 19 '13 at 15:15
  • \$\begingroup\$ If your object is massless, then adding a force will not change its velocity or acceleration. F=ma. \$\endgroup\$ – Almo Nov 19 '13 at 15:20
  • 2
    \$\begingroup\$ So it's not a force at all. Force has units of kg*m/s^2. \$\endgroup\$ – Almo Nov 19 '13 at 15:36
  • 7
    \$\begingroup\$ Hey, calm down everyone. It's hardly uncommon to call things a "force" in simple games that just have velocity and acceleration when talking about a change to acceleration. It might not be accurate to classical physics terminology but it gets the point across. If it helps, interpret "massless" as "everything is uniformly m=1" rather than m=0. \$\endgroup\$ – Sean Middleditch Nov 19 '13 at 17:45
0
\$\begingroup\$

This is my code from a little platformer I made. Not sure if it will have the effects you want, but it's way of moving the player using forces. I used Java with Box2D, in case you're wondering. (The code isn't very cleaning as it was for testing mostly, but it works. :P)

    if (keys.get(Keys.LEFT)) {
        float desiredVel = -6f;
        float velChange = desiredVel - collidable.getBody().getLinearVelocity().x;
        float impulse = collidable.getBody().getMass() * velChange;       
        collidable.getBody().applyLinearImpulse((new Vector2(impulse, 0f)), collidable.getBody().getWorldCenter());
    }

    if (keys.get(Keys.RIGHT)) {
        float desiredVel = 6f;
        float velChange = desiredVel - collidable.getBody().getLinearVelocity().x;
        float impulse = collidable.getBody().getMass() * velChange;
        collidable.getBody().applyLinearImpulse((new Vector2(impulse, 0f)), collidable.getBody().getWorldCenter());
    }
\$\endgroup\$
  • \$\begingroup\$ For the record, you are not using forces. You are using impulses; they are subtly different. \$\endgroup\$ – Almo Nov 19 '13 at 15:04
  • 1
    \$\begingroup\$ Like you said, it's not recommended to use forces. :P I tried it and it was somewhat of a not good experience. It should have the same net effect of adding a force to the player so that he reacts with other forces more realisticly unlike when setting the velocity directly. \$\endgroup\$ – Pat Nov 20 '13 at 6:40
  • \$\begingroup\$ Yeah, we were using impulses in a lot of places in Tiny Brains. \$\endgroup\$ – Almo Nov 20 '13 at 11:47
0
\$\begingroup\$

I cannot recommend using forces to set velocities. Using forces is for altering a player's acceleration, not for setting velocities.

If you know what velocity you want, just set it. If you want something to reach a certain velocity over time, use some kind of interpolation, setting the velocity as you go.

Forces become even more complicated when you remember that the results from forces are dependent upon the mass of the object being acted upon.

\$\endgroup\$
  • 1
    \$\begingroup\$ Did you read the question? I think I gave some fair motivations on why I want to use forces instead of velocity. \$\endgroup\$ – Vittorio Romeo Nov 19 '13 at 14:38
  • \$\begingroup\$ I did read the question. I've written a whole lot of player control stuff, having been a gameplay programmer for over a decade. My experience has been that using forces usually causes more problems than it solves, unless what you're really after is in fact changing accelerations, or you're in need of something like realistic car physics. \$\endgroup\$ – Almo Nov 19 '13 at 14:44
0
\$\begingroup\$
Vec2f getForceRequiredToReach(float mDesiredVelocity, float mCurrentVelocity)
{
    // What goes in here?
}

The function prototype will not allow the function to work as you expect. You are passing two scalars and you are expecting a vector as return value. Since, as you stated in an comment, your objects are without mass, so you need to treat acceleration rather than force. Given the current velocity and the desired velocity as scalar you can calculate the required acceleration (also a scalar) to reach the desired velocity within some time (let's call it t)

float getAccelerationRequiredToReach(float mDesiredVelocity, float mCurrentVelocity, float t)
{
    return (mDesiredVelocity - mCurrentVelocity) / t;
}

If you apply this acceleration for the time of t on your object it will slow down/ speed up to the desired velocity.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.