Weird Spritekit Collision Bug depending on SKSpriteNode position - ios

I'm having a weird Spritekit issue where my moving SKSpriteNode is passing through a fixed SKSpriteNode depending on the position of the fixed SKSpriteNode.
UPDATE: Code works in simulator but not on real device.
Example:
Placing my bin SKSpriteNode at position x: -500, y: 100 works fine and my moving SKSpriteNode collides as expected.
Placing my bin SKSpriteNode at position x: -600, y: 100 DOES NOT work and my moving SKSpriteNode DOES NOT collide with the bin.
Using view.showsPhysics = true shows that there is physics bodies in both cases.
x values between -500 and -508 work as expected. All other values I have tried did not work.
Collisions with my other fixed SKSpriteNodes work as expected.
enum CollisionTypes: UInt32 {
case Plane = 1
case FloorAndRoof = 2
case OtherObject = 4
case FinishPoint = 8
}
Code to create levels
func createLevel(level: Int) {
switch level {
case 1:
createFloor()
createRoof()
createTable(position: CGPoint(x: 750, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -500, y: 100)) // THIS IS THE PROBLEM LOCATION
createFinishPoint(position: CGPoint(x: -500, y: 100))
break
case 2:
createFloor()
createRoof()
createTable(position: CGPoint(x: 250, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -600, y: 100))
createFinishPoint(position: CGPoint(x: -300, y: 200))
break
default:
break
}
}
Moving SKSpriteNode
func createPlane() {
plane = SKSpriteNode(imageNamed: "plane1")
plane.name = "plane1"
//plane.position = CGPoint(x: -UIScreen.main.bounds.width + plane.size.width , y: 0)
plane.position = CGPoint(x: 0, y: 300)
plane.zPosition = 1
//plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.texture!.size())
plane.physicsBody = SKPhysicsBody(texture: planeTexture, size: planeTexture.size())
plane.physicsBody?.allowsRotation = true
plane.physicsBody?.categoryBitMask = CollisionTypes.Plane.rawValue
plane.physicsBody?.collisionBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue // dont collide with finish point
plane.physicsBody?.contactTestBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue | CollisionTypes.FinishPoint.rawValue
plane.physicsBody?.usesPreciseCollisionDetection = true
plane.physicsBody?.isDynamic = true
plane.physicsBody?.friction = 1
plane.physicsBody?.restitution = 0
plane.physicsBody?.mass = 0.1 // customise for different planes
plane.physicsBody?.angularDamping = 1
plane.physicsBody?.linearDamping = 0.2 // customise for different planes
liftFactor = 0.1 // customise for different planes
addChild(plane)
flightMode = 4 // dead, should drop to floor and change to mode 0 when at rest
//print(flightMode)
}
Bin SKSpriteNode that moving Plane should collide with.
func createBin(position: CGPoint) {
binFront = SKSpriteNode(imageNamed: "binFront")
binFront.name = "binFront"
binFront.setScale(0.15)
binFront.position = position
binFront.zPosition = 2 // in front of plane
addChild(binFront)
binBack = SKSpriteNode(imageNamed: "binBack")
binBack.name = "binBack"
binBack.setScale(0.15)
binBack.position = position
binBack.zPosition = 0 // behind plane
addChild(binBack)
binPhysicsBody = SKSpriteNode(imageNamed: "binPhysicsBody")
binPhysicsBody.name = "binPhysicsBody"
binPhysicsBody.physicsBody = SKPhysicsBody(texture: binPhysicsBody.texture!, size: binPhysicsBody.texture!.size())
binPhysicsBody.setScale(0.15)
binPhysicsBody.physicsBody?.allowsRotation = false
binPhysicsBody.physicsBody?.categoryBitMask = CollisionTypes.OtherObject.rawValue
binPhysicsBody.physicsBody?.collisionBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.contactTestBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.usesPreciseCollisionDetection = false
binPhysicsBody.physicsBody?.isDynamic = false
binPhysicsBody.physicsBody?.friction = 1
binPhysicsBody.physicsBody?.restitution = 0
binPhysicsBody.physicsBody?.mass = 50
binPhysicsBody.position = position
binPhysicsBody.zPosition = 0
addChild(binPhysicsBody)
}

