In SpriteKit when sound is being played it messes with accelerometer - ios

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:()
}
}
}

Related

How to detect no collision in a sprite kit game

I'm doing a game where you have to capture candies using a spider hung by a thread, as I show in this link: Game screenshot (I'm new here so I can't post images yet). I already have the movement of the spider from left to right and also I'm able to catch the candies using SKAction moving through 'Y', my only issue is I didn't figure it out yet how to know if the spider don't capture any candy, during his movement, I was trying use the allContactedBodies function when the action finish but the count of the array returned is always zero. Any suggestions?
Here is the code :
class GameScene: SKScene, SKPhysicsContactDelegate {
private var rope = SKSpriteNode(imageNamed: "rope")
private var anchor = SKSpriteNode(imageNamed: "anchor")
private var currentCharacter: SKSpriteNode!
private var candy: SKSpriteNode!
var direction : String = "backward"
var lastCandyAdded: TimeInterval = 0
let candyVelocity: CGFloat = 4.0
let characterBitMask : UInt32 = 0x1 << 1
let candyBitMask: UInt32 = 0x1 << 2
let characterVelocity: CGFloat = 18.0
var direction : String = "backward"
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
self.addAnchor()
self.addRope()
self.addCharacter()
let jointOneFixed = SKPhysicsJointFixed.joint(withBodyA: anchor.physicsBody!, bodyB: rope.physicsBody!, anchor: anchor.position)
self.physicsWorld.add(jointOneFixed);
let jointTwoFixed = SKPhysicsJointFixed.joint(withBodyA: rope.physicsBody!, bodyB: currentCharacter.physicsBody!, anchor: currentCharacter.position)
self.physicsWorld.add(jointTwoFixed);
}
func addAnchor(){
anchor.position = CGPoint(x: self.size.width / 2, y: self.size.height + 1)
anchor.anchorPoint = CGPoint(x: 0.5, y: 0.5)
anchor.setScale(1)
anchor.zPosition = 2
anchor.name = "anchor"
anchor.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: anchor.size.width, height: anchor.size.height))
anchor.physicsBody?.affectedByGravity = false
anchor.physicsBody?.friction = 0;
anchor.physicsBody?.linearDamping = 0;
anchor.physicsBody?.mass = 10;
self.addChild(anchor)
}
func addCharacter() {
let characterName: String = UserDefaults.standard.string(forKey: "current_character")!
currentCharacter = SKSpriteNode(imageNamed: characterName);
currentCharacter.position = CGPoint(x: self.size.width / 2, y: self.size.height - 400)
currentCharacter.anchorPoint = CGPoint(x: 0.5, y: 0.5)
currentCharacter.setScale(0.43)
currentCharacter.zPosition = 2
currentCharacter.name = "character"
currentCharacter.physicsBody = SKPhysicsBody(rectangleOf: currentCharacter.size)
currentCharacter.physicsBody?.categoryBitMask = characterBitMask
currentCharacter.physicsBody?.contactTestBitMask = candyBitMask
currentCharacter.physicsBody?.collisionBitMask = candyBitMask;
currentCharacter.physicsBody?.affectedByGravity = false;
currentCharacter.physicsBody?.friction = 0;
currentCharacter.physicsBody?.linearDamping = 0;
currentCharacter.physicsBody?.mass = 20;
self.addChild(currentCharacter)
}
func addRope() {
rope.position = CGPoint(x: anchor.position.x, y: anchor.position.y - 70)
rope.setScale(0.65)
rope.zPosition = 1
rope.name = "rope"
rope.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: rope.size.width, height: rope.size.height))
rope.physicsBody?.affectedByGravity = false;
rope.physicsBody?.friction = 0;
rope.physicsBody?.linearDamping = 0;
rope.physicsBody?.mass = 5;
rope.physicsBody?.allowsRotation = false
self.addChild(rope)
}
func addCandy() {
let number = Int.random(min: 1, max: 24)
let candyWord = "candie"
let candyTexture = SKTexture(imageNamed: "\(candyWord)\(number)")
candy = SKSpriteNode(texture: candyTexture)
candy.zPosition = 3
candy.setScale(0.40)
candy.physicsBody = SKPhysicsBody(circleOfRadius: max(candy.size.width / 2, candy.size.height / 2))
candy.physicsBody?.isDynamic = true
candy.name = "candy"
candy.physicsBody?.categoryBitMask = candyBitMask
candy.physicsBody?.contactTestBitMask = characterBitMask
candy.physicsBody?.collisionBitMask = characterBitMask
candy.physicsBody?.affectedByGravity = false
candy.position = CGPoint(x: self.frame.size.width + 20, y: self.frame.size.height / 2 + 150)
self.addChild(candy)
}
func moveCandy() {
self.enumerateChildNodes(withName: "candy", using: {(node, stop) -> Void in
if let candy = node as? SKSpriteNode {
candy.position = CGPoint(x: candy.position.x - self.candyVelocity, y: candy.position.y)
if candy.position.x < 0 {
candy.removeFromParent()
}
}
})
}
override func update(_ currentTime: TimeInterval) {
self.moveCandy()
self.moveCharacter()
if currentTime - self.lastCandyAdded > 0.75 {
self.lastCandyAdded = currentTime + Double.random(min: 0.00, max: 0.60)
self.addCandy()
}
}
func collisionBetween(candy: SKNode, object: SKNode) {
let moveUp = SKAction.moveBy(x: 0, y: 100, duration:0.0)
let shrinkRope = SKAction.animate(with: [SKTexture(imageNamed: "rope")], timePerFrame: 0)
let moveUpBlock = SKAction.run({
self.anchor.run(moveUp)
})
let shrinkRopeBlock = SKAction.run({
self.rope.run(shrinkRope)
})
let sequence = SKAction.sequence([SKAction.wait(forDuration: 0.07), shrinkRopeBlock, moveUpBlock])
self.run(sequence)
candy.removeFromParent()
}
func didBegin(_ contact: SKPhysicsContact) {
guard let nodeA = contact.bodyA.node else { return }
guard let nodeB = contact.bodyB.node else { return }
if nodeA.name == "candy" && nodeB.name == "character" {
collisionBetween(candy: nodeA, object: nodeB)
} else if nodeA.name == "character" && nodeB.name == "candy" {
collisionBetween(candy: nodeB, object: nodeA)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
let moveDown = SKAction.moveBy(x: 0, y: -100, duration:0.0)
let stretchRope = SKAction.animate(with: [SKTexture(imageNamed: "rope_stretch")], timePerFrame: 0)
let moveDownBlock = SKAction.run({
self.anchor.run(moveDown, completion: {
var physicBodies = self.currentCharacter.physicsBody?.allContactedBodies();
// This count is always zero
print(physicBodies?.count)
})
})
let stretchRopeBlock = SKAction.run({
self.rope.run(stretchRope)
})
let sequence = SKAction.sequence([moveDownBlock, stretchRopeBlock])
self.run(sequence)
}
func moveCharacter(){
self.enumerateChildNodes(withName: "anchor", using: {(node, stop) -> Void in
if let anchorNode = node as? SKSpriteNode {
if anchorNode.position.x < 120 {
anchorNode.position = CGPoint(x: anchorNode.position.x + self.characterVelocity, y: anchorNode.position.y)
self.direction = "forward"
} else if anchorNode.position.x > self.size.width - 120 {
anchorNode.position = CGPoint(x: anchorNode.position.x - self.characterVelocity, y: anchorNode.position.y)
self.direction = "backward"
} else if self.direction == "forward" {
anchorNode.position = CGPoint(x: anchorNode.position.x + self.characterVelocity, y: anchorNode.position.y)
self.direction = "forward"
} else {
anchorNode.position = CGPoint(x: anchorNode.position.x - self.characterVelocity, y: anchorNode.position.y)
self.direction = "backward"
}
}
})
}
}
First of all you have a lot of code in this question...too much, it makes it hard to focus on what is really happening. You are also missing a block of code for moveCharacter().
You should strongly look at creating subclasses for your player, rope and (mostly)candies. I would also look into creating an array of candies initially so that you are not dynamically creating physics objects during run time.
As for your question wouldn't it be as simple as creating a couple of variables in your class
private var isMoving = false
private var didGetCandy = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//prevent the user from firing the move while in the middle of a move
guard !isMoving else { return }
isMoving = true
let moveDownBlock = SKAction.run({
self.anchor.run(moveDown) {
//this is an appreviated form of a 'completion' block
self.isMoving = false
print("did I get a candy \(didGetCandy)")
}
})
}
func collisionBetween(candy: SKNode, object: SKNode) {
didGetCandy = true
}

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.

