Physics not Detecting Collision - ios

I simply have put a square shape node onto a scene, and made the physicsBody for the scene be the edge of the screen. I turned on the physics view so you can see all of the physics stuff. The square has a physics body around it, as does the border of the scene. However, when the square runs into the border, nothing happens. The square just passes straight through. Here is how I initialize the square:
let rect1 = CGRect(x: 100, y: 100, width: 50, height: 50)
let square = Square(rect: rect1)
square.fillColor = UIColor.blackColor()
square.zPosition = 200
square.physicsBody = SKPhysicsBody(edgeLoopFromRect: rect1)
square.physicsBody?.allowsRotation = false
square.physicsBody?.affectedByGravity = false
square.physicsBody?.restitution = 0.4
self.addChild(square)
Here is how I initialize the physics body for the scene:
let physicsBody = SKPhysicsBody(edgeLoopFromRect: view.bounds)
self.physicsBody = physicsBody
Very similar code has worked for me on other games, so I am not sure why no collisions happen. Any help is greatly appreciated thanks!

The movement of the balls must be caused by physics rather than just setting the position. The issue was fixed through using impulses to move the balls which then made them collide with the various objects.

Related

How do I stop physicsbody's from falling in SpriteKit?

I am making a game in Swift using spritekit and I want 2 objects on screen, one that I move with the touchesMoved function (player) and the other to stay still in its position in the screen (cell).
I wanted to make the objects physicsbody's so that I could work out collisions between them, but now whenever the scene loads the objects fall straight away. And the object moved through touch falls as soon as the user stops touching the screen.
Here's all of the code relating to the object that should stay stationary in the scene and I am unsure what makes it fall.
//Defining the cell
let cell = SKSpriteNode(imageNamed: "cell.png")
override func didMove(to view: SKView){
self.physicsWorld.contactDelegate = self
cell.physicsBody?.categoryBitMask = cellCategory
cell.physicsBody?.contactTestBitMask = playerCategory
cell.physicsBody?.isDynamic = true
cell.physicsBody = SKPhysicsBody(rectangleOf: cell.frame.size)
//Adding the cell to the scene
cell.position = CGPoint(x:size.width * 0.9, y:size.height * 0.9)
cell.size = CGSize(width: 50, height: 50)
addChild(cell)
Any help in what makes the object fall and how I can stop it from happening would be greatly appreciated.
Gravity is by default on. You can either turn it off entirely by setting the gravity property of the scene's physicsWorld:
// somewhere in the scene's initialization, or in didMove if you like
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
See https://developer.apple.com/documentation/spritekit/skphysicsworld for info on that.
Or you can turn off whether individual objects are affected by gravity. E.g.,
let body = SKPhysicsBody(circleOfRadius: 10.0)
body.affectedByGravity = false
See https://developer.apple.com/documentation/spritekit/skphysicsbody, and in particular, https://developer.apple.com/documentation/spritekit/skphysicsbody/1519774-affectedbygravity
You have a different problem in that you're setting the properties of your cell's physics body before you're creating it. cell.physicsBody?... = will not assign anything until cell.physicsBody exists. So those assignments must be moved after you create cell.physicsBody = SKPhysicsBody(rectangleOf: ...)

How to calculate an SKPhysicsBody on the fly while animating a sprite?

In my original build, my sprites were static, so to make the collision physics as accurate as I could rather than use rectangleOfSize for SKPhysicsBody passing in the node, I used this tool to define a path SpriteKit's SKPhysicsBody with polygon helper tool.
However now I'm animating the sprites so that they move back and forth during gameplay (obviously my physics path remains static given the above) so my physicsbody no longer matches what the player sees on screen.
The helper tool seemed like a bit of hack that Apple would eventually fix in the API, has there been anything recent in SpriteKit that would help me out here so that I can pass in the node and define a precise physicsbody rather than the hard-coded approach? If not, any other alternatives?
Not sure how performant this is but you can pre-generate the physics bodies for each texture then animate the sprite along with its physicsBody using a custom action.
Here is an example:
func testAnimation() {
var frameTextures = [SKTexture]()
var physicsBodies = [SKPhysicsBody]()
for index in 1...8 {
// The animation has 8 frames
let texture = SKTexture(imageNamed: "guy\(index)")
frameTextures.append(texture)
let physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
physicsBody.affectedByGravity = false
physicsBodies.append(physicsBody)
}
let sprite = SKSpriteNode(texture: frameTextures[0])
let framesPerSecond = 16.0
let animation = SKAction.customAction(withDuration: 1.0, actionBlock: { node, time in
let index = Int((framesPerSecond * Double(time))) % frameTextures.count
if let spriteNode = node as? SKSpriteNode {
spriteNode.texture = frameTextures[index]
spriteNode.physicsBody = physicsBodies[index]
}
})
sprite.run(SKAction.repeatForever(animation));
sprite.position = CGPoint(x: 0, y: 0)
addChild(sprite)
}

didBeginContact() called before contact occurred

I have two sprite nodes where I have made sure both self.size and the size of their respective physics bodies is the same, but I still get a very odd behavior like this:
The photo is taken as the collision has been detected and i paused the scene. Why does this happen?
Here is the code for setting the different sizes:
Inside init() of my Player class (circular node):
super.init(texture: texture, color: color, size: CGSize(width: 100, height: 100))
then:
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2, center: self.position)
Turn on physics visual representation in you GameViewController.swift, like this:
skView.showsPhysics = true
self.size in your case probably referring to the scene. What you need is to set physics body's size like this:
yourNode.physicsBody = SKPhysicsBody(rectangleOfSize: yourNode.size)
Also keep in mind that if you are altering node's anchor point,you may end up with unexpected results. Anchor point defines how texture is drawn relative to the node. It has no effect on node's physics body.

