Make a SCNNode drop using gravity? - ios

I have a SceneKit setup and have one Sphere in it that is setup as a Dynamic body.
I am able to run the app and see the sphere drop on the static body floor.
What I am trying to do is setup the scene so the sfere initially does not drop.
Then when a function is run I want the sfere to drop.
what is the correct logic / steps to make the scene suddenly (maybe when a button is pressed or something) drop the sphere?
I have tried also to set the sphere to mass 0 and then set the mass to 100 but it does not cause the drop...

Mass doesn't control how fast something falls. This is true in the real world, but more so in simulations that take shortcuts instead of simulating every detail of real-world physics. (Sadly, iOS devices still don't have the CPU power to account for the rotating reference frame of the Earth, the Van der Waals attraction between your sphere and any body especially close to it, the strong force that keeps its triangles atoms together, etc etc.) In SceneKit, gravity is just a constant acceleration in a specific direction.
Setting mass to zero and switching it to something else interferes with the distinction between static/kinematic and dynamic bodies... so don't do that.
As #mnuages notes, you can add/remove the physics body from your sphere when you want it to be affected or unaffected by physics entirely.
But what if you want to keep the sphere's physics body for other reasons—such as allowing other bodies to collide with it even before you make it start falling? There are a few approaches you could use for that:
Set the sphere body's damping to 1.0.
Set the sphere body's velocityFactor to zero (at least in the direction of gravity).
Both of those will keep the sphere from moving when something else hits it. If you want the ball to get knocked around, but not be affected by gravity, the best thing to do might be to switch out scene gravity for physics fields:
Set scene.physicsWorld.gravity to SCNVector3Zero.
Add a SCNPhysicsField created with the linearGravityField constructor to your scene, and set its direction and strength to get the kind of gravity behavior you want.
Set the categoryBitMasks on both your sphere body and the gravity field such that the field affects other bodies but not the sphere.
Whichever of these methods you use, you can change them when you want to "turn gravity on" for the sphere: reduce the damping, reset the velocityFactor, or change the sphere's or the gravity field's categoryBitMask.

As of iOS 9, you can set the isAffectedByGravity property to false then flip the value to true to make the sphere drop: https://developer.apple.com/reference/scenekit/scnphysicsbody/1514738-isaffectedbygravity

setting a physics body to sphere only when you want to it to be affected by gravity should work.

Related

PhysicsBody stays after translation and rotation

I have a node with a cube attached which represents for example a door. The physicsbody type is .static. If i animate the node up, rotate it and animate it down to the orignial position of the physicsbody stays in the upper position.
In the debug mode the color of the phyisicsbody is first grey (i asume grey = .static), after the translation up, the physicsbody stays at the bottom. As soon as I rotate the node in the upper position, the physicsbody becomes green and moves up to the nodes position. After I translate the node down to the original position, the physicsbody stays in the upper position. Why is this behaviour? Is this because the type is .static?
I know if I set the physicsbody type to .kinematic (shown red in debug) mode it works as expected. The physicsbody adapts the translations and rotations. But with .static type I can place more objects before the fps drops than with .dynamic.
From the documentation for SCNPhysicsBodyTypeStatic we learn that it is
A physics body that is unaffected by forces or collisions and cannot move
However you can use resetTransform to explicitly tell the engine that the node has moved and that the physics body needs to be updated:
If you change the position or orientation of a node with an attached
static or dynamic physics body, call this method afterward to ensure
that the physics simulation incorporates the change. You need not call
this method for kinematic bodies.
Note that dynamic and physics bodies
are designed to be moved only by the physics simulation or not at all.
You may use this method to move them regardless of this restriction,
but at a cost to performance.

SpriteKit & Swift Ball Speed

I have made a game using SpriteKit and Swift 3 and have figured out all aspects of the game except the speed of the ball node in the game. Im confused with the different function applyImpulse() and ball.physicsBody.velocity, as I have tested both and don't seem to really understand what the speed I'm actually programatically settings is. Any clarification on what I should be using would be great?
Also whilst testing (by printing the ball's velocity to the console every collision) I would see sometimes the ball's speed would simply go to some long and random decimal value when it hit other nodes such as a paddle which I hadn't specifically coded anything to happen with the ball's speed in the case of a collision with it.
In summary I would appreciate:
Just general clarification regarding speed of the ball in SpriteKit and how I should approach it (what method/function I should use)
How I would make it so the ball's speed doesn't got to these very long random decimals
Thanks
In regards to the values, there is not really a set rule of what the values are for impulses and forces. It depends on how big your sprites physics body are etc. An impulse of 80 might be a perfect jump value for 1 sprite size, but than make it half the size and that 80 is suddenly way to high. There are also factors such as gravity, mass etc than can have an effect on this.
So you usually just play around with the values until you get the desired result.
In regards to the collision with the paddle, you need to check your bit mask values and your dynamic properties. SpriteKit by default sets collisions to all objects, so if you dont specifically tell your paddle/ball to ignore each other they will collide.
There are also things such as restitution, friction, damping etc that can have an effect on how you sprites behave when colliding.
There are loads of tutorials on google about SpritKit physic/collisions or read the apple documentation.
In regards to the difference between velocity and impulses/forces, as per apples documentation
"First, you can control a physics body’s velocity directly, by setting its velocity and angularVelocity properties. As with many other properties, you often set these properties once when the physics body is first created and then let the physics simulation adjust them as necessary. For example, assume for a moment you are making a space-based game where a rocket ship can fire missiles. When the ship fires a missile, the missile should have a starting velocity of the ship plus an additional vector in the direction of the launch.
When a body is in the simulation, it is more common for the velocity to be adjusted based on forces applied to the body. Another source of velocity changes, collisions, is discussed later."
https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Physics/Physics.html
So basically the general rule of thumb is this:
1) Only set the velocity property when you create the physics body. I never needed to do this for my games yet.
The only time I really use the velocity property is for things such as double jumping where I need to set it to 0 to have a consistent double jump
...velocity.dy = 0
...applyImpulse(
2) When you are playing the game already than
a) If you are trying to continuously move your ball you should use
applyForce...
in something like the update method of your SKScene.
b) If you want to make your ball jump, so basically a short 1 time thing, you should use
applyImpulse...
Hope this helps

Create one or multiple gravitational points in sprite-kit scene

As this question, I want to add some gravity in my sprite-kit scene. But the difference is my scene objects should be attracted to a point (at the middle of the scene). Or to multiple points.
I'm pretty sure I found something like that on the web, but I can't find it again.
I there a common way to acheive this, or should I calculate my own forces in the update: method?
Thanks
I believe all you have to do is add gravity field nodes, and then turn OFF the gravity of the physicsWord so that your objects don't fall "down". You might have to set up some invisible borders to prevent the objects from orbiting the gravity field nodes, or possibly set a really friction.
You can also set the field strength of the gravity field nodes, which may save you from having to calculate the forces manually.
To turn off gravity (swift notation):
physicsWorld.gravity = CGVectorMake(0, 0)

How would I build pool-cues / simplified pinball-style plungers with SpriteKit?

I'm working on a game in which the user should be able to trigger 'rods' that come out from the edge of the screen to displace elements on screen (balls). These projectiles roughly resemble pool-cues. Or perhaps pinball plungers, except that they start from the 'loaded' position (mostly offscreen), and when triggered, they eject out, then quickly retreat.
I'm unclear how I should build these with Sprite Kit.
The game uses the PhysicsEngine, and the onscreen balls should be effected both by gravity AND they should be displaced when they collide with the rods. However the rods should neither be effected by gravity, not displaced when they collide with the balls -- they should simply retreat regardless of whether they've made contact with the balls.
I realize I can set the affectedByGravity property for the rods. However because they will still displace slightly when they collide with the balls. How can I 'fix' or 'peg' them in place? Do I need to use an SKPhysicsSlidingJoint? If so, has anyone encountered any examples online? Is there a simpler way to do this?
A related physics engine, Box2D distinguishes static, kinematic, and dynamic bodies.
Kinematic bodies can move and will collide with other objects, but they are themselves not affected by dynamic bodies or forces like gravity. Thus, consider setting rod.dynamic = NO; but animate it with actions. See also here in the reference for SKPhysicsBody.

Box2D / cocos2d animation to a point with rotation

I'm pretty new to Box2D and cocos2d. I'm trying to do something which I thought would be pretty simple, but it is turning out to be more difficult than I had expected and I cannot find a working answer anywhere.
Basically, I want to move a b2body and rotate it to a certain point with animation.
I can get it to the correct position and rotation with:
targetBody->SetTransform(b2Vec2(10.0f,1.0f),10);
But I have no idea how to animate it there over time. I tried using cocos2d animation on the sprite used for the body, but that doesn't do anything. Any ideas?
There are a couple of ways you could do this.
You could use SetTransform every time step to update the position of the body gradually over time, in effect performing the animation yourself. The drawback with this method is that the body is 'teleporting' to the new position rather than moving, so it has no momentum, which means you can get odd results if it hits anything along the way. Still, if you know it will not hit anything or does not need to react to a collision this would be ok.
The other way is to SetLinearVelocity and SetAngularVelocity to give the body proper movement. This will keep the results of a collision realistic, and you don't need to keep updating anything every timestep. On the other hand, you will need to detect when the body has arrived at the desired position and then set the velocities back to zero, otherwise it will just keep moving. For dynamic bodies you will also need to counter gravity somehow, either by setting the gravity scale of the body to zero, or by applying an upwards force to balance gravity, or by changing the body type to kinematic during the move.
In general, you use Box2D to simulate the physical behavior of objects in relation to each other. The rules of mechanics implemented by Box2D dictate how your cocos2d CCSprites move if you continuously update the translation and rotation of your sprites according to their corresponding Box2d b2Body. You will have some kind of repeatedly invoked tick: method in which you step your Box2d world along in time, and in which you update your sprite positions according to simulation results of Box2d.
This pattern corresponds to b2Bodys of type b2_dynamicBody. Physical laws dictate the motion of the body in this case, and your sprites will follow these simulation results. This is why setting a conflicting position of a sprite by means of a CCAction or even directly will be undone almost instantaneously with the next tick:.
Solution 1: kinematic body type
However, there do exist other modes for a b2Body, and one of these is b2_kinematicBody in which the translation is no longer governed by the world but by the velocities or angular speeds you dictate through setters. So it would be one solution to work with body type b2_kinematicBody as in:
b2BodyDef bdef;
bdef.type = b2_kinematicBody;
With this you would manipulate the velocity and angular speed of a b2Body explicitly. In this case, Box2d is still responsible for moving bodies around, but according the velocities you dictate, and without any force effects of collision or gravity applied to this particular body. Also with this strategy, your CCSprites will follow b2Bodys. Setting conflicting positions for your sprites directly or by applying a CCAction would not make sense for the same reason as described above.
Solution 2: decouple sprites from Box2d
An alternative way to animating sprites would be to fully decouple those sprites from Box2d. In this case, you would simply not have any b2Body that governs the position of the sprite you are going to animate. Now, in this case, only you will dictate the position and rotation of your CCSprite, i.e. directly either through its position property or by applying a CCAction.

Resources