SpriteKit + Swift - Not Firing on contact

So I am playing around with Swift and SpriteKit. I decided to create a simple game where a character will walk to a chest of coins and get all the treasure.
I am trying to detect when the two objects contact eachother, however nothing seems to be happening.
What I did:
1) I set the delegate:
SKPhysicsContactDelegate
2) Created the scene:
override func didMoveToView(view: SKView) {
backgroundColor = SKColor.whiteColor()
physicsWorld.contactDelegate = self
let sceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sceneBody.friction = 0
background.zPosition = -20
background.anchorPoint = CGPointZero
background.position = CGPointZero
backgroundRepeated.zPosition = -20
backgroundRepeated.anchorPoint = CGPointZero
backgroundRepeated.position = CGPointMake(background.size.width-1,0)
addChest()
addCharacter()
addChild(background)
addChild(backgroundRepeated)
}
3) Created the items:
func addChest() {
chestOfCoins.anchorPoint = CGPointZero
chestOfCoins.size = CGSize(width: 200,height: 200)
chestOfCoins.position = CGPoint(x: self.frame.width-1, y: 300)
chestOfCoins.zPosition = 20
chestOfCoins.physicsBody = SKPhysicsBody(rectangleOfSize: chestOfCoins.size)
chestOfCoins.physicsBody?.affectedByGravity = false
chestOfCoins.physicsBody?.dynamic = false
chestOfCoins.physicsBody?.categoryBitMask = physicsCategory.chests
chestOfCoins.physicsBody?.collisionBitMask = 0
chestOfCoins.physicsBody?.contactTestBitMask = physicsCategory.character
addChild(chestOfCoins)
}
func addCharacter() {
character.anchorPoint = CGPointZero
character.position = CGPoint(x: 300, y: 300)
character.zPosition = 20
character.size = CGSize(width: 200, height: 200)
character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
character.physicsBody?.categoryBitMask = physicsCategory.character
character.physicsBody?.contactTestBitMask = physicsCategory.chests
character.physicsBody?.collisionBitMask = 0
addChild(character)
}
4) created didBeginContact:
func didBeginContact(contact: SKPhysicsContact) {
var contactBody1: SKPhysicsBody
var contactBody2: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
contactBody1 = contact.bodyA
contactBody2 = contact.bodyB
} else {
contactBody1 = contact.bodyB
contactBody2 = contact.bodyA
}
if((contactBody1.categoryBitMask == 1) && (contactBody2.categoryBitMask == 2)) {
print("touched")
} else {
print("not these two")
}
}
FYI, this IF if((contactBody1.categoryBitMask == 1) && (contactBody2.categoryBitMask == 2)) does not output Either the main if block or the else.
5) I created the category physics :
struct physicsCategory {
static let none: UInt32 = 0 //0
static let character: UInt32 = 0b1 //1
static let chests: UInt32 = 0b10 //2
static let snake: UInt32 = 0b100 //4
}
Full GameScene.Swift:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
struct physicsCategory {
static let none: UInt32 = 0 //0
static let character: UInt32 = 0b1 //1
static let chests: UInt32 = 0b10 //2
static let snake: UInt32 = 0b100 //4
static let all: UInt32 = UInt32.max
}
let background = SKSpriteNode(imageNamed: "Backgrounds")
let backgroundRepeated = SKSpriteNode(imageNamed: "Backgrounds")
let chestOfCoins = SKSpriteNode(imageNamed: "chest")
let character = SKSpriteNode(imageNamed: "character")
let gameActions = NSUserDefaults.standardUserDefaults()
func addChest() {
chestOfCoins.anchorPoint = CGPointZero
chestOfCoins.size = CGSize(width: 200,height: 200)
chestOfCoins.position = CGPoint(x: self.frame.width-1, y: 300)
chestOfCoins.zPosition = 20
chestOfCoins.physicsBody = SKPhysicsBody(rectangleOfSize: chestOfCoins.size)
chestOfCoins.physicsBody?.affectedByGravity = false
chestOfCoins.physicsBody?.dynamic = false
chestOfCoins.physicsBody?.categoryBitMask = physicsCategory.chests
chestOfCoins.physicsBody?.collisionBitMask = 0
chestOfCoins.physicsBody?.contactTestBitMask = physicsCategory.character
addChild(chestOfCoins)
}
func addCharacter() {
character.anchorPoint = CGPointZero
character.position = CGPoint(x: 300, y: 300)
character.zPosition = 20
character.size = CGSize(width: 200, height: 200)
character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
character.physicsBody?.categoryBitMask = physicsCategory.character
character.physicsBody?.contactTestBitMask = physicsCategory.chests
character.physicsBody?.collisionBitMask = 0
addChild(character)
}
override func didMoveToView(view: SKView) {
backgroundColor = SKColor.whiteColor()
physicsWorld.contactDelegate = self
let sceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sceneBody.friction = 0
background.zPosition = -20
background.anchorPoint = CGPointZero
background.position = CGPointZero
backgroundRepeated.zPosition = -20
backgroundRepeated.anchorPoint = CGPointZero
backgroundRepeated.position = CGPointMake(background.size.width-1,0)
addChest()
addCharacter()
addChild(background)
addChild(backgroundRepeated)
}
func didBeginContact(contact: SKPhysicsContact) {
var contactBody1: SKPhysicsBody
var contactBody2: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
contactBody1 = contact.bodyA
contactBody2 = contact.bodyB
} else {
contactBody1 = contact.bodyB
contactBody2 = contact.bodyA
}
if((contactBody1.categoryBitMask == 1) && (contactBody2.categoryBitMask == 2)) {
print("touched")
} else {
print("not these two")
}
}
override func update(currentTime: NSTimeInterval) {
let startWalking = gameActions.boolForKey("Walking")
if (startWalking == true) {
chestOfCoins.position = CGPoint(x: chestOfCoins.position.x - 5, y: chestOfCoins.position.y)
background.position = CGPoint(x: background.position.x - 5, y: background.position.y)
backgroundRepeated.position = CGPoint(x: backgroundRepeated.position.x - 5, y: backgroundRepeated.position.y)
if (background.position.x < -background.size.width) {
background.position = CGPointMake(backgroundRepeated.position.x + backgroundRepeated.size.width, background.position.y)
}
if (backgroundRepeated.position.x < -backgroundRepeated.size.width) {
backgroundRepeated.position = CGPointMake(background.position.x + background.size.width, backgroundRepeated.position.y)
}
}
}
}
Question
Can anyone tell me why, when the screen starts scrolling and those two items come into contact nothing happens and tell me how to fix it?
One also seems to go behind even though I set the zPosition of both to the same
Here is a pic, Don't judge about images :(
set either your chest or your other thingies property to dynamic = true
two non-dynamic physics bodies wont register contacts

