Swift Spritekit dissipating Gravity field - ios

I have a game in swift using spritekit. If you tap the screen it will create a radial gravity field and pull all the other objects in. I create the gravity field like so
var fieldNode = SKFieldNode.radialGravityField();
fieldNode.falloff = 0.5;
fieldNode.strength = 1;
fieldNode.animationSpeed = 0.5;
It works but my problem is that I only want a sprite to be affected only when it is when it within a certain distance to the centre of the radial gravity, and i will have more than 1 sprite. The way I see it is that there are 2 ways to do it, 1. When a sprite is too far turn off the radial gravity for that sprite or 2. Make the radial gravity dissipate after a certain radius. There is also an overall gravity for the scene.
So the main question is:
How can I either turn off 1 gravity for a sprite OR make a radial gravity dissipate ?

A field node's region property determines its area of effect. The associated SKRegion object lets you define a circular region by its radius.
You can also use the fieldBitMask on a physics body and the categoryBitMask on a field to selectively control which fields affect which bodies.

Try using:
let radius: CGFloat = 1000.0
gravityField.strength = Float(pow(radius, 2)) * pow(10, -3)

Related

Put a ball inside a rectangle trapped inside, with some velocity and restitution

In this scene:
let rectangle = SKShapeNode(rectangleOfSize: CGSize(300, 400))
rectangle.fillColor = UIColor.clearColor()
rectangle.strokeColor = UIColor.grayColor()
rectangle.strokeWidth = 10
self.addChild(rectangle)
I want to put a ball inside this rectangle, trapped inside, with some velocity and restitution, that will be bouncing and changing the vector direction when collides with one of the walls.
I am not 100% sure if you can do that with SKShapeNodes and physics bodies because the physics body will apply to the whole shape node (with center).
Since you want to make the rectangle visible you can could either make a SKSpriteNode subclass with 4 SKSpriteNodes sides and than shape them as a rectangle.
Alternatively you could just draw a rectangle border in your program of choice, just make sure the centre is nothing basically, and export as PNG. Than just create a SKSpriteNode with the image.
let rectangle = SKSpriteNode(imageNamed: "Rectangle")
let texture = SKTexture(imageNamed: "Rectangle")
rectangle.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
rectangle.physicsBody?.collisionBitMask = 1
Now if you have drawn the rectangle correctly it will only have a physics body on the 4 sides since you did not draw a centre.
Than you simply create your ball and give it a physics body like above, with the same collision bitMask. Position it in the centre of the rectangle and give it an impulse or something. It should bounce around as you wish without leaving the rectangle.
If you are unsure about physics bodies than you need to read a bit about it, e.g
http://www.techotopia.com/index.php/A_Swift_iOS_8_Sprite_Kit_Collision_Handling_Tutorial

How to make a node to rotate around a point outside of the node in a spritekit game project

I came across this answer, but the answer is not clear to me. Can someone provide some sample code?
Create an SKNode and set its position to the center of rotation. Add the node that should rotate around that center as child to the center node. Set the child node's position to the desired offset (ie radius, say x + 100). Change the rotation property of the center node to make the child node(s) rotate around the center point.
Specifically, "Change the rotation property of the center node" to what?
var centerNode: SKSpriteNode = SKSpriteNode(imageNamed: "image1")
centerNode.position = CGPointMake(self.frame.width/2, self.frame.height/2)
self.addChild(centerNode)
var nodeRotateMe: SKSpriteNode = SKSpriteNode(imageNamged: "image2")
nodeRotateMe.position = CGPointMake(self.frame.width/2 + 100, self.frame.height/2 + 100)
centerNode.addChild(nodeRotateMe)
// Change the rotation property of the center node to what??
centerNode.zRotation = ?
You have a couple of options:
1) You could rotate the centerNode over time in your SKScene's update: method by changing its zRotation property manually. You'll have to change the value slowly, at every call to update: to achieve a gradual rotation.
Note that the zRotation property is in radians, with means a 180 degree rotation would be equal to pi (M_PI). SKScene strives to update: at 60 FPS, which means to rotate 360 degrees over 5 seconds, you'd need to increment by 1/300th of a degree every call to update, which would be 1/150th of pi every update.
centerNode.zRotation = centerNode.zRotation + CGFloat(1.0/150.0 * M_PI)
Of course, there is no guarantee that your scene will be able to update at 60 FPS, so you may have to monitor the currentTime variable in update: and adjust accordingly.
2) Probably better, you could use an SKAction to rotate the centerNode for you.
let rotateAction = SKAction.rotateByAngle(CGFloat(2 * M_PI), duration: 5.0)
centerNode.runAction(rotateAction)
Note that the rotation angle is in radians, not degrees. Also note that the centerNode need not be a Sprite Node if you don't want to display an image there; it could be a regular SKNode.