In SpriteKit on iOS, scaling a textured sprite produces an incorrect frame?

I'm learning SpriteKit game development for the fun of it & I've run across a seemingly simple problem that has me stumped.
Basically, after I scale a textured SKSpriteNode, the frame is NOT what I expect. I have figured out a few hacks to force it to what I want, but I'm trying to understand what is going on. Any ideas appreciated!
Here's my code WITHOUT SCALING:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
// spaceship.setScale(0.50)
let debugFrame = SKShapeNode.init(rect: spaceship.frame)
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)
self.addChild(spaceship)
}
And my app looks like this:
Now, if I comment back in the line of code which scales it (spaceship.setScale(0.50)), I get this:
Notice that the spaceship is scaled down in the second image, but the frame is scaled even smaller. Why?
If I move the scaling line to after I add the spaceship to the scene, it does what I expect, but that seems wrong:
Here's the code with setScale called after adding the spaceship to the scene:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
let debugFrame = SKShapeNode.init(rect: spaceship.frame)
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)
self.addChild(spaceship)
spaceship.setScale(0.50)
}
And here is what running my app looks like then:
So that works, but why is it necessary?
It has been suggested below, that this is a bug with SKShapeNode. But, replacing the SKShapeNode with an SKLabelNode has the same problem:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
spaceship.setScale(0.50)
let scoreNode = SKLabelNode(text: "100")
scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame))
scoreNode.fontColor = SKColor.redColor()
scoreNode.fontSize = 15.0
scoreNode.fontName = "Monaco"
scoreNode.zPosition = 10.0
spaceship.addChild(scoreNode)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)
self.addChild(spaceship)
}
which gives us:
The intent is to have the score label (scoreNode) centered above the rocket, but as you can see it is on top of the top porthole. There is just something wrong with the spaceship's frame after I call spaceship.setScale.
I have made one additional discovery: the setScale call does not need to be after I add the spaceship to the scene. It just needs to be after I add the debugFrame/scoreNode to the spaceship. If I setScale AFTER that point, all is well:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
let scoreNode = SKLabelNode(text: "100")
scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame))
scoreNode.fontColor = SKColor.redColor()
scoreNode.fontSize = 15.0
scoreNode.fontName = "Monaco"
scoreNode.zPosition = 10.0
spaceship.addChild(scoreNode)
spaceship.setScale(0.50)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)
self.addChild(spaceship)
}
which results in:
Your problem may be in the order of these two lines :
spaceship.setScale(0.50)
let debugFrame = SKShapeNode.init(rect: spaceship.frame)
You scaled down the spaceship and then calculate the size of the rectangle with the scaled spaceship. Then when rendering the rectangle is scaled down to half its size which is quarter of the original spaceship size.
If you swap the lines, it should work as expected.
In general, it is better to make compose in the real size and then scale the whole just before adding it to the scene.
First of all, let me preface with SKShapeNode is a really funky (maybe buggy class). At least it was in previous iterations of spritekit. If your goal is to add a debug rectangle for physics purposes. You can turn on showsPhysics on your SKView class inside of your GameViewController
Heres my experiment
let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100))
redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
redbox.setScale(0.5)
let debugFrame = SKShapeNode(ellipseOfSize: redbox.size)
debugFrame.strokeColor = SKColor.greenColor()
self.addChild(redbox)
redbox.addChild(debugFrame)
looks same as yours. if i call setScale after i add the nodes then my circle fills up my red square.
Also if I keep everything the same, but I just add my debugframe to the scene directly it will be scaled the right way, weird huh??
ok another test. note I set greenbox to 50% of redboxes size so we can see the redbox beneath. If the bug was occuring here than greenbox would end up filling 25% of the redbox.
let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100))
redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
redbox.setScale(0.5)
let greenbox = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 50, height: 50))
self.addChild(redbox)
redbox.addChild(greenbox)
Ok so i did the same thing using another SKSpriteNode, and it behaves the way we'd expect. So for whatever reason, when you use an SKShapeNode as a child.. setScale is being called twice on it; unless you set the scale after adding the nodes to the scene. But this doesnt happen with SKSpriteNode.
The answer is.. I don't think there's a good answer. It's probably a bug. SKShapeNode has a history of bugs. SpriteKit has a few bugs =/ Someone correct me if I'm wrong.

How to fix a node in a position using SpriteKit

I have created a world using SpriteKit, containing a SKShapeNode. I'd like to tie it into the ceiling. The gravity and other stuff still have their effect on this shape, but it should hang from the ceiling. Like a lamp, or a rope.
My shape:
let shape = SKShapeNode(rectOfSize: CGSize(width: self.tamanhoQuadrado, height: self.tamanhoQuadrado))
When I add this:
shape.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: self.tamanhoQuadrado, height: self.tamanhoQuadrado))
It falls to the ground. I haven't found a property that can ignore gravity.
Found it!
//no gravity
shape.physicsBody!.affectedByGravity=false
//make it stay on it's place
shape.physicsBody!.dynamic=false

Resources