Score label in top left Corner for all devices

I’m new to programming and I recently did a tutorial that I found online to make a endless frogger game. The tutorial person didn’t show me how to do the score label and I have tried endlessly to find a video tutorial that will show me how to position a score label in the top left corner. I have tried using this code:
label.horizontalAlignmentMode = .Left
label.position = CGPoint(x:0.0, y:self.size.height)
but I have had no luck, It does not show up in the top left corner. So i tried another way to get it positioned in the corner and I played around with the values and ended up with this
scoreLabel.position = CGPointMake(frame.size.width / -2.231, frame.size.height / 2.29)
which positions it perfectly in the corner of the screen on the simulator, but not for all the devices. I have a seperate swift file for my score label with is here:
import Foundation
import SpriteKit
import UIKit
class Score: SKLabelNode {
var number = 0
init (num: Int) {
super.init()
fontColor = UIColor.whiteColor()
fontName = "Helvetica"
fontSize = 150.0
number = num
text = "\(num)"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addOneToScore() {
number++
text = "\(number)"
}
}
I have a world node that has a player inside it and the camera position is focused on the player. I have provided my game Scene class for you to have a look at. All I want is to be able to position a score label in the top left or top right corner of the screen for all devices.
import SpriteKit
enum BodyType:UInt32 {
case player = 1
case roadObject = 2
case waterObject = 4
case water = 8
case road = 16
}
enum LevelType:UInt32 {
case road, water
}
class GameScene: SKScene, SKPhysicsContactDelegate {
//recongises swipe and tap gestures
let TapUpRec = UITapGestureRecognizer()
let swipeRightRec = UISwipeGestureRecognizer()
let swipeLeftRec = UISwipeGestureRecognizer()
let swipeDownRec = UISwipeGestureRecognizer()
//defines the attributes for level units.
var levelUnitCounter:CGFloat = 1 // Not sure, i think it starts the frog further up.
var levelUnitWidth:CGFloat = 0 //will be screenwidth
var levelUnitHeight:CGFloat = 50 // changes the height of the level units
var initialUnits:Int = 10 // tells how many level units will be spawned as you climb.
//defines the world node for the scene & defines the player image in a constant.
var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0
let worldNode:SKNode = SKNode()
let thePlayer:Player = Player(imageNamed: "Frog")
var increment:CGFloat = 0
// variables with boolean values to check if the player is on certain types of levels or objects.
var onLilyPad:Bool = false
var onWater:Bool = false
var onRoad:Bool = false
//same variable that checks if the player is dead.
var isDead:Bool = false
//variable that links with the swift file called object and (maybe passes it through :( )
var waterObject:Object?
//creates a constant that will be the starting point of the player
let startingPosition:CGPoint = CGPointMake(0, 0)
var direction:CGFloat = 1
// var nodeToMove:Object?
// var moveInProgress:Bool = false
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// Defines the view as the target defines the direction and calls the function (in red)
swipeRightRec.addTarget(self, action:"swipedRight")
swipeRightRec.direction = .Right
self.view!.addGestureRecognizer(swipeRightRec)
swipeLeftRec.addTarget(self, action: "swipedLeft")
swipeLeftRec.direction = .Left
self.view!.addGestureRecognizer(swipeLeftRec)
TapUpRec.addTarget(self, action: "tapUp")
self.view!.addGestureRecognizer(TapUpRec)
swipeDownRec.addTarget(self, action: "swipedDown")
swipeDownRec.direction = .Down
self.view!.addGestureRecognizer(swipeDownRec)
//makes the background colour black and defines the screenWidth variable as sk view boundry
self.backgroundColor = SKColor.greenColor()
screenWidth = self.view!.bounds.width
screenHeight = self.view!.bounds.height
//makes the world able to have objects that can collide (I Think)
physicsWorld.contactDelegate = self
//physicsWorld.gravity = CGVector(dx:0.3, dy:0.0)
//creates the world node point to be in the middle of the screen
self.anchorPoint = CGPointMake(0.5, 0.5)
addChild(worldNode)
let scoreLabel = Score(num: 0)
scoreLabel.horizontalAlignmentMode = .Left
scoreLabel.position = CGPoint(x:0.0, y:self.size.height)
addChild(scoreLabel)
//scoreLabel.position = CGPointMake(frame.size.width / -2.231, frame.size.height / 2.29)
// let highscoreLabel = Score(num: 0)
//adds a child node to the world node (so the player is playing within the world node)
worldNode.addChild(thePlayer)
thePlayer.position = startingPosition
thePlayer.zPosition = 500 // zPosition is the order the player will be displayed.
addLevelUnits() //runs the func that addds levelUnits.
}
func addScoreLabels(){
}
// this function along with the next three run the swipe and tap gesture actions.
func swipedRight(){
let amountToMove:CGFloat = levelUnitHeight
let move:SKAction = SKAction.moveByX(amountToMove, y: 0, duration: 0.1)
thePlayer.runAction(move) // links the action with the players
}
func swipedLeft(){
let amountToMove:CGFloat = levelUnitHeight
let move:SKAction = SKAction.moveByX(-amountToMove, y: 0, duration: 0.1)
thePlayer.runAction(move)
}
func swipedDown(){
let amountToMove:CGFloat = levelUnitHeight
let move:SKAction = SKAction.moveByX(0, y: -amountToMove, duration: 0.1)
thePlayer.runAction(move)
// clearNodes()
}
func tapUp(){
let amountToMove:CGFloat = levelUnitHeight
let move:SKAction = SKAction.moveByX(0, y: amountToMove, duration: 0.1)
thePlayer.runAction(move)
clearNodes()
}
func resetLevel(){
//searches the world node for child nodes that have the name "levelUnit"
worldNode.enumerateChildNodesWithName("levelUnit") {
node, stop in
//removes all the child nodes from the parent.
node.removeFromParent()
}
levelUnitCounter = 1
addLevelUnits()
}
func addLevelUnits() {
for (var i = 0; i < initialUnits; i++ ) {
createLevelUnit()
}
}
func createLevelUnit() {
if (direction == 1) {
direction = -1
} else {
direction = 1
}
print(direction )
let levelUnit:LevelUnit = LevelUnit()
worldNode.addChild(levelUnit)
levelUnit.zPosition = -1
levelUnit.levelUnitWidth = screenWidth
levelUnit.levelUnitHeight = levelUnitHeight
levelUnit.direction = direction
levelUnit.setUpLevel()
levelUnit.position = CGPointMake( 0 , levelUnitCounter * levelUnitHeight) // counts the level unit and multiplies it so t goes above the last level unit.
levelUnitCounter++ //constantly makes the level units appear.
}
func clearNodes(){
var nodeCount:Int = 0
worldNode.enumerateChildNodesWithName("levelUnit") {
node, stop in
let nodeLocation:CGPoint = self.convertPoint(node.position, fromNode: self.worldNode) //converts cordinates of level units with the world node.
if ( nodeLocation.x < -(self.screenWidth / 2) - self.levelUnitWidth ) { // checks to see if the node is off the screen.
node.removeFromParent()
print("levelUnit was removed", terminator: "")
} else {
nodeCount++
}
}
print( "levelUnits in the scene is \(nodeCount)")
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
worldNode.enumerateChildNodesWithName("levelUnit"){
node, stop in
let levelUnit:LevelUnit = node as! LevelUnit //cast as an actual LevelUnit class
levelUnit.enumerateChildNodesWithName("obstacle"){
node, stop in
let obstacle:Object = node as! Object //cast as an actual Object class
obstacle.update()
let obstacleLocation:CGPoint = self.convertPoint(obstacle.position, fromNode: levelUnit)
let buffer:CGFloat = 150
if (obstacleLocation.x < -(self.screenWidth / 2) - buffer) { //changes the speed of object when it reaches middle of the screen.
levelUnit.changeSpeed()
obstacle.position = CGPointMake(obstacle.position.x + (self.screenWidth + (buffer * 2)) , obstacle.position.y)
} else if (obstacleLocation.x > (self.screenWidth / 2) + buffer ) { //changes the speed of the object again.
levelUnit.changeSpeed()
obstacle.position = CGPointMake(obstacle.position.x - (self.screenWidth + (buffer * 2)) , obstacle.position.y)
}
}
}
// creates new level units if always centering horizontally
let nextTier:CGFloat = (levelUnitCounter * levelUnitHeight) - (CGFloat(initialUnits) * levelUnitHeight)
if (thePlayer.position.y > nextTier) {
createLevelUnit()
}
//deal with the players location....
let playerLocation:CGPoint = self.convertPoint(thePlayer.position, fromNode: worldNode)
var repositionPlayer:Bool = false
if ( playerLocation.x < -(screenWidth / 2)) {
repositionPlayer = true
} else if ( playerLocation.x > (screenWidth / 2)) {
repositionPlayer = true
} else if ( playerLocation.y < 0) {
repositionPlayer = true
} else if ( playerLocation.y > screenHeight) {
repositionPlayer = true
}
if (repositionPlayer == true) {
/* great code for reference later */
killPlayer()
thePlayer.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
}
}
// this function centers the world node on teh player.
override func didSimulatePhysics() {
self.centerOnNode(thePlayer)
if (onLilyPad == true) {
thePlayer.position = CGPointMake(thePlayer.position.x + waterObject!.xAmount , thePlayer.position.y)
}
}
//centers the camera on the node world.
func centerOnNode(node:SKNode) {
let cameraPositionInScene:CGPoint = self.convertPoint(node.position, fromNode: worldNode)
worldNode.position = CGPoint(x: worldNode.position.x , y:worldNode.position.y - cameraPositionInScene.y )
}
func didBeginContact(contact: SKPhysicsContact) {
// Defines the contact between objects.
/// lily pad
if (contact.bodyA.categoryBitMask == BodyType.player.rawValue && contact.bodyB.categoryBitMask == BodyType.waterObject.rawValue ) {
waterObject = contact.bodyB.node!.parent as? Object
onLilyPad = true
self.removeActionForKey("checkOnLilyPad")
let waterObjectLocation:CGPoint = self.convertPointToView(waterObject!.position)
thePlayer.position = self.convertPointFromView(waterObjectLocation)
} else if (contact.bodyA.categoryBitMask == BodyType.waterObject.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue ) {
waterObject = contact.bodyA.node!.parent as? Object
onLilyPad = true
self.removeActionForKey("checkOnLilyPad")
let waterObjectLocation:CGPoint = self.convertPointToView(waterObject!.position)
thePlayer.position = self.convertPointFromView(waterObjectLocation)
}
//// check on water
if (contact.bodyA.categoryBitMask == BodyType.player.rawValue && contact.bodyB.categoryBitMask == BodyType.water.rawValue ) {
onRoad = false
onWater = true
waitAndThenCheckOnLilyPad()
} else if (contact.bodyA.categoryBitMask == BodyType.water.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue ) {
onRoad = false
onWater = true
waitAndThenCheckOnLilyPad()
}
//// cars
if (contact.bodyA.categoryBitMask == BodyType.player.rawValue && contact.bodyB.categoryBitMask == BodyType.roadObject.rawValue ) {
killPlayer()
} else if (contact.bodyA.categoryBitMask == BodyType.roadObject.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue ) {
killPlayer()
}
//// check on road
if (contact.bodyA.categoryBitMask == BodyType.player.rawValue && contact.bodyB.categoryBitMask == BodyType.road.rawValue ) {
onRoad = true
onWater = false
onLilyPad = false
} else if (contact.bodyA.categoryBitMask == BodyType.road.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue ) {
onRoad = true
onWater = false
onLilyPad = false
}
}
func waitAndThenCheckOnLilyPad() {
let wait:SKAction = SKAction.waitForDuration(0.1)
let check:SKAction = SKAction.runBlock(checkIfOnLilyPad)
let seq:SKAction = SKAction.sequence([wait, check])
self.runAction(seq, withKey:"checkOnLilyPad")
}
func checkIfOnLilyPad() {
if ( onRoad == false) {
if ( onWater == true && onLilyPad == false) {
killPlayer()
} else if ( onWater == true && onLilyPad == true) {
print("safely on water")
// maybe play sound here
}
}
}
func didEndContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch (contactMask) {
case BodyType.waterObject.rawValue | BodyType.player.rawValue:
onLilyPad = false
waterObject = nil
onWater = true
waitAndThenCheckOnLilyPad()
default:
return
}
}
func killPlayer() {
if ( isDead == false) {
isDead = true
let fadeOut:SKAction = SKAction.fadeAlphaTo(0, duration: 0.2)
let move:SKAction = SKAction.moveTo(startingPosition, duration: 0.2)
let block:SKAction = SKAction.runBlock(revivePlayer)
let seq:SKAction = SKAction.sequence([fadeOut, move, block])
thePlayer.runAction(seq)
}
}
func revivePlayer() {
isDead = false
onRoad = false
onWater = false
onLilyPad = false
let fadeOut:SKAction = SKAction.fadeAlphaTo(0, duration: 0.2)
let block:SKAction = SKAction.runBlock(resetLevel)
let fadeIn:SKAction = SKAction.fadeAlphaTo(1, duration: 0.2)
let seq:SKAction = SKAction.sequence([fadeOut, block, fadeIn])
worldNode.runAction(seq)
let wait:SKAction = SKAction.waitForDuration(1)
let fadeIn2:SKAction = SKAction.fadeAlphaTo(1, duration: 0.2)
let seq2:SKAction = SKAction.sequence([wait , fadeIn2])
thePlayer.runAction(seq2)
}
}
If other solutions don't work, you could try something like this:
import UIKit
var screenSize = UIScreen.mainscreen().bounds
var screenWidth = screenSize.width
var screenHeight = screenSize.height
This will get the dimensions of the screen and store them in the screenHeight and screenWidth variables.
Then when you call scoreLabel.position you could say
scoreLabel.position = CGPoint(x: screenWidth / 10, y: screenHeight / 15)
Or something like that but experiment with the math until it is in the correct position.
If this doesn't work you may also need to declare the size or scoreLabel. Let me know if it works.
Swift 4 and Xcode 9 code:
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
self.menuButton.position = CGPoint(x: screenWidth / 10, y: screenHeight / 15)
I think you are on the right track with:
let scoreLabel = Score(num: 0)
scoreLabel.horizontalAlignmentMode = .Left
scoreLabel.position = CGPoint(x:0.0, y:self.size.height)
addChild(scoreLabel)
But I think you also need to add
scoreLabel.verticalAlignmentMode = .Top
as the default is.Baseline which would cause it draw most off the screen.

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