Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit - Making a sprite defy gravity (like a balloon)

Tags:

ios

sprite-kit

Does anyone have any idea how I can make my SKSpriteNode defy gravity? I thought of inverting the default gravity but realise I also need things to fall too!

It seems like it should be easy but reading through the documentation I can’t see how I would do it!

Thanks

like image 437
Adam Carter Avatar asked Dec 09 '22 07:12

Adam Carter


2 Answers

Update: In iOS 8 / OS X Yosemite (10.10), physics fields provide an elegant solution to these sorts of problems. Here's a quick take on using them to add buoyancy (for a specific set of nodes) to your scene.

  1. Create an SKFieldNode with the linearGravityFieldWithVector constructor, providing a vector that's the opposite of gravity, and add the field node to your scene.
  2. Set the fieldBitMask on your balloons to something unique.
  3. Set the categoryBitMask on the field to something that overlaps with the balloons' fieldBitMask, but that does not overlap with the fieldBitMask of any other bodies.

Now, the balloons will rise or hold steady, but other objects will fall. Tweaking the field's strength will let you tune whether the balloons' buoyancy is perfectly balancing gravity (so that they float in place, but are disturbed when touched), or slightly more or less than gravity (so that they slowly rise or fall).

By default, a field is infinite, covering the whole scene, but you can change that with the field's region property to limit it to a portion of the scene. (This is useful if you want to simulate buoyancy in water — once an object rises past the top of the field at the water's surface, it falls back in.)

Also, if you want variable buoyancy as per @TheisEgeberg's answer, you can control its variation over distance with the falloff property.

In iOS 7 / OS X Mavericks (10.9), or if you want more precise control over which forces apply where and when, you can use the approach from my original answer below.


If you want an object to really float like a balloon — that is, to be buoyant, affected by gravity but also counteracting it — you'll need to apply a force to it on every frame (i.e. in your update: method).

Beware scaling: gravity is a constant acceleration, but if you're applying a force to counteract gravity, a force is proportional to mass. To make a vector that perfectly balances gravity for use in applyForce:, you'll need to:

  1. scale the gravity vector by {-1,-1,-1} to point in the opposite direction
  2. scale by the mass of the body you're applying the force to (F = ma, where gravity or anti-gravity is a).
  3. scale by 150 — there's a bug where the SKPhysicsWorld.gravity property isn't in the same units as applyForce:. (If you turn SKPhysicsWorld gravity off and use SKFieldNode gravity instead, you don't need to do this.)

Unlike turning off affectedByGravity and applying an action to make the balloon rise, this approach works well with the rest of the physics sim. With a balancing force exactly equal to gravity, the balloon will float in place — after colliding with other things it'll return to equilibrium. If the balancing force is greater than gravity, the balloon will rise, but its rise will be hindered by other bodies in its way.

like image 135
rickster Avatar answered Dec 20 '22 11:12

rickster


First off, an SKSpriteNode isn't affected by gravity at all. It is the SKPhysicsBody that belongs to the node that is affected by gravity.

Second...

myNode.physicsBody.afectedByGravity = NO;

:D

If you want it to rise upwards then you can add an action to it...

SKAction *moveAction = [SKAction moveByX:0 y:-10 duration:1];

SKAction *repeatingAction = [SKAction repeatActionForever:moveAction];

[myNode runAction:repeatingAction];
like image 26
Fogmeister Avatar answered Dec 20 '22 10:12

Fogmeister