I still don't know the cause of my issue but I got around it by changing the image used to create my physics body. I used a slightly thicker 'wall thickness' on the bin.

Related

SKSpriteNode creates a thin coloured line

So I am using 3 SKSpriteNode's in my application. floorSprite, leftWall and rightWall.
This is the code I am currently using:
let floorSprite = SKSpriteNode()//(imageNamed: "floor")
floorSprite.alpha = 0.0
floorSprite.anchorPoint = CGPoint(x: 0.5, y: CGPoint.zero.y)
floorSprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.size.width, height: floorSprite.size.height + 12))
floorSprite.physicsBody?.isDynamic = false
floorSprite.physicsBody?.restitution = 0.4
floorSprite.position = CGPoint(x: self.frame.minX, y: self.frame.minY + (floorSprite.size.height / 2))
floorSprite.physicsBody?.contactTestBitMask = 0x1 << 1
floorSprite.physicsBody?.collisionBitMask = 0x1 << 1
floorSprite.zPosition = 4
floorSprite.aspectFillToSize(self.frame.size)
self.addChild(floorSprite)
self.floorSprite = floorSprite
let leftwall = SKSpriteNode()
leftwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
leftwall.physicsBody?.collisionBitMask = 0x1 << 1
leftwall.physicsBody?.isDynamic = false
leftwall.position = CGPoint(x: 0 , y: self.frame.size.height / 2.0)
leftwall.zPosition = 4
leftwall.physicsBody?.restitution = 1.0
self.addChild(leftwall)
let rightwall = SKSpriteNode()
rightwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
rightwall.physicsBody?.collisionBitMask = 0x1 << 1
rightwall.physicsBody?.isDynamic = false
rightwall.physicsBody?.restitution = 1.0
rightwall.position = CGPoint(x: self.frame.size.width , y: self.frame.size.height / 2.0)
rightwall.zPosition = 4
self.addChild(rightwall)
Here is a screenshot of the issue I have. You can see the light blue lines that shows. If I remove the self.addChild line, the Sprite is not there, and the light blue color gone.
CLICK HERE FOR IMAGE.
Any ideas what might be wrong here? I have tried adding leftWall.isHidden = true and leftWall.alpha = 0.0 but that has no effect...
This looks like you have SKScene.showPhysics on.. turn this off in your appdelegate (or didmovetoview) or wherever you turned it on, and the lines should go away.
These are caused by your physics bodies :)

Rotate object under gravity force

I'm trying to create a scenario where there's a radial gravity field. In this scene, there's also an object built by two physics bodies with a different mass.
When I run this code, the radial gravity field is created correctly and the body goes to gravityCenter.
I'm expecting that the body rotates too because the head is heavier than the tail but this doesn't happend.
Why?
class GameScene: SKScene {
let object = SKSpriteNode(imageNamed: "myobj")
let myCategory : UInt32 = 0x1 << 0
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
let gravityCenter = SKFieldNode.radialGravityField()
gravityCenter.isEnabled = true
gravityCenter.position = CGPoint(x: size.width, y: size.height * 0.5)
gravityCenter.strength = 0.5
addChild(gravityCenter)
object.position = CGPoint(x: size.width * 0.1, y: size.height * 0.9)
object.scale(to: CGSize(width: 100, height: 25))
let head = SKPhysicsBody(circleOfRadius: object.size.width/5, center: CGPoint(x: object.size.width/2, y: 0))
let tail = SKPhysicsBody(circleOfRadius: object.size.width/50, center: CGPoint(x: -object.size.width/2, y: 0))
head.mass = 500
head.categoryBitMask = myCategory
head.allowsRotation = true
head.isDynamic = true
head.angularDamping = 0
head.affectedByGravity = true
tail.mass = 2
tail.categoryBitMask = myCategory
tail.allowsRotation = true
tail.isDynamic = true
tail.angularDamping = 0
tail.affectedByGravity = true
object.physicsBody = SKPhysicsBody(bodies: [head, tail])
object.physicsBody?.categoryBitMask = myCategory
object.physicsBody?.allowsRotation = true
object.physicsBody?.isDynamic = true
object.physicsBody?.angularDamping = 0
object.physicsBody?.affectedByGravity = true
addChild(object)
}
}
Well, from a physics standpoint SpriteKit is behaving correctly. If you think about it, more mass does mean more gravitational force, but it also means more inertia, which exactly cancels out the increased force. Perhaps introduce a little bit of linearDamping into the tail? That would get the body to rotate by making the head drag the tail a little bit.

