Sprite-Kit Obstacle Game - PhysicsBody issues - ios

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
}

Related

SKSpriteNode fall off the screen

Can some body help me, I created a SpriteKit ​node called(player) and once I set its physics it fall off the screen​:
let player = SKSpriteNode(imageNamed: "car")
player.position.x = -300
player.zPosition = 1
player.physicsBody = SKPhysicsBody(texture: player.texture!, size: player.size)
player.physicsBody.categoryBitMask = 1
addChild(player)
I already tried adding
affectedByGravity
but the same result for the player and the enemy.
If I got it, you want your car not to be effected by gravity.
If it is so you might want to setup the physics of your "world", like:
func setWorld() {
self.backgroundColor = UIColor.white
//This should do the trick!
physicsWorld.gravity = CGVector(dx:0, dy:0)
//This is useful if you want to create wall along the borders
let frame = CGRect(x: self.frame.minX, y: self.frame.minY, width: self.frame.width, height: self.frame.height)
//here you set the borders as walls
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
physicsBody?.friction = 0
physicsBody?.restitution = 1
physicsBody?.linearDamping = 0
}
and call this function in didMove

Restitution not working on ANYTHING in SpriteKit

I have tried creating bitmask categories, setting all restitution values to 1 and everything else under the sun including running the application an a device and it still is not working at all. After setting an SKSpriteNode with retitution 1 to hit another skspritenode also with restitution one at dx: 100, it still doesn't bounce! Here is my code for GameScene.swift:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let Ball = SKSpriteNode()
Ball.self.childNode(withName: "Ball")
let playerPaddle = SKSpriteNode()
playerPaddle.self.childNode(withName: "playerPaddle")
let computerPaddle = SKSpriteNode()
computerPaddle.self.childNode(withName: "computerPaddle")
let ballCategory: UInt32 = 0x1 << 1
let paddleCategory: UInt32 = 0x1 << 2
let borderCategory: UInt32 = 0x1 << 3
Ball.physicsBody?.categoryBitMask = ballCategory
playerPaddle.physicsBody?.categoryBitMask = paddleCategory
computerPaddle.physicsBody?.categoryBitMask = paddleCategory
self.physicsBody?.categoryBitMask = borderCategory
let playerScore = SKLabelNode()
playerScore.fontName = "Pong Score"
playerScore.text = "0"
playerScore.fontSize = 100
playerScore.color = SKColor.white
playerScore.position = CGPoint(x: -200, y: 220)
playerScore.zPosition = 3
addChild(playerScore)
let comScore = SKLabelNode()
comScore.fontName = "Pong Score"
comScore.text = "0"
comScore.fontSize = 100
comScore.color = SKColor.white
comScore.position = CGPoint(x: 200, y: 220)
comScore.zPosition = 3
addChild(comScore)
var comScoreInt: Int = Int(comScore.text!)!
comScoreInt += 1
comScore.text = String(comScoreInt)
var playerScoreInt: Int = Int(playerScore.text!)!
playerScoreInt += 1
playerScore.text = String(playerScoreInt)
let bodyBorder = SKPhysicsBody(edgeLoopFrom: self.frame)
bodyBorder.friction = 0
bodyBorder.restitution = 1
self.physicsBody = bodyBorder
}
}
PS most all of the physics is in GameScene.sks not GameScene.swift, however this is where the bitmasks are.
EDIT:
Ball Config;
Position x:0, y:0, z:0,
Rotation: 0,
Size: w:25, h:25,
Anchor Point: x:0.5, y:0.5,
Color: white,
Blend Factor: 0,
Blend Mode: alpha,
Alpha: 1,
Ik Constraints: min:0, max:360,
Scale: x:1, y:1,
PHYSICS
Body Type: bounding rect,
only dynamic checked,
Friction: 0,
Restitution: 1,
Linuar Damp:0,
Angular damp: 0,
Category, Collision, and Field mask: 4294967295,
Contact Mask: 0
Inital Velocity: dx:100 dy:0
Paddles are the same physics wise
PLEASE HELP!
Insead of applying an Inital Velocity in GameScene.sks I instead applied a force in GameScene.swift like so: Ball.physicsBody?.applyImpulse(CGVector(dx:50, dy:0)) restitution began working

Sprite-kit collison

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

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.

Resources