Sprite-kit collison - ios

All this code in my project works fine, but I am having some problems. When the plane touches the border of the screen it starts to spin after contact. I can't figure out how to make it so it doesn't spin when it hits the border of the screen. It only has this problem when I use:
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
Other forms of definition I have no problem, but I need it to be the size of the texture.
plane = SKSpriteNode(imageNamed: sett.store() as! String)
plane.size = CGSize(width: 80, height: 80)
plane.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 4)
// scorenode collison off, makes images spin on any contact
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
plane.physicsBody?.categoryBitMask = Physics.Plane
plane.physicsBody?.collisionBitMask = Physics.Bird
plane.physicsBody?.contactTestBitMask = Physics.Bird | Physics.Score | Physics.Coin
plane.physicsBody?.affectedByGravity = true
plane.physicsBody?.dynamic = true
plane.zPosition = 2
self.addChild(plane)
// screen boarder so cant leave screen
let boredBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
boredBody.friction = 0
self.physicsBody = boredBody
My other problem is again with the the plane
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
but as well I need this so it's the size of the texture. When it hits my score node on the screen it should only add 1 point but it varies 1-about 60 points when it crosses the scoreNode. How would i fix this?
let scoreNode = SKSpriteNode()
scoreNode.size = CGSize(width: 800, height: 1)
scoreNode.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 350)
scoreNode.physicsBody = SKPhysicsBody(rectangleOfSize: scoreNode.size)
scoreNode.physicsBody?.affectedByGravity = false
scoreNode.physicsBody?.dynamic = false
scoreNode.physicsBody?.categoryBitMask = Physics.Score
scoreNode.physicsBody?.collisionBitMask = 0
scoreNode.physicsBody?.contactTestBitMask = Physics.Plane
scoreNode.color = SKColor.whiteColor()
// when scoreNode and plane touch && initates score and highScore
if firstBody.categoryBitMask == Physics.Score && secondBody.categoryBitMask == Physics.Plane || firstBody.categoryBitMask == Physics.Plane && secondBody.categoryBitMask == Physics.Score {
score += 1
if score >= highScore{
highScore = score
scoreLabel.text = "SCORE: \(score)"
highScoreLabel.text = "HIGH SCORE: \(highScore)"
let highScoreDefault = NSUserDefaults.standardUserDefaults()
highScoreDefault.setValue(highScore, forKey: "highScore")
highScoreDefault.synchronize()
} else {
scoreLabel.text = "SCORE: \(score)"
highScoreLabel.text = "HIGH SCORE: \(highScore)"
}
}

It's spining because the collision has imparted angular velocity on the physics body. This is as it should be. If you really never want an object to have angular velocity you can do that by setting the node physics body
allowsRotation property to false.
in this case it would be something like:
scoreNode.physicsBody?.allowsRotation = false
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/index.html#//apple_ref/occ/instp/SKPhysicsBody/allowsRotation

Related

Sprite-Kit Obstacle Game - PhysicsBody issues

I have created a simple 2D arcade game using SpriteKit and I am trying to add a scoring system.Basically the game is a square sprite which has to jump over various obstacles.
What I have tried so far is creating an SKSpriteNode() which adds +1 to the score counter label when it contacts the player's physicsBody. My problem is that when they contact each other the player sprite floats over the gap's PhysicsBody. I have set it's collisionBitMask to 0 and have made it isDynamic = false. Can anybody help?
Okay so here's my gap's code
var gap = SKNode()
gap.position = CGPoint(x: obstacle.position.x, y: platform.position.y + 210)
gap.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 70))
gap.physicsBody!.isDynamic = true
gap.physicsBody!.affectedByGravity = false
gap.physicsBody?.contactTestBitMask = PhysicsCategory.Player
gap.physicsBody?.categoryBitMask = PhysicsCategory.Gap
gap.physicsBody?.collisionBitMask = PhysicsCategory.None
gap.physicsBody?.restitution = 0
gap.physicsBody?.friction = 0
self.addChild(gap)
And here's my players code
let playerTexture = SKTexture(imageNamed: "white.jpg")
player = SKSpriteNode(texture: playerTexture)
player.size = CGSize(width: 40, height: 40)
player.physicsBody = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody!.isDynamic = false
player.position = CGPoint(x: self.frame.midX - 100 , y: self.frame.midY + 50 )
player.physicsBody!.restitution = 0
player.physicsBody!.friction = 0
player.physicsBody?.categoryBitMask = PhysicsCategory.Player
player.physicsBody?.contactTestBitMask = PhysicsCategory.Obstacles | PhysicsCategory.Gap
player.physicsBody?.collisionBitMask = PhysicsCategory.Obstacles | PhysicsCategory.Floor
self.addChild(player)
Physics Category is
struct PhysicsCategory {
static let None : UInt32 = 0
static let Obstacles : UInt32 = 0b1 // 1
static let Player : UInt32 = 0010
static let Floor : UInt32 = 0100
static let Gap : UInt32 = 1000
}

