applyForce(0, 400) - SpriteKit inconsistency

maxhud picture maxhud · Nov 7, 2013 · Viewed 9k times · Source

So I have an object that has a physicsBody and gravity affects it. It is also dynamic.

Currently, when the users touches the screen, I run the code:

applyForce(0, 400)

The object moves up about 200 and then falls back down due to gravity. This only happens some of the time. Other times, it results in the object only moving 50ish units in the Y direction.

I can't find a pattern... I put my project on dropbox so it can be opened if anyone is willing to look at it.

https://www.dropbox.com/sh/z0nt79pd0l5psfg/bJTbaS2JpY

EDIT: It seems this happens when the player is bouncing off of the ground slightly for a moment after impact. Is there a way I can make it so the player doesn't bounce at all?

EDIT 2: I tried to solve this using the friction parameter and only allowing the player to "jump" when the friction was = 0 (you would think this would be all cases where the player was airborne) but friction appears to be greater than 0 at all times. How else might I detect if the player is touching an object (other than by using the y location)?

Thanks

Answer

godel9 picture godel9 · Nov 7, 2013

Suggested Solution

If you're trying to implement a jump feature, I suggest you look at applyImpulse instead of applyForce. Here's the difference between the two, as described in the Sprite Kit Programming Guide:

You can choose to apply either a force or an impulse:

A force is applied for a length of time based on the amount of simulation time that passes between when you apply the force and when the next frame of the simulation is processed. So, to apply a continuous force to an body, you need to make the appropriate method calls each time a new frame is processed. Forces are usually used for continuous effects.

An impulse makes an instantaneous change to the body’s velocity that is independent of the amount of simulation time that has passed. Impulses are usually used for immediate changes to a body’s velocity.

A jump is really an instantaneous change to a body's velocity, meaning that you should apply an impulse instead of a force. To use the applyImpulse: method, figure out the desired instantaneous change in velocity, multiply by the body's mass, and use that as the impulse parameter into the function. I think you'll see better results.

Explanation for Unexpected Behavior

If you're calling applyForce: outside of your update: function, what's happening is that your force is being multiplied by the amount of time passed between when you apply the force and when the next frame of the simulation is processed. This multiplier is not a constant, so you're seeing a different change in velocity every time you call applyForce: in this manner.