Edge based SKPhysicsBody moves over time - ios

I am using the following code to put a floor in my SpriteKit based game:
var floorNode = SKSpriteNode()
var floorBody = SKPhysicsBody(edgeFromPoint: CGPointMake(self.frame.minX, self.frame.minY), toPoint: CGPointMake(self.frame.maxX, self.frame.minY))
floorNode.physicsBody = floorBody
addChild(floorNode)
This places a floor at the bottom of the screen as expected. However as I add more things to the scene, one end of the floor eventually sinks down and everything in the scene that is resting on it slides off into the abyss.
I am at a complete loss here since Apple's documentation says that "an edge-based body does not have mass or volume, and is unaffected by forces or impulses in the system. Edge-based bodies are used to represent volume-less boundaries or hollow spaces in your physics simulation."
Anyone else seen this kind of behavior?

The easiest way to define floor for your scene, without adding any nodes to it:
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
where self is your SKScene.
If you don't want ceiling on the scene, define physicsBody as this:
[SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height*5)];

Related

How to make a Sprite an obstacle for another Sprite?

I am making a game with sprites that move and obstacles to learn SpriteKit. I want the sprites that move to collide with the obstacles and bounce off of them but I want the obstacles to stay fixed. How do I do this? I have tried the following with no success:
Setting obstacle.physicsBody?.isDynamic = true. This made the sprites go through the obstacle.
Fixing the movement and rotation of the object with SKConstraint. When I do this they just go through each other.
Setting the mass of the body to be really high as follows obstacle.physicsBody?.mass = CGPoint.maxFiniteMagnitude but this freezes the game. When I set it really high it doesn't seem to do anything.
Setting obstacle?.physicsBody.velocity = CGVector(dx: 0, dy: 0) when the objects collide. I know that the contact.bodyA and contact.bodyB are passed by value and not reference so I loop through an array with the obstacles and set the velocity this way. The obstacles are still pushed by the other sprites.
Update:
- Setting obstacle.physicsBody?.collisionBitMask = PhysicsCategory.none so the sprite collides with the obstacle but not the other way around.
The object is setup as follows, with fish being the other sprite:
obstacle.position = location
obstacle.physicsBody = SKPhysicsBody(rectangleOf: obstacle.size)
obstacle.physicsBody?.isDynamic = true
obstacle.physicsBody?.categoryBitMask = PhysicsCategory.obstacle
obstacle.physicsBody?.contactTestBitMask = PhysicsCategory.fish
obstacle.physicsBody?.collisionBitMask = PhysicsCategory.fish
obstacle.physicsBody?.usesPreciseCollisionDetection = true
self.obstacles.append(obstacle)
super.addChild(obstacle)
Please let me know if there is something I am doing wrong / misunderstanding. Thanks.
Found the answer here. One of the objects needs to have .physicsBody?.isDynamic = true. In this case I set the obstacle to false so it is stationary.

How to stop a sprite from bouncing off a specific surface

Hi I am making a endless scrolling game where the character basically avoids obstacles as they come and he can jump over them. I got everything to work pretty well but I see that the character texture will bounce slightly after hitting the ground. I want the sprite to stop immediately after touching down. I tried setting the .restitution property to 0 but i still see it bouncing. Here is the setup code for my stickman character and the edge physics category in question
stickman.physicsBody?.dynamic = true
stickman.physicsBody?.allowsRotation = false
stickman.physicsBody?.usesPreciseCollisionDetection = true
stickman.physicsBody?.categoryBitMask = PhysicsCategory.Stickman
stickman.physicsBody?.collisionBitMask = PhysicsCategory.Edge
stickman.physicsBody?.contactTestBitMask = PhysicsCategory.Obstacle | PhysicsCategory.Edge
stickman.physicsBody?.restitution = 0
self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
physicsBody = SKPhysicsBody(edgeLoopFromRect: playableRect)
physicsWorld.contactDelegate = self
physicsBody?.categoryBitMask = PhysicsCategory.Edge
Where playable rect is just the screen boundary for universal deployment purposes.
Has anyone run into this problem. I couldn't quite find the same issue in other posts.
Set the restitution of the physics body your sprite is running into to 0 as well. Both physics bodies in a physics collision need to have a restitution of 0 to result in no bounciness.

Swift Spritekit dissipating Gravity field

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)

Weird shaking with hinge joint in Scene Kit

