SKPhysicsContactDelegate didBegin won't run - ios

I was creating a Swift Playground using SpriteKit but couldn't get collision detection to work. I've read all of the posts regarding this issue on StackOverFlow and none of them has solved my issues. Below is my code:
public class MyScene: SKScene, SKPhysicsContactDelegate {
var node: SKSpriteNode?
var touchedNodeCreator: Timer?
let nodeCategory : UInt32 = 0x1 << 1
let touchedNodeCategory : UInt32 = 0x1 << 2
var score = 0
public override func didMove(to view: SKView) {
//Setup
physicsWorld.contactDelegate = self
self.backgroundColor =
UIColor(red:0.60, green:0.88, blue:1.00, alpha:1.0)
//node
node = SKSpriteNode(imageNamed: "node")
node!.setScale(0.175)
node!.physicsBody? = SKPhysicsBody(rectangleOf: node!.size)
node!.physicsBody?.categoryBitMask = nodeCategory
node!.physicsBody?.contactTestBitMask = touchedNodeCategory
node!.physicsBody?.collisionBitMask = floorCategory
floor.physicsBody?.categoryBitMask = floorCategory
floor.physicsBody?.collisionBitMask = nodeCategory
let nodeStartingPos = CGPoint(x: node!.size.width / 2 + 25, y: self.size.height / 5 + node!.size.height / 2)
node!.position = nodeStartingPos
addChild(node!)
//Create touchedNode Timer
touchedNodeCreator = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { (timer) in
self.createtouchedNode()
}
}
func createtouchedNode() {
let touchedNode = SKSpriteNode(imageNamed: "otherNode")
touchedNode.setScale(0.2)
touchedNode.name = "TouchedNode"
touchedNode.physicsBody? = SKPhysicsBody(rectangleOf: touchedNode.size)
touchedNode.physicsBody?.affectedByGravity = false
let maxY = self.size.height / 1 - touchedNode.size.height / 2
let minY = self.size.height / 5 + 25
let rangeY = maxY - minY
let y = maxY - CGFloat(arc4random_uniform(UInt32(rangeY)))
let touchedNodeStartingPos = CGPoint(x: self.size.width + 20, y: y)
touchedNode.position = touchedNodeStartingPos
touchedNode.physicsBody?.categoryBitMask = touchedNodeCategory
touchedNode.physicsBody?.contactTestBitMask = nodeCategory
addChild(touchedNode)
let moveLeft = SKAction.moveBy(x: -size.width - touchedNode.size.width, y: 0, duration: 3)
let remove = SKAction.removeFromParent()
let sequence = SKAction.sequence([moveLeft, remove])
touchedNode.run(sequence)
}
public func didBegin(_ contact: SKPhysicsContact) {
print("Began")
if contact.bodyA.categoryBitMask == touchedNodeCategory {
contact.bodyA.node?.removeFromParent()
score += 1
print(score)
} else if contact.bodyB.categoryBitMask == touchedNodeCategory {
contact.bodyB.node?.removeFromParent()
score += 1
print(score)
}
}
Please keep in mind that I have omitted a lot of code, mainly just code that moves the node when any touch is detected.
I would appreciate it if you guys could help me get this solved. Thanks!

Related

SpriteKit (Swift) Enemy doesn't get deleted / Enemy & bullet doesn't seems to contact

import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let player = SKSpriteNode(imageNamed: "Player")
struct PhysicsCategories {
static let None: UInt32 = 0
static let Player: UInt32 = 0b1 //1
static let Bullet: UInt32 = 0b10 //2
static let Enemy: UInt32 = 0b100 //4
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
player.setScale(0.2)
player.position = CGPoint(x: self.size.width/2, y: self.size.height * 0.2)
player.zPosition = 2
player.physicsBody = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody!.affectedByGravity = false
player.physicsBody!.categoryBitMask = PhysicsCategories.Player
player.physicsBody!.collisionBitMask = PhysicsCategories.None
player.physicsBody?.isDynamic = true
player.physicsBody!.contactTestBitMask = PhysicsCategories.Enemy
self.addChild(player)
}
func didBeginContact(contact: SKPhysicsContact) {
var body1 = SKPhysicsBody()
var body2 = SKPhysicsBody()
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
body1 = contact.bodyA
body2 = contact.bodyB
}
else {
body1 = contact.bodyB
body2 = contact.bodyA
}
if body1.categoryBitMask == PhysicsCategories.Player && body2.categoryBitMask == PhysicsCategories.Enemy {
// if player hit enemy
if body1.node != nil {
spawnExplosion(spawnPosition: body1.node!.position)
}
if body2.node != nil {
spawnExplosion(spawnPosition: body2.node!.position)
}
body1.node!.removeFromParent()
body2.node!.removeFromParent()
}
if body1.categoryBitMask == PhysicsCategories.Bullet && body2.categoryBitMask == PhysicsCategories.Enemy {
// if bullet hit enemy
if body2.node != nil {
if body2.node!.position.y > self.size.height {
return
}
else {
spawnExplosion(spawnPosition: body2.node!.position)
}
}
body1.node!.removeFromParent()
body2.node!.removeFromParent()
}
}
func fireBullet() {
let bullet = SKSpriteNode(imageNamed: "Bullet")
bullet.setScale(0.8)
bullet.position = player.position
bullet.zPosition = 1
bullet.physicsBody = SKPhysicsBody(rectangleOf: bullet.size)
bullet.physicsBody!.affectedByGravity = false
bullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet
bullet.physicsBody!.collisionBitMask = PhysicsCategories.None
bullet.physicsBody?.isDynamic = true
bullet.physicsBody!.contactTestBitMask = PhysicsCategories.Enemy
self.addChild(bullet)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([bulletSound, moveBullet, deleteBullet])
bullet.run(bulletSequence)
}
func spawnEnemy()
let randomxStart = randomBetweenNumbers(firstNum: 0, secondNum: frame.width)
let randomxEnd = randomBetweenNumbers(firstNum: 0, secondNum: frame.width)
let startPoint = CGPoint(x: randomxStart, y: self.size.height * 1.2 )
let endPoint = CGPoint(x: randomxEnd, y: -self.size.height * 0.2)
let Enemy = SKSpriteNode(imageNamed: "EnemyShip")
Enemy.setScale(0.2)
Enemy.position = startPoint
Enemy.zPosition = 2
Enemy.physicsBody = SKPhysicsBody(rectangleOf: Enemy.size)
Enemy.physicsBody!.affectedByGravity = false
Enemy.physicsBody!.categoryBitMask = PhysicsCategories.Enemy
Enemy.physicsBody!.collisionBitMask = PhysicsCategories.None
Enemy.physicsBody?.isDynamic = true
Enemy.physicsBody!.contactTestBitMask = PhysicsCategories.Player | PhysicsCategories.Bullet
self.addChild(Enemy)
let moveEnemy = SKAction.move(to: endPoint, duration: 1.5)
let deleteEnemy = SKAction.removeFromParent()
let enemySequence = SKAction.sequence([moveEnemy, deleteEnemy])
Enemy.run(enemySequence)
let dx = endPoint.x - startPoint.x
let dy = endPoint.y - startPoint.y
let amountToRotate = atan2(dy, dx)
let degreesToRadians = CGFloat.pi / 180
// let radiansToDegree = 180 / CGFloat.pi
Enemy.zRotation = amountToRotate - 90 * degreesToRadians
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
fireBullet()
}
}
So I'm just beginning to learn SpriteKit and Swift through building simple game. The code is to build space invader-like game. I am stuck on Contact Reporting part of the code where bullet and enemy get deleted on contact / enemy and player get deleted on contact.
I have set up the Physics Body of Player, Enemy, Bullet. Seen some StackOverFlow question on similar issue and put in isDynamic = true. Put in the ifBeginContact -> removeFromParent but currently I don't know why, the enemy does not get deleted when hit by a bullet. I have left the essential code in. Please help.
Probably had a function inside of another function as mentioned in the comment.
Added view.ShowPhysics = true. Moved the func didBegin to the very bottom and apparently it worked.