Detecting collision with a child of a node and another node in Swift 2

So I created a parent node named planet, that has to two children one of which is a 'landingPad'. I'm trying to detect collision between this child and another node named 'lander'. I've tried a lot of options but nothing seems to work. Thanks in advance.
func createPlanet() {
var planet = SKSpriteNode()
planet.zPosition = 1
planet.name = "mars"
redPlanet = SKSpriteNode(imageNamed: "redPlanet")
redPlanet.name = "red"
redPlanet.zPosition = 2
planet.addChild(redPlanet)
landingPad = SKSpriteNode(imageNamed: "landingPad")
landingPad.name = "pad"
landingPad.zPosition = 3
landingPad.position = CGPoint(x: 0, y: redPlanet.size.height / 2 - 60)
landingPad.physicsBody = SKPhysicsBody(texture: landingPad.texture!, size: size)
landingPad.physicsBody!.dynamic = false
landingPad.physicsBody!.categoryBitMask = landingPadMask
landingPad.physicsBody!.collisionBitMask = landerMask
landingPad.physicsBody!.contactTestBitMask = 0
planet.addChild(landingPad)
planet.position = CGPoint(x: frame.size.width / 2, y: -redPlanet.size.height / 6)
planet.physicsBody = SKPhysicsBody(circleOfRadius: redPlanet.size.height / 2)
planet.physicsBody!.dynamic = false
planet.physicsBody!.categoryBitMask = planetMask
planet.physicsBody!.contactTestBitMask = 0
let spinner = SKAction.rotateByAngle(CGFloat(M_PI), duration: 3)
planet.runAction(SKAction.repeatActionForever(spinner))
addChild(planet)
}
And the lander code...
func createLander() {
var randomX = RandomInt(min: 10, max: 400)
lander = SKSpriteNode(imageNamed: "lander")
lander.position = CGPoint(x: CGFloat(randomX), y: frame.size.height + 20)
lander.name = "lander"
lander.zPosition = 10
lander.physicsBody = SKPhysicsBody(texture: lander.texture!, size: lander.size)
lander.physicsBody!.dynamic = true
lander.physicsBody!.affectedByGravity = true
lander.physicsBody!.friction = 0.2
lander.physicsBody!.restitution = 0.75
lander.physicsBody!.linearDamping = 0.208
lander.physicsBody!.angularDamping = 0.1
lander.physicsBody!.categoryBitMask = landerMask
lander.physicsBody!.collisionBitMask = landingPadMask | cometMask
addChild(lander)
}
you are missing:
lander.physicsBody!.contactTestBitMask = landingPadMask | cometMask
and
landingPad.physicsBody!.contactTestBitMask = landerMask
And for the delegate:
self.physicsWorld.contactDelegate = self;
Then you get the collision with:
didBeginContact and didEndContact

Sprite Kit efficient random node spawn