i'm trying to make a join, tank with turret, but because of this joint whole model is shaking, do you have any ideas what causing this behaviour?
Link to project: Project
this is how i made it:
SCNNode *tankNode = [extraScene.rootNode childNodeWithName:#"Main_Body" recursively:YES];
[tankNode setScale:SCNVector3Make(0.003, 0.003, 0.003)];
[tankNode setPosition:SCNVector3Make(0, 1, 0)];
[tankNode setPhysicsBody:[SCNPhysicsBody dynamicBody]];
[tankNode setRotation:SCNVector4Make(0, 1, 0, -M_PI_2)];
[scene.rootNode addChildNode:tankNode];
SCNNode *turretNode = [tankNode childNodeWithName:#"Turret" recursively:YES];
turretNode.physicsBody = [SCNPhysicsBody staticBody];
SCNNode *gunNode = [turretNode childNodeWithName:#"gun" recursively:YES];
gunNode.physicsBody = [SCNPhysicsBody staticBody];
SCNPhysicsHingeJoint *gunJoint = [SCNPhysicsHingeJoint jointWithBodyA:turretNode.physicsBody axisA:SCNVector3Make(0,0,1) anchorA:SCNVector3Make(0.1,0.1,0.1) bodyB:gunNode.physicsBody axisB:SCNVector3Make(0,0,1) anchorB:SCNVector3Make(0.1,0.1,0.1)];
[scene.physicsWorld addBehavior:gunJoint];
SCNPhysicsHingeJoint *turretJoint = [SCNPhysicsHingeJoint jointWithBodyA:turretNode.physicsBody axisA:SCNVector3Make(0,1,0) anchorA:SCNVector3Make(0.1,0.1,0.1) bodyB:tankNode.physicsBody axisB:SCNVector3Make(0,1,0) anchorB:SCNVector3Make(0.5,0.5,-0.1)];
[scene.physicsWorld addBehavior:turretJoint];
I think there are two problems:
you are are assigning a constraint between a node and one of its child node (turret and tank). This is unlikely to give the expected results since a child node position is relative to its parent (so let's say the constraint moves the parent node, it will also move the child node).
you are assigning a constraint between two static bodies (gun & turret) - this should have no effect
Im only guessing here but i'd imagine you are placing a joint inside tankNode's physics body due to the fact you have scaled the tankNode, but not its physics shape.
Remember scaling a SCNNode does not scale its physics shape.
If you need your tank to be scaled : ensure you scale the physics body as well -
SCNVector3 Scale=SCNVector3Make(0.003, 0.003, 0.003);
Then your physics shape should be scaled :
NSDictionary *options=[NSDictionary dictionaryWithObject:
[NSValue valueWithSCNVector3:Scale] forKey:SCNPhysicsShapeScaleKey];
Now create a physics body from the scaled shape :
SCNPhysicsShape *physicsGeometry=[SCNPhysicsShape shapeWithGeometry:tankNode.geometry options:options];
Finally add the physics shape to your tank
tankNode.physicsBody=[SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:physicsGeometry];
Your physics body and Tank node are now the same size.
If you require physics on the cannon and turret, i.e. the cannon needs to collide, create its physics body the same way..
Your code would suggest that turret and gun are children of the tank. The best / easiest way is to parent the turret to the gun so the gun is a child of the turret, and then parent the turret to the tank. This way, moving the tank moves the gun, turret and tank, Moving the turret moves the turret and the gun, and moving the gun only moves the gun.
Also in your 3d authoring software don't forget to move the pivot to the required centre of rotation for each node (or set it using SCNNode.pivot property).
You won't even need to use joints at all in this circumstance if the parent / child hierarchy is correct :)
I hope this helps.

sprite kit collisions: ignore transparency?

I am building a game with Xcode's spritekit. Its a platform game and right now it functions well with flat ground pieces. I was wondering if it was possible to ignore transparency in the png for collisions. That is to say, If i have a ground piece with a curved floor and transparency filling the troughs, can i make the player walk the curves instead of a square bounding box covering the whole thing? The only example i can find is in the Gamemaker GML language, you can do "precise" collisions such that blank space in the images do not count as part of the sprite. I can supply code if necessary but this seems like more of a conceptual question. Thanks in advance
Hey there's a easy solution for this provided in the Apple Documentation.
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
sprite.physicsBody = [SKPhysicsBody bodyWithTexture:sprite.texture size:sprite.texture.size];
This creates a physics body around the physical paths of the texture.
Simulating Physics - SpriteKit Programming Guide
It's all in how you instantiate the physicsBody of the node in question.
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node.size];
is probably the easiest and most common way of making a physicsBody, but will also create the issue you've identified above, because, for all collision purposes, the node is a rectangle.
take a look at the documentation for SKPhysicsBody to see the other options available to you. PolygonFromPath and BodyWithBodies are probably the best suited for what you're doing.
SKPhysicsBody is the right move, just wanted to note that it does make sense to have a separate (simplified) mask-image for SKPhysicsBody to improve your performance, simplified from color and geometry standpoint, and here's the code:
let birdMask: UInt32 = 0x1 << 0
let pipeMask: UInt32 = 0x1 << 1
//...
pipeImage = SKSpriteNode(imageNamed: "realImage")
//... size and position
let maskTexture = SKSpriteNode(imageNamed: mask)
maskTexture.size = pipeImage!.size // size of texture w/ real imageNamed
pipeImage!.physicsBody?.usesPreciseCollisionDetection = true
pipeImage!.physicsBody = SKPhysicsBody(texture: maskTexture.texture!, size: size)
pipeImage!.physicsBody?.affectedByGravity = false // disable falling down...
pipeImage!.physicsBody?.allowsRotation = false
pipeImage!.physicsBody?.isDynamic = true
pipeImage!.physicsBody?.friction = 0
pipeImage!.physicsBody?.categoryBitMask = pipeMask
pipeImage!.physicsBody?.collisionBitMask = birdMask | pipeMask
pipeImage!.physicsBody?.contactTestBitMask = birdMask | pipeMask
and more detailed example/guide.

Resources