Positioning SKSpriteNodes in GameScene

I am having a little bit of trouble positioning two SKSpriteNodes correctly in my GameScene. My nodes appear in the scene, but they are zoomed in and take up most of the entire scene. I would to have the output similar to this:
Here is my current code:
let size = CGRect(x: 100, y:98, width:200, hight:271)
bottomRectangle = SKSpriteNode(imageNamed: "bottomRectangle")
bottomRectangle.zPosition = 3
bottomRectangle.size.height = self.size.height
bottomRectangle.size.width = self.size.width
bottomRectangle.position = CGPoint(x: 200, y:271)
bottomRectangle.physicsBody = SKPhysicsBody(edgeLoopFromRect: size)
self.addChild(bottomRectangle)
topRectangle = SKSpriteNode(imageNamed: "topRectangle")
topRectangle.physicsBody = SKPhysicsBody(edgeLoopFromRect: size)
topRectangle.zPosition = 4
topRectangle.size.height = self.size.height
topRectangle.size.width = self.size.width
topRectangle.position = CGPoint(x: 100, y: 98)
self.addChild(topRectangle)
You are using the size of the scene, because of:
self.size.height
You have to use you local variable:
size.height

How to create a node in another node

I have a circle, an SKShapeNode, and I want to create a child node inside it. How I can do this?
func AddCircle() {
Circle = SKShapeNode(circleOfRadius: circleRadius)
Circle.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
Circle.strokeColor = UIColor.whiteColor()
self.addChild(Circle)
Circle.addChild(BooCharacter)
}
Main Character:
func AddCharacter() {
BooCharacter.size = CGSize(width: 30, height: 30)
BooCharacter.anchorPoint.y = 0
BooCharacter.zRotation = CGFloat(-M_PI_2)
BooCharacter.position.y += circleRadius
}
I want to create an object in my circle but I don't know how you write it.
For example, I've tried to add a rect inside of my circle:
func AddRect() {
Rect = SKShapeNode()
Rect.path = UIBezierPath(roundedRect: CGRect(x:0, y: 250, width: 256, height: 256), cornerRadius: 64).CGPath
Rect.fillColor = UIColor.whiteColor()
}
func AddCircle() {
Circle = SKShapeNode(circleOfRadius: circleRadius)
Circle.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
Circle.strokeColor = UIColor.whiteColor()
self.addChild(Circle)
Circle.addChild(BooCharacter)
Circle.addChild(Rect)
but it's still not working.
I want to create and add triangles inside of my circle like this
You're doing exactly the right thing, although I don't see where BooCharacter is being created – are you definitely creating that somewhere? Using addChild() to add a node to your scene, or to add one node to another node, is correct, and should work for all types of SKNode.

Pause in SpriteKit game

func pause() {
pausedSpeed = self.speed
self.speed = 0
backgroundMusicPlayer.pause()
worldNode.alpha = 0.7
resumeButton = SKShapeNode(rectOfSize: CGSize(width: 100, height: 50))
resumeButton.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 - 50)
resumeButton.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 100, height: 50))
resumeButton.name = resumeButtonName
pauseLabel = SKLabelNode(text: "PAUSED")
pauseLabel.fontSize = 100
pauseLabel.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 100)
pauseLabel.fontColor = UIColor.blackColor()
worldNode.addChild(resumeButton)
worldNode.addChild(pauseLabel)
}
Even thought I set self.speed to 0, a node still keeps moving. Any ideas why this might be happening?
Do not change the speed of the node. Just change node.paused = true
In your case, you should define all your control buttons on one SKNode, and declare all the game elements on another SKNode. In that case, if you want to pause the game, just make the second SKNode pause.

Resources