Shan Robertson
Shan Robertson

Reputation: 2742

SpriteKit Jumping and moving issues

I'm fairly new to swift, and have been working on a game for fun, and i'm running into something I can't quite get my head around.

When the run button is pressed, the character moves forward with the following function

func move(dt: CGFloat) {
  position.x += moveRate * dt
}

And when the jump button is pressed, the character jumps with the following function

func jump() {
  physicsBody?.applyImpulse(CGVector(dx: 0, dy: jumpRate))
  run(jumpAnimation!)
}

both work fine, but consider this senario. The player is running, and then they jump while still moving. While in the air, the player releases the move button and the player's x position stops dead. This obviously feels very unnatural, and i would like the player's x position to ease out.

Now i have also played with moving the character with physicsBody?.applyForce(CGVector(dx: 1000, dy: 0)) which would give that effect, but he seems to just gain more and more speed and you don't get a constant rate or "max speed" so to speak.

Could anybody share some insight with me? I'd love to learn anything I can about spritekit and game development in general. Thanks!

Upvotes: 1

Views: 829

Answers (2)

Confused
Confused

Reputation: 6278

There are two schools of thought on platformer game "physics".

  1. Don't use physics, do everything with positional incrementation.
  2. Do everything with physics, since positional changes mess up physics

Since you're using physics for jumping, and physics jumping is fun:

There are three ways to create movement in a physics system:

  1. Set the velocity as and when required. This is what Crazyrems is suggesting
  2. Apply impulses as needed to increase and decrease rates of movement
  3. Apply forces over time that increase or decrease rates of movement

  4. Use fields to induce motion (too complex for this, and messy, but fun)

What you're attempting, with your physicsBody?.applyForce(CGVector(dx: 1000, dy: 0)) is the application of force over time. Number 3 in the list above. The longer you continue applying this force the faster the character moves.

Each of these techniques can be made to work, but they all need compensation for their various limitations and methodologies of simulation.

In the case of your approach, you need monitor speed and to set a maximum speed. Having reached maximum speed, if the player is still holding the button, only provide enough force to maintain speed (assuming you're using some form of constant resistance to slow the character).

Monitoring speed combined with force-over-time creates interesting acceleration trait possibilities - like very strong initial acceleration and then taper off acceleration as the player nears their maximum speed.

Slowing down when the player releases the button is the next focus. In all these approaches you need something that slows the player. This can be the application of opposing forces, or the use of friction or damping, as provided by the physics engine.

Upvotes: 2

Crazyrems
Crazyrems

Reputation: 2591

You should try to set the velocity instead of setting the X position. When setting the position you bypass all the physics behaviors.
You should also try to set it only when you actually press a button.

func move(dt: CGFloat) {
    if Math.abs(moveRate) > 0.1 { // If player initiates movement. You can increase the value 0.1 if you want to filter move values
        velocity = CGVector(dx: moveRate, dy: veloxity.dy)
    }
}

It your character moves indefinitely like in space, linearDamping will be useful. it's used to simulate air friction, so values closer to 1 means more friction and values closer to 0 means less friction.

linearDamping = 0.85

Also, this way, moveRate isn't dt dependent but it should be lowered.


Try it, I haven't tested it yet, but that's basically how I would do it.

Upvotes: 3

Related Questions