I am searching for the most efficient way to Nodes with random SKSpriteNodes on given positions.
I have 10 Platforms, on each of them I want to have an Enemy (SKNode) that contains for 3 different SKSpriteNodes which will randomly spawn. These SKSpriteNodes all do other behaviors, thats why I can't simply change the Texture of the SKNode.
As with my Code, I wanted to spawn the same Node on different Platforms.
However, the code does not work properly, the nodes do spawn but only at 1 position(the position from the last SpawnEnemycode in didMoveToView), meaning 10 nodes at 1 position.
I also tried it with adding 10 different Enemy nodes, each given a Platform. But this just looks like a copy & paste code thats inefficient.
How can I fix my problem, or is there either another way to spawn them more efficiently?
My Code:
class GameScene: SKScene, SKPhysicsContactDelegate {
var Enemy: SKNode!
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.physicsWorld.contactDelegate = self
self.physicsBody?.velocity = CGVectorMake(0, 0)
self.anchorPoint = CGPoint(x: 0, y: 0.20)
backgroundColor = SKColor(red: 81.0/255.0, green: 192.0/255.0, blue: 201.0/255.0, alpha: 1.0)
self.Enemy1 = SKNode()
addChild(Enemy1)
SpawnPlayer()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform1.position.y + 15))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 15))
//Same code for all the other Platforms.
}
func SpawnEnemy(position: CGPoint!){
switch (arc4random_uniform(3)){
case 0:
Picture1.filteringMode = .Nearest
Picture2.filteringMode = .Nearest
Animation1 = SKAction.animateWithTextures([Picture1,Picture2], timePerFrame: 0.5)
AnimationRepeat1 = SKAction.repeatActionForever(Animation1)
Sprite1 = SKSpriteNode (imageNamed: "Sprite1.png")
Sprite1.size = CGSize(width: 64, height: 64)
Sprite1.zPosition = 2
Sprite1.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 45, height: 50))
Sprite1.physicsBody?.dynamic = true
Sprite1.physicsBody?.allowsRotation = false
Sprite1.physicsBody?.restitution = 0.0
Sprite1.physicsBody?.usesPreciseCollisionDetection = true
Sprite1.physicsBody?.categoryBitMask = EnemyCategory
Sprite1.physicsBody?.collisionBitMask = PlayerCategory | Platform1Category
Sprite1.physicsBody?.contactTestBitMask = Wall1Category | Wall2Category | PlayerCategory
Sprite1.runAction(AnimationRepeat1)
Enemy.position = position
Enemy.addChild(Sprite1)
case 1:
Picture3.filteringMode = .Nearest
Picture4.filteringMode = .Nearest
Animation1 = SKAction.animateWithTextures([Picture3,Picture4], timePerFrame: 0.5)
AnimationRepeat1 = SKAction.repeatActionForever(Animation1)
Sprite2 = SKSpriteNode (imageNamed: "Sprite2.png")
Sprite2.size = CGSize(width: 64, height: 64)
Sprite2.zPosition = 2
Sprite2.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 45, height: 50))
Sprite2.physicsBody?.dynamic = true
Sprite2.physicsBody?.allowsRotation = false
Sprite2.physicsBody?.restitution = 0.0
Sprite2.physicsBody?.usesPreciseCollisionDetection = true
Sprite2.physicsBody?.categoryBitMask = EnemyCategory
Sprite2.physicsBody?.collisionBitMask = PlayerCategory | Platform1Category
Sprite2.physicsBody?.contactTestBitMask = Wall1Category | Wall2Category | PlayerCategory
Sprite2.runAction(AnimationRepeat1)
Enemy.position = position
Enemy.addChild(Sprite2)
case 2:
Picture5.filteringMode = .Nearest
Picture6.filteringMode = .Nearest
Animation1 = SKAction.animateWithTextures([Picture5,Picture6], timePerFrame: 0.5)
AnimationRepeat1 = SKAction.repeatActionForever(Animation1)
Sprite3 = SKSpriteNode (imageNamed: "Sprite3.png")
Sprite3.size = CGSize(width: 64, height: 64)
Sprite3.zPosition = 2
Sprite3.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 45, height: 50))
Sprite3.physicsBody?.dynamic = true
Sprite3.physicsBody?.allowsRotation = false
Sprite3.physicsBody?.restitution = 0.0
Sprite3.physicsBody?.usesPreciseCollisionDetection = true
Sprite3.physicsBody?.categoryBitMask = EnemyCategory
Sprite3.physicsBody?.collisionBitMask = PlayerCategory | Platform1Category
Sprite3.physicsBody?.contactTestBitMask = Wall1Category | Wall2Category | PlayerCategory
Sprite3.runAction(AnimationRepeat1)
Enemy.position = position
Enemy.addChild(Sprite3)
default:
return
}
}
The reason you're only seeing one position is that you're only creating one "enemy" and moving it around with SpawnEnemy. Since your sprites are all added to the same "enemy", they will all show up wherever your enemy was moved to last.
Let's chop down what your code is to the relevant bits:
var Enemy: SKNode!
override func didMoveToView(view: SKView) {
self.Enemy1 = SKNode()
addChild(Enemy1)
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform1.position.y + 15))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 15))
}
func SpawnEnemy(position: CGPoint!){
switch (arc4random_uniform(3)){
case 0:
Enemy.position = position
Enemy.addChild(Sprite1)
case 1:
Enemy.position = position
Enemy.addChild(Sprite2)
case 2:
Enemy.position = position
Enemy.addChild(Sprite3)
default:
return
}
}
So, in didMoveToView(), you create one Enemy node. Then, as you call SpawnEnemy, you do a bunch of stuff to add other sprites, but as far as Enemy is concerned, you're just changing its position. Since you're adding the sprites to the same node, when you move that Enemy node, the child sprites move with it, too.
You have two options to fix this. Either add your sprites to some higher-level node (like the scene), or create new "enemy" nodes for each of the sprites you intend to add. Either should work, but the best choice will depend on what you're trying to accomplish with them - the scope of that discussion is beyond what you're talking about here.

SKSpriteNode ball not colliding with border