In SpriteKit when sound is being played it messes with accelerometer

I have an issue whereby I am moving the character based on the accelerometer data using the following code in the update function as follows:
let currentX = self.player.position.x
if motionManager.isAccelerometerAvailable == true {
motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
data, error in
self.destX = currentX + CGFloat((data?.acceleration.x)! * 40)
print(CGFloat((data?.acceleration.x)!))
})
}
player.position.x = destX
Originally I was moving the player using SKAction.moveTo but have removed this for testing purposes.
This works ok but the problem is, I have a sound that is being played upon collision of an invisible object and when this is enabled it sends the accelerometer all funny. There is no specific pattern to it but after a little while the player usually sticks to either side of the screen or just hovers in the middle and the accelerometer doesn't have any effect on the movement.
I am playing the sound using
let playSound = SKAction.playSoundFileNamed("phaserDown3.mp3", waitForCompletion: false)
At the top of the file and then calling run on a collision.
The full code is in here http://pastebin.com/f6kWTnr7 and I have made a little video of the issue here https://youtu.be/tcGYyrKE4QY - as you will see, in this case when the score is at around 15 it sticks to the left for a little bit, then returns to normal then sticks to the right. It isn't always at score 15, it can be sooner or even later there is no consistency at all.
Any input will be greatly appreciated, thank you in advance
Take a look at this updated scene, some of the major changes are I combined your 3 separate blocks into 1 SKNode so that I only have to move the single SKNode, and I set it up where you score at the end of a contact, not the beginning. You can also see that the blocks now die when done scrolling, and your background is more efficient with its scrolling. If you have any other questions on the changes, feel free to ask.
//
// GameScene.swift
// SpriteKitSimpleGame
//
// Created by James Leist on 28/11/2016.
// Copyright © 2016 James Leist. All rights reserved.
//
import SpriteKit
import CoreMotion
var motionManager = CMMotionManager()
enum BodyType:UInt32 {
case player = 1
case score = 2
case dontCollide = 4
case sides = 8
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var killNodes = [SKNode]()
//let player = SKSpriteNode(imageNamed: "Airplane")
let player = SKSpriteNode(color: .green, size: CGSize(width:32,height:32))
var bg1:SKSpriteNode!
var bg2:SKSpriteNode!
let block = SKNode()
let blockHeight = 50
var currentScore = 0
var scoreLabel:SKLabelNode!
let playSound = SKAction.playSoundFileNamed("phaserDown3.mp3", waitForCompletion: false)
let move = SKAction.move(by:CGVector(dx:0,dy:-4 * 60),duration:1) //this means we move 4 every 1/60 of a second
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
backgroundColor = SKColor.white
addScrollingBG()
createRandomBlock()
addRandomBlocks1()
// sideRestraints()
scoreLabel = SKLabelNode(fontNamed: "Copperplate-Bold")
scoreLabel.text = String(currentScore)
scoreLabel.fontSize = 80
scoreLabel.position = CGPoint(x: frame.size.width - 60, y: frame.size.height - 60)
scoreLabel.zPosition = 20
self.addChild(scoreLabel)
player.name = "Player"
player.zPosition = 15
player.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
// player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Airplane"), size: CGSize(width: player.size.width, height: player.size.height))
player.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: player.size.width, height: player.size.height))
player.physicsBody?.affectedByGravity = false
player.physicsBody!.categoryBitMask = BodyType.player.rawValue
player.physicsBody!.contactTestBitMask = BodyType.score.rawValue | BodyType.sides.rawValue
player.physicsBody!.collisionBitMask = 0
addChild(player)
startAccelerometer()
}
func startAccelerometer()
{
if motionManager.isAccelerometerAvailable == true {
motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
[weak self] data, error in
guard let strongSelf = self else {return}
var destX = UInt32(strongSelf.player.position.x + CGFloat((data?.acceleration.x)! * 40))
// Called before each frame is rendered */
if destX <= 0 {
destX = 0
}
else if destX >= UInt32(strongSelf.frame.size.width) {
destX = UInt32(strongSelf.frame.size.width)
}
strongSelf.player.position.x = CGFloat(destX)
print(CGFloat((data?.acceleration.x)!))
})
}
}
func addScrollingBG() {
bg1 = SKSpriteNode(imageNamed: "bgPlayScene")
bg1 = SKSpriteNode(color:.blue,size:self.size)
bg1.anchorPoint = CGPoint.zero
bg1.position = CGPoint(x: 0, y: 0)
// bg1.size = CGSize(width: frame.size.width, height: frame.size.height)
bg1.zPosition = 0
addChild(bg1)
bg2 = SKSpriteNode(imageNamed: "bgPlayScene")
bg2 = SKSpriteNode(color:.purple,size:self.size)
bg2.anchorPoint = CGPoint.zero
bg2.position = CGPoint(x: 0, y: bg1.size.height)
// bg2.size = CGSize(width: frame.size.width, height: frame.size.height)
bg2.zPosition = 0
self.addChild(bg2)
setupBackgroundAnimation()
}
func setupBackgroundAnimation()
{
let reset = SKAction.customAction(withDuration: 1,actionBlock:
{
node,time in
guard let sNode = node as? SKSpriteNode else {return}
sNode.position = sNode.position.y <= -sNode.size.height ?
CGPoint(x: sNode.position.x, y: sNode.position.y + sNode.size.height * 2) : sNode.position
})
let scroll = SKAction.repeatForever(SKAction.group([move,reset]))
bg1.run(scroll)
bg2.run(scroll)
}
func createRandomBlock()
{
block.position = CGPoint(x:0,y:size.height + CGFloat(blockHeight))
//let partialBlock = SKSpriteNode(imageNamed: "block")
let partialBlock = SKSpriteNode(color:.yellow, size:CGSize(width: 1, height: blockHeight))
let blockLeft1 = partialBlock.copy() as! SKSpriteNode
blockLeft1.name = "left"
blockLeft1.anchorPoint = CGPoint.zero
blockLeft1.size = CGSize(width: 1, height: blockHeight)
blockLeft1.zPosition = 5;
blockLeft1.position = CGPoint.zero
block.addChild(blockLeft1)
let leftBody = SKPhysicsBody(rectangleOf: blockLeft1.size)
leftBody.affectedByGravity = false
leftBody.categoryBitMask = BodyType.sides.rawValue
leftBody.contactTestBitMask = 0
leftBody.collisionBitMask = 0
leftBody.isDynamic = false
blockLeft1.physicsBody = leftBody
let blockRight1 = partialBlock.copy() as! SKSpriteNode
blockRight1.color = .green
blockRight1.anchorPoint = CGPoint.zero
blockRight1.name = "right"
blockRight1.size = CGSize(width: 1, height: blockHeight)
blockRight1.zPosition = 5;
blockRight1.position = CGPoint(x:size.width,y:0)
block.addChild(blockRight1)
let rightBody = SKPhysicsBody(rectangleOf: blockRight1.size)
rightBody.affectedByGravity = false
rightBody.categoryBitMask = BodyType.sides.rawValue
rightBody.contactTestBitMask = 0
rightBody.collisionBitMask = 0
rightBody.isDynamic = false
blockRight1.physicsBody = rightBody
let scoreBody = SKPhysicsBody(rectangleOf:CGSize(width:Int(frame.size.width),height:blockHeight))
scoreBody.affectedByGravity = false
scoreBody.categoryBitMask = BodyType.score.rawValue
scoreBody.contactTestBitMask = 0
scoreBody.collisionBitMask = 0
scoreBody.isDynamic = false
block.physicsBody = scoreBody
}
func addRandomBlocks1() {
let randomLeftWidth : UInt32 = arc4random_uniform(UInt32(size.width) - 50)
let randomRightWidth : UInt32 = arc4random_uniform((UInt32(size.width) - randomLeftWidth) - 50)
guard let newBlock = block.copy() as? SKNode else {return} //ifw e do not have a node return
if let leftBlock = newBlock.childNode(withName:"left") as? SKSpriteNode
{
leftBlock.xScale = CGFloat(randomLeftWidth)
}
if let rightBlock = newBlock.childNode(withName:"right") as? SKSpriteNode
{
rightBlock.xScale = -CGFloat(randomRightWidth)
}
let addRandom = SKAction.customAction(withDuration: 0, actionBlock:
{
[unowned self] node,time in
if Int(node.position.y) < -self.blockHeight
{
node.removeFromParent()
self.addRandomBlocks1()
}
})
newBlock.run(SKAction.repeatForever(SKAction.group([move,addRandom])))
addChild(newBlock)
}
override func update(_ currentTime: CFTimeInterval) {
}
override func didFinishUpdate()
{
killNodes.forEach{$0.removeFromParent()}
}
func didBegin(_ contact: SKPhysicsContact) {
//This will organize the bodies so that the lowest category is A
let bodies = (contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? (A:contact.bodyA,B:contact.bodyB) : (A:contact.bodyB,B:contact.bodyA)
switch (bodies.A.categoryBitMask,bodies.B.categoryBitMask)
{
case let (a, b) where ((a & BodyType.player.rawValue) | (b & BodyType.sides.rawValue)) > 0:
killNodes.append(bodies.A.node!)
let label = SKLabelNode(text: "Gameover")
label.position = CGPoint(x:self.size.width/2,y:self.size.height/2)
addChild(label)
default:()
}
}
func didEnd(_ contact: SKPhysicsContact) {
//This will organize the bodies so that the lowest category is A
let bodies = (contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? (A:contact.bodyA,B:contact.bodyB) : (A:contact.bodyB,B:contact.bodyA)
switch (bodies.A.categoryBitMask,bodies.B.categoryBitMask)
{
case let (a, b) where ((a & BodyType.player.rawValue) | (b & BodyType.score.rawValue)) > 0:
currentScore += 1
run(playSound, withKey:"phaser")
scoreLabel.text = String(currentScore)
default:()
}
}
}

Struggling with collision detection in Swift/SpriteKit

I'm having a play with game programming in Swift/Xcode and am struggling getting collision to work.
I'm using Xcode 8 Beta 3 (because I couldn't use Xcode 7 on MacOS Sierra) so its using the new Swift 3.0 Syntax. The game has a little puppy (defined in a SK Scene file) that jumps and collects thrown items from the right. The thrown item is created in a function and removed when a new item is thrown.
I need contact with the thrown item comes into contact with the puppy. I've got physics turned on and the item bounces off the puppy but no contact is registered.
Heres my code. Appologies for the mess of code but its very first attempt at Swift and everything just thrown in for now. I can't see what I'm doing wrong :(
UPDATE: As cocoajoe suggested, I've tried setting the masks to 1 and have simplified the code to remove references to the gamescene.sks file and created everything programmatically but its still not working. I've updated the code below to reflect the latest version of the code...
import SpriteKit
import AVFoundation
class GameScene: SKScene, SKPhysicsContactDelegate {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder) is not used in this app")
}
override init(size: CGSize) {
super.init(size: size)
anchorPoint = CGPoint(x: 0.0, y: 0.0)
}
var isJumping = false
var gamePaused = false
var gameRunning = false
var playerScore = 0
var lastSpawnTime = 0
var lastTick = 0
var spawnDelay = 4
let PuppyCategory : UInt32 = 0x1 << 0
let ThrowableCategory : UInt32 = 0x1 << 1
let GroundCategory : UInt32 = 0x1 << 2
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0.0, dy: -9.8)
physicsWorld.contactDelegate = self
let background = SKSpriteNode(imageNamed: "bg")
background.anchorPoint = CGPoint(x: 0.0, y:0.0)
background.size = size
addChild(background)
// Set up Ground Object
let Ground = SKSpriteNode()
Ground.name = "Ground"
Ground.size = CGSize(width:frame.width, height: frame.height / 10)
Ground.position = CGPoint(x: frame.midX, y: Ground.frame.height / 2 )
Ground.zPosition = -20
Ground.color = SKColor.white()
// Set up the Physics
Ground.physicsBody = SKPhysicsBody(rectangleOf: Ground.size)
Ground.physicsBody!.categoryBitMask = GroundCategory
Ground.physicsBody!.contactTestBitMask = PuppyCategory | ThrowableCategory
Ground.physicsBody!.collisionBitMask = PuppyCategory | ThrowableCategory
Ground.physicsBody?.affectedByGravity = false
Ground.physicsBody?.allowsRotation = false
Ground.physicsBody?.isDynamic = false
Ground.physicsBody?.mass = 1.99999
// Initialise the Node
addChild(Ground)
// Create a Puppy
let Puppy = SKSpriteNode(imageNamed: "puppy1")
Puppy.name = "Puppy"
Puppy.position = CGPoint(x: frame.width / 10, y: frame.height / 2)
Puppy.size = CGSize(width: frame.width / 7, height: frame.height / 5)
Puppy.zPosition = 3
// Set up the Physics
Puppy.physicsBody = SKPhysicsBody(rectangleOf: Puppy.size)
Puppy.physicsBody!.categoryBitMask = PuppyCategory
Puppy.physicsBody!.contactTestBitMask = ThrowableCategory | GroundCategory
Puppy.physicsBody!.collisionBitMask = ThrowableCategory | GroundCategory
Puppy.physicsBody?.affectedByGravity = true
Puppy.physicsBody?.allowsRotation = false
Puppy.physicsBody?.isDynamic = true
Puppy.physicsBody?.mass = 1.99999
// Set up the Textures/Animation Frames
var TextureAtlas = SKTextureAtlas()
var TextureArray = [SKTexture]()
TextureAtlas = SKTextureAtlas(named: "puppy")
for i in 1...TextureAtlas.textureNames.count {
let Name = "puppy\(i).png"
TextureArray.append(SKTexture(imageNamed: Name))
}
Puppy.run(SKAction.repeatForever(SKAction.animate(with:TextureArray, timePerFrame: 0.1)))
// Add the Sprite
addChild(Puppy)
let gameMessage = SKSpriteNode(imageNamed: "TapToPlay")
gameMessage.name = "GameMessage"
gameMessage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
gameMessage.zPosition = 30
gameMessage.setScale(0.0)
addChild(gameMessage)
let gameLogo = SKSpriteNode(imageNamed: "pjlogo")
gameLogo.name = "GameLogo"
gameLogo.size = CGSize(width: frame.width / 3, height: frame.height / 5)
gameLogo.position = CGPoint(x: frame.midX, y: (frame.maxY / 100) * 80)
gameLogo.zPosition = 30
addChild(gameLogo)
let scale = SKAction.scale(to: 1.0, duration: 1)
scene?.childNode(withName: "GameMessage")!.run(scale)
if let musicURL = Bundle.main.urlForResource("bgmusic", withExtension: "mp3") {
var backgroundMusic: SKAudioNode!
backgroundMusic = SKAudioNode(url: musicURL)
addChild(backgroundMusic)
}
startNewGame()
}
func puppyJump() {
if gameRunning {
let Puppy = childNode(withName: "Puppy")
if !isJumping {
Puppy?.physicsBody?.applyImpulse(CGVector(dx: 0,dy: 1400))
isJumping = true
}
}
}
func generateThrowable() {
print("new enemy")
let oldItem = childNode(withName: "throwableItem")
oldItem?.removeFromParent()
let throwableItem = SKSpriteNode(imageNamed: "puppy1")
throwableItem.name = "throwableItem"
throwableItem.position = CGPoint(x: frame.maxX, y: frame.midY)
throwableItem.zPosition = 3
throwableItem.setScale(0.1)
throwableItem.physicsBody = SKPhysicsBody(rectangleOf: throwableItem.size)
throwableItem.physicsBody!.categoryBitMask = ThrowableCategory
throwableItem.physicsBody!.contactTestBitMask = PuppyCategory | GroundCategory
throwableItem.physicsBody!.collisionBitMask = PuppyCategory | GroundCategory
throwableItem.physicsBody?.friction = 0.1
throwableItem.physicsBody?.restitution = 0.1
throwableItem.physicsBody?.mass = 0.01
throwableItem.physicsBody?.affectedByGravity = true
throwableItem.physicsBody?.allowsRotation = true
throwableItem.physicsBody?.isDynamic = true
addChild(throwableItem)
throwableItem.physicsBody?.applyImpulse(CGVector(dx: -7,dy: 4))
let throwableTrail = SKEmitterNode(fileNamed: "particleTrail.sks")
throwableTrail?.name = "throwableTrail"
throwableTrail?.targetNode = scene
throwableItem.addChild(throwableTrail!)
}
func startNewGame() {
let logo = childNode(withName: "GameLogo")
let gameMessage = childNode(withName: "GameMessage")
logo?.removeFromParent()
gameMessage?.removeFromParent()
let gameScore = SKLabelNode(fontNamed: "Arial")
gameScore.name = "GameScore"
gameScore.text = "Score:0"
gameScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.right
gameScore.fontSize = 20
gameScore.position = CGPoint(x: frame.maxX - 20, y: frame.maxY - 26)
gameScore.zPosition = 30
addChild(gameScore)
let pauseButton = SKLabelNode(fontNamed: "Arial")
pauseButton.name = "pauseButton"
pauseButton.text = "PAUSE"
pauseButton.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.left
pauseButton.fontSize = 20
pauseButton.position = CGPoint(x: 20, y: frame.maxY - 26)
pauseButton.zPosition = 30
addChild(pauseButton)
gameRunning = true
}
func didBeginContact(contact: SKPhysicsContact) {
print("contact")
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
// 2
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
// 3
if firstBody.categoryBitMask == PuppyCategory && secondBody.categoryBitMask == GroundCategory {
print("Hit bottom. First contact has been made.")
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if gameRunning {
let gameScore = childNode(withName: "GameScore") as? SKLabelNode
gameScore?.text = "Score:\(playerScore)"
let currentTick:Int = Int(ceil(currentTime))
if lastTick < currentTick {
lastTick = currentTick
}
if (lastSpawnTime + spawnDelay) < currentTick {
// Time to Spawn new Bad Guy
generateThrowable()
lastSpawnTime = currentTick
}
}
}
}
I haven't checked other parts. (Your code still needs plenty of resources...)
But this line:
func didBeginContact(contact: SKPhysicsContact) {
needs to be changed as:
func didBegin(_ contact: SKPhysicsContact) {
in Swift 3. (Which is suggested by Xcode, with just typing didBegin.)
Please try.

Physics of node not working.(Sprite kit)

I am making a spritekit game where you need to move the player back and forth to catch objects falling down the screen. (You gain a point when the player collides with the falling object.)Recently I added restart button function. Before the restart button comes up everything works fine but when I restart the scene and the objects fall to hit the player the player falls off the screen once they make contact. This is odd because I have already set it to make the player (or person) not affected by gravity and not to be dynamic. Again before I press the button it works fine. Why are the characteristics of the person not there once I restart the scene. If you could take a look at my code and tell me why this is happening I would greatly appreciate it.
import SpriteKit
struct physicsCatagory {
static let person : UInt32 = 0x1 << 1
static let Ice : UInt32 = 0x1 << 2
static let IceTwo : UInt32 = 0x1 << 3
static let IceThree : UInt32 = 0x1 << 4
static let Score : UInt32 = 0x1 << 5
}
class GameScene: SKScene, SKPhysicsContactDelegate {
func restartScene(){
self.removeAllChildren()
self.removeAllActions()
scorenumber = 0
lifenumber = 0
createScene()
random()
//spawnThirdIce()
Died = false
}
func createScene(){
physicsWorld.contactDelegate = self
lifenumber = 0
SpeedNumber = 1
BackGround.size = CGSize(width: self.frame.width, height: self.frame.height)
BackGround.position = CGPointMake(self.size.width / 2, self.size.height / 2)
BackGround.zPosition = -5
self.addChild(BackGround)
Score.size = CGSize(width: 2563, height: 1)
Score.position = CGPoint(x: 320, y: -20)
Score.physicsBody = SKPhysicsBody(rectangleOfSize: Score.size)
Score.physicsBody?.affectedByGravity = false
Score.physicsBody?.dynamic = false
Score.physicsBody?.categoryBitMask = physicsCatagory.Score
Score.physicsBody?.collisionBitMask = 0
Score.physicsBody?.contactTestBitMask = physicsCatagory.IceThree
Score.color = SKColor.blueColor()
Score.zPosition = -5
self.addChild(Score)
person.zPosition = 1
person.position = CGPointMake(self.size.width/2, self.size.height/10)
person.setScale(0.6)
person.physicsBody = SKPhysicsBody (rectangleOfSize: CGSize(width: 40, height: 50))
person.physicsBody?.affectedByGravity = false
person.physicsBody?.categoryBitMask = physicsCatagory.person
person.physicsBody?.contactTestBitMask = physicsCatagory.Ice
person.physicsBody?.collisionBitMask = physicsCatagory.Ice
person.physicsBody?.dynamic = false
person.physicsBody?.affectedByGravity = false
ScoreLable = SKLabelNode(fontNamed: "Zapfino")
ScoreLable.position = CGPoint(x: self.frame.width / 2, y: 1700)
ScoreLable.text = "\(scorenumber)"
ScoreLable.fontColor = UIColor.yellowColor()
ScoreLable.fontSize = 150
ScoreLable.fontName = "Zapfino "
self.addChild(ScoreLable)
self.addChild(person)
}
func random() -> CGFloat{
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min min: CGFloat, max: CGFloat) -> CGFloat{
return random() * (max - min) + min
}
var gameArea: CGRect
override init(size: CGSize) {
let maxAspectRatio: CGFloat = 16.0/9.0
let playableWidth = size.height / maxAspectRatio
let margin = (size.width - playableWidth) / 2
gameArea = CGRect(x: margin, y: 0, width: playableWidth, height: size.height)
super.init(size: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var timeOfLastSpawn: CFTimeInterval = 0.0
var timePerSpawn: CFTimeInterval = 1.2
var scorenumber = Int()
var lifenumber = Int()
var SpeedNumber : Double = 0.5
var person = SKSpriteNode(imageNamed: "Person1")
let Score = SKSpriteNode()
var ScoreLable = SKLabelNode()
let BackGround = SKSpriteNode (imageNamed: "BackGround")
var restartButton = SKSpriteNode()
var Died = Bool()
override func didMoveToView(view: SKView) {
createScene()
}
func createButton(){
restartButton = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 200, height: 100))
restartButton.position = CGPoint(x: self.gameArea.width/2, y: self.gameArea.height/2)
restartButton.zPosition = 6
self.addChild(restartButton)
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCatagory.person && secondBody.categoryBitMask == physicsCatagory.IceThree || firstBody.categoryBitMask == physicsCatagory.IceThree && secondBody.categoryBitMask == physicsCatagory.person{
scorenumber++
if scorenumber == 20 {
timePerSpawn = 1.0
}
if scorenumber == 40{
timePerSpawn = 0.89
}
if scorenumber == 60{
timePerSpawn = 0.6
}
if scorenumber == 80{
timePerSpawn = 0.5
}
if scorenumber == 100{
timePerSpawn = 0.4
}
if scorenumber == 120{
timePerSpawn = 0.3
}
ScoreLable.text = "\(scorenumber)"
CollisionWithPerson(firstBody.node as! SKSpriteNode, Person: secondBody.node as! SKSpriteNode)
}
if firstBody.categoryBitMask == physicsCatagory.Score && secondBody.categoryBitMask == physicsCatagory.IceThree ||
firstBody.categoryBitMask == physicsCatagory.IceThree && secondBody.categoryBitMask == physicsCatagory.Score{
lifenumber++
if lifenumber == 1{
//person.texture
person.texture = SKTexture (imageNamed: "Flower#2")
}
if lifenumber == 2{
person.texture = SKTexture (imageNamed: "Flower #3")
}
if lifenumber == 3{
createButton()
// self.view?.presentScene(EndScene())
Died = true
}
}
}
func CollisionWithPerson (Ice: SKSpriteNode, Person: SKSpriteNode){
Person.removeFromParent()
}
func spawnThirdIce(){
var Ice = SKSpriteNode(imageNamed: "Ice")
Ice.zPosition = 2
Ice.setScale(1.5)
Ice.physicsBody = SKPhysicsBody(rectangleOfSize: Ice.size)
Ice.physicsBody?.categoryBitMask = physicsCatagory.IceThree
Ice.physicsBody?.contactTestBitMask = physicsCatagory.person | physicsCatagory.Score
Ice.physicsBody?.affectedByGravity = false
Ice.physicsBody?.dynamic = true
let randomXStart = random(min:CGRectGetMinX(gameArea), max: CGRectGetMaxX(gameArea))
let randomXend = random(min:CGRectGetMinX(gameArea),max: CGRectGetMaxX(gameArea))
let startPoint = CGPoint(x: randomXStart, y: self.size.height * 1.2)
let endpoint = CGPoint(x: randomXend, y: -self.size.height * 0.2)
Ice.position = startPoint
let moveEnemy = SKAction.moveTo(endpoint, duration: 2.0)
let deleteEnemy = SKAction.removeFromParent()
let enemySequence = SKAction.sequence([moveEnemy , deleteEnemy])
Ice.runAction(enemySequence)
self.addChild(Ice)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let location = touch.locationInNode(self)
if Died == true{
if restartButton.containsPoint(location){
restartScene()
}
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if Died == true {
}
else{
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let previousTouch = touch.previousLocationInNode(self)
let ammountDragged = location.x - previousTouch.x
person.position.x += ammountDragged
if person.position.x > CGRectGetMaxX(gameArea) - person.size.width/2{
person.position.x = CGRectGetMaxX(gameArea) - person.size.width/2
}
if person.position.x < CGRectGetMinX(gameArea) + person.size.width/2{
person.position.x = CGRectGetMinX(gameArea) + person.size.width/2
}
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if (currentTime - timeOfLastSpawn > timePerSpawn) {
spawnThirdIce()
self.timeOfLastSpawn = currentTime
}
}
}

Accelerometer works in first game, but goes crazy in the second

I'm creating a game where a player will control a falling sprite with the accelerometer X axis and an impulse is added when the user taps on the screen. In my current code when I run the game, it works okay and then once the player dies and tries again the sprite goes crazy and just flies of the screen. Can someone help please...
class PlayScene: SKScene, SKPhysicsContactDelegate {
var score = 0
var scoreLabel = SKLabelNode()
var gameOverLabel = SKLabelNode()
var labelHolder = SKSpriteNode()
var background = SKSpriteNode()
let playerGroup:UInt32 = 1
let objectGroup:UInt32 = 2
let gapGroup:UInt32 = 0 << 3
let boundary:UInt32 = 4
var movingObjects = SKNode()
var motionManager = CMMotionManager()
var destX:CGFloat = 0.0
var gameOver = 0
var currentX: CGFloat?
let greenPlayer = SKSpriteNode(imageNamed: "Image/Players/greenPlayer.png")
override func didMoveToView(view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsWorld.contactDelegate = self
self.physicsBody!.friction = 0
self.physicsWorld.gravity = CGVectorMake(-0.0, -0.8)
self.addChild(labelHolder)
scoreLabel.fontName = "Helvetica"
scoreLabel.fontSize = 60
scoreLabel.text = "0"
scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height - 140)
scoreLabel.zPosition = 10
self.addChild(scoreLabel)
//self.physicsWorld.contactDelegate = self
self.addChild(movingObjects)
let backgroundTexture = SKTexture(imageNamed: "Image/TempBG.png")
background=SKSpriteNode(texture: backgroundTexture)
background.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
background.size.width = self.frame.width
background.zPosition = 0
self.addChild(background)
greenPlayer.physicsBody = SKPhysicsBody(circleOfRadius: greenPlayer.size.height/2)
greenPlayer.physicsBody?.dynamic = true
greenPlayer.physicsBody?.allowsRotation = false
greenPlayer.physicsBody?.categoryBitMask = playerGroup
greenPlayer.physicsBody?.collisionBitMask = objectGroup
greenPlayer.physicsBody?.contactTestBitMask = objectGroup
greenPlayer.physicsBody?.collisionBitMask = gapGroup
greenPlayer.physicsBody?.collisionBitMask = boundary
//self.greenPlayer.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.greenPlayer.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
greenPlayer.zPosition = 5
self.addChild(greenPlayer)
currentX = self.greenPlayer.position.x
//if motionManager.accelerometerAvailable == true {
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.currentQueue()!, withHandler:{ data, error in
if data!.acceleration.x < 0 {
self.destX = self.currentX! + CGFloat(data!.acceleration.x * 1000)
}
else if data!.acceleration.x > 0 {
self.destX = self.currentX! + CGFloat(data!.acceleration.x * 1000)
}
})
NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: Selector("makeDodges"), userInfo: nil, repeats: true)
}
func makeDodges() {
if(gameOver == 0){
let gapWidth = greenPlayer.size.width * 3
let movementAmount = arc4random() % UInt32(self.frame.size.width / 2)
let dodgeOffSet = CGFloat(movementAmount) - (self.frame.size.width / 4)
let moveDodges = SKAction.moveByX(0, y: self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
let removeDodges = SKAction.removeFromParent()
let moveAndRemoveDodges = SKAction.sequence([moveDodges, removeDodges])
let dodge1Texture = SKTexture(imageNamed: "Image/Dodge.png")
let dodge1 = SKSpriteNode(texture: dodge1Texture)
dodge1.position = CGPoint(x: CGRectGetMidX(self.frame) + dodge1.size.width/2 + gapWidth/2 + dodgeOffSet, y: CGRectGetMidY(self.frame) - self.frame.size.height)
dodge1.runAction(moveDodges)
dodge1.physicsBody = SKPhysicsBody(rectangleOfSize: dodge1.size)
dodge1.physicsBody?.dynamic = false
dodge1.physicsBody?.categoryBitMask = objectGroup
dodge1.zPosition = 10
movingObjects.addChild(dodge1)
let dodge2Texture = SKTexture(imageNamed: "Image/Dodge.png")
let dodge2 = SKSpriteNode(texture: dodge2Texture)
dodge2.position = CGPoint(x: CGRectGetMidX(self.frame) - dodge2.size.width/2 - gapWidth/2 + dodgeOffSet , y: CGRectGetMidY(self.frame) - self.frame.size.height)
dodge2.runAction(moveDodges)
dodge2.physicsBody = SKPhysicsBody(rectangleOfSize: dodge2.size)
dodge2.physicsBody?.dynamic = false
dodge2.physicsBody?.categoryBitMask = objectGroup
dodge2.zPosition = 10
movingObjects.addChild(dodge2)
let gap = SKNode()
gap.position = CGPoint(x: CGRectGetMidX(self.frame) + dodgeOffSet , y: CGRectGetMidY(self.frame) - self.frame.size.height)
gap.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(dodge1.size.height, gapWidth))
gap.runAction(moveAndRemoveDodges)
gap.physicsBody?.dynamic = false
gap.physicsBody?.collisionBitMask = gapGroup
gap.physicsBody?.categoryBitMask = gapGroup
gap.physicsBody?.contactTestBitMask = playerGroup
movingObjects.addChild(gap)
}
}
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == gapGroup || contact.bodyB.categoryBitMask == gapGroup {
score++
print(score)
scoreLabel.text = "\(score)"
} else {
if gameOver == 0 {
gameOver = 1
movingObjects.speed = 0
let scene:SKScene = GameScene(size: self.frame.size)
scene.scaleMode = .AspectFill
let transition:SKTransition = SKTransition.fadeWithDuration(2)
self.view?.presentScene(scene, transition: transition)
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if(gameOver == 0) {
greenPlayer.physicsBody?.velocity = CGVectorMake(0, 0)
greenPlayer.physicsBody?.applyImpulse(CGVectorMake(0, 50))
} else {
score = 0
scoreLabel.text = "0"
movingObjects.removeAllChildren()
self.greenPlayer.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
greenPlayer.physicsBody?.velocity = CGVectorMake(0, 0)
labelHolder.removeAllChildren()
gameOver = 0
movingObjects.speed = 1
currentX = CGRectGetMidX(self.frame)
}
}
override func update(currentTime: CFTimeInterval) {
let action = SKAction.moveToX(destX, duration: 1)
self.greenPlayer.runAction(action)
}
}
You never stop and remove the old motion manager queue, so your old scene will never die, thus causing your problems.
Add motionManager.stopAccelerometerUpdates();motionManager = nil; at the point you want to destroy your old scene, If you are not destroying your old scene, and just resetting your data, then just add motionManager.stopAccelerometerUpdates(); to the point where you are going to reset your scene.

Resources