Spritekit physics and camera smoothing

I've been struggling with this problem for a while, which appears to be buried deep inside the spritekit physics engine.
My first question would be: Does Spritekit process its physics updates in a different thread than the main thread?
I have a "world" node in the scene which I move around to simulate a "camera" view. As such, I can center the "camera" on my player character node. Since the player jumps up and down a lot, I want to smooth the camera. Without camera smoothing, there's no problems. But when I add camera smoothing, as such: (this code is called from didFinishUpdate)
CGPoint ptPosition = self.position;
float fSmoothY = m_fLastCameraY + (ptPosition.y - m_fLastCameraY) * 0.1;
CGPoint pointCamera = [self.scene convertPoint:CGPointMake(ptPosition.x, fSmoothY) fromNode:self.parent];
[gameScene centerOnPoint:pointCamera];
m_fLastCameraY = fSmoothY;
If I call the above code from didSimulatePhysics, it does the exact same thing. It stutters whenever it falls down (due to the Y camera smoothing).
When plotting it out, you can see that the player Y (the red line) is stuttering over the course of the frames.
How can I fix this, or work around it if it can't be truly "fixed"?
I suggest you apply an infinite impulse response (IIR) filter to smooth the camera. You can do that by...
First, declare the instance variables
CGFloat alpha;
CGFloat fSmoothY;
and then Initialize alpha and fSmoothY
// alpha should be in [0, 1], where a larger value = less smoothing
alpha = 0.5;
fSmoothY = ptPosition.y;
Lastly, apply the filter with
fSmoothY = fSmoothY * (1-alpha) + ptPosition.y * alpha;

Moving layer causes physics object to stay in place

I'm fiddling around with cocos2d v3 in combination with sprite builder.
The game is a simple catch and avoid game, objects coming down an the hero is standing in the bottom of the screen and you can move him around with the accelerometer.
I have a level file (cclayer) with some objects (ccnode) in it, the have physics enabled.
In my update function I move the layer slowly down.
If the objects have physics enabled, they just drop down. If I switch it to statics physics, they stay in place.
The only way I can find to move the object along with the layer is to turn off the physics completely. But then the collisions won't work anymore...
This kept me buys for the past 4 hours or so.
What is the best approach for this situation?
Thanks in advance guys!
this is my update function:
- (void)update:(CCTime)delta {
float maxX = winSize.width - _hero.contentSize.width/2;
float minX = _hero.contentSize.width/2;
CMAccelerometerData *accelerometerData = _motionManager.accelerometerData;
CMAcceleration acceleration = accelerometerData.acceleration;
CGFloat newXPosition = _hero.position.x + acceleration.x * 1000 * delta;
newXPosition = clampf(newXPosition, minX, maxX);
_hero.position = CGPointMake(newXPosition, _hero.position.y);
//level position
CGPoint oldLayerPosition = _levelNode.position;
float xNew = oldLayerPosition.x;
float yNew = oldLayerPosition.y -1.4f;
_levelNode.position = ccp(xNew, yNew);
}
This is a design decision made within the physics engine. Physics bodies do not move with their parents. See: https://github.com/cocos2d/cocos2d-iphone/issues/570
You need to change the design of your game so that your hero moves, and the obstacles stay in the same position. Then you implement a camera like mechanism to follow your moving hero.
We have used the same approach in our flappy bird tutorial.

Cocos2D Gravity?

I am really looking to try to have gravity in my game. I know everyone says use Box2D, but in my case I can't. I need to use Cocos2D for the gravity.
I know Cocos2D does not have any gravity API built in so I need to do something manually. The thing is there is like no tutorials or examples anywhere on the web that show this.
Can anyone show me what they have done or can some explain step by step on how to apply a non-constant gravity (One that gets slightly stronger while falling).
I think this will help a lot of people that are facing the same issue that I am having!
Thanks!
Gravity is nothing but a constant velocity applied to the body for every physics step. Have a look at this exemplary update method:
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update sprite position after applying downward gravity velocity
CGPoint pos = sprite.position;
pos.y += gravity.y;
sprite.position = pos;
}
Every frame the sprite y position will be decreased. That's the simple approach. For a more realistic effect you will want to have a velocity vector for each moving object, and apply gravity to the velocity (which is also a CGPoint).
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update velocity with gravitational influence
velocity.y += gravity.y;
// update sprite position with velocity
CGPoint pos = sprite.position;
pos.y += velocity.y;
sprite.position = pos;
}
This has the effect that velocity, over time, increases in the downward y direction. This will have the object accelerate faster and faster downwards, the longer it is "falling".
Yet by modifying velocity you can still change the general direction of the object. For instance to make the character jump you could set velocity.y = 2.0 and it would move upwards and come back down again due to the effect of gravity applied over time.
This is still a simplified approach but very common in games that don't use a "real" physics engine.

Resources