My ball (SKSpriteNode) is suppose to bounce of the wall that is around the screen, but it simply past through it, and disappeared from the screen.
GameScene.swift
let borderCategory: UInt32 = 1
let ball = SKShapeNode(circleOfRadius: 30)
let bCategoryName = "Ball"
let bCategory: UInt32 = 2
let paddle = SKShapeNode(rectOfSize: CGSize(width: 90, height: 35))
let pCategoryName = "Paddle"
let pCategory: UInt32 = 3
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.backgroundColor = SKColor.whiteColor()
self.physicsWorld.gravity = CGVectorMake(0, 0)
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
NSLog(String(self.frame.width) + ":" + String(self.frame.height), nil)
self.physicsBody = borderBody
self.physicsBody.friction = 0.0
self.physicsBody.categoryBitMask = borderCategory
self.physicsBody.restitution = 1.0
setupPaddle()
setupBall()
}
func setupPaddle() {
paddle.name = pCategoryName
paddle.position = CGPointMake(CGRectGetMidX(self.frame), paddle.frame.size.height * 0.6)
paddle.fillColor = SKColor.blackColor()
self.addChild(paddle)
paddle.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 90, height: 35))
paddle.physicsBody.restitution = 0.1
paddle.physicsBody.friction = 0.4
paddle.physicsBody.dynamic = false
paddle.physicsBody.categoryBitMask = pCategory
paddle.physicsBody.collisionBitMask = bCategory
}
func setupBall() {
ball.name = bCategoryName
ball.position = CGPointMake(self.frame.size.width/2, paddle.position.y+paddle.frame.height+10)
ball.fillColor = SKColor.blackColor()
self.addChild(ball)
ball.physicsBody = SKPhysicsBody(circleOfRadius: 30)
ball.physicsBody.friction = 0.0
ball.physicsBody.restitution = 1.0
ball.physicsBody.linearDamping = 0.0
ball.physicsBody.angularDamping = 0.0
ball.physicsBody.allowsRotation = false
ball.physicsBody.dynamic = true
ball.physicsBody.categoryBitMask = bCategory
ball.physicsBody.collisionBitMask = borderCategory
}
The output for NSLog(String(self.frame.width) + ":" + String(self.frame.height), nil)
is 1024.0:768.0, ran on iPhone 5S, IOS8.
How do i solve this problem? I believe that self.frame is the problem, but i already changed my the controller view from viewDidLoad to viewWillLayoutSubview.
EDIT 1: I noticed that the ball is now bouncing after setting the boundary's restitution to 1.0. BUT, I realised the ball is bouncing in an unknown region. It is bouncing out of the screen, then return back. The weird thing is it can bounce once it hit the top of the screen, but it won't hit side of the screen
EDIT 2: I realised another problem, UIDevice.currentDevice().orientation.isPortrait returns false, but yet I'm running my game in portrait mode
EDIT 3: If I changed orientation to landscape, the ball can escape out of the screen from the top and bottom by a little then bounce back, the ball bounces off the side of the screen correctly. But now the paddle is below the screen.

SpriteNode is not visible

I'm trying to create my User SpriteNode with the following Methode. The texture is Kladde and the Image is not empty too.
func spawnPlayer() {
if didFirstTap == true && isGameOver == false {
let collisionMask = CollisionCategory.Surrounding.rawValue | CollisionCategory.Platform.rawValue
let x = self.frame.size.width / 4
let y = CGRectGetMidY(self.frame)
let node = SKNode()
node.position = CGPointMake(frame.size.width + playerTexture!.size().width, 0)
playerNode = SKSpriteNode(texture: playerTexture)
playerNode!.setScale(1.0)
playerNode!.position = CGPointMake(x, y)
playerNode!.speed = 1.0
playerNode!.zRotation = 0.0
playerNode!.physicsBody = SKPhysicsBody(circleOfRadius: playerNode!.size.height / 2)
playerNode!.physicsBody?.dynamic = true
playerNode!.physicsBody?.allowsRotation = false
playerNode!.physicsBody?.categoryBitMask = CollisionCategory.Player.rawValue
playerNode!.physicsBody?.contactTestBitMask = collisionMask
playerNode!.physicsBody?.collisionBitMask = collisionMask
playerNode!.physicsBody!.velocity = CGVectorMake( 0, 0 )
node.addChild(playerNode!)
addChild(node)
}
}
I Hope someone knows, why my Node is invisible?
Look at where the node is spawning:
node.position = CGPointMake(frame.size.width + playerTexture!.size().width, 0)
Then on top of that you move the player in the position of the node
let x = self.frame.size.width / 4
let y = CGRectGetMidY(self.frame)
playerNode!.position = CGPointMake(x, y)
This poor guy is way outside of the screen space.

Resources