Looping my code so that the user can continue to play - swift

import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let balls = [
SKSpriteNode(imageNamed: "blueball.png"),
SKSpriteNode(imageNamed: "greenball.png"),
SKSpriteNode(imageNamed: "realredball.png"),
]
let redRectangle = SKSpriteNode(imageNamed: "redrectangle.png")
let blueRectangle = SKSpriteNode(imageNamed: "bluerectangle.png")
let greenRectangle = SKSpriteNode(imageNamed: "greenrectangle.png")
let wall1 = SKSpriteNode(imageNamed: "drop_wall.png")
let wall2 = SKSpriteNode(imageNamed: "drop_wall.png")
let bottom = SKSpriteNode(imageNamed:"drop_bottom.png")
let top = SKSpriteNode(imageNamed:"drop_bottom.png")
let blueBallCategory :UInt32 = 0x1 << 0
let greenBallCategory :UInt32 = 0x1 << 1
let realRedBallCategory :UInt32 = 0x1 << 2
let redRectangleCategory : UInt32 = 0x1 << 3
let blueRectangleCategory : UInt32 = 0x1 << 4
let greenRectangleCategory : UInt32 = 0x1 << 5
override func didMove(to view: SKView) {
spawnBalls()
spawnRectangles()
physicsWorld.contactDelegate = self
moveRectangles()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for ball in balls{
ball.isUserInteractionEnabled = false
}
physics()
}
func didBegin(_ contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case blueBallCategory | blueRectangleCategory:
for ball in balls{
ball.removeFromParent()
}
print("Alive! Blue ball has hit blue rectangle.")
case greenBallCategory | greenRectangleCategory:
print("Alive! Green ball has hit green rectangle.")
case realRedBallCategory | redRectangleCategory:
print("Alive! Red ball has hit red rectangle.")
case blueBallCategory | redRectangleCategory:
print("dead")
case blueBallCategory | greenRectangleCategory:
print("dead")
case realRedBallCategory | blueRectangleCategory:
print("dead")
case realRedBallCategory | greenRectangleCategory:
print("dead")
case greenBallCategory | redRectangleCategory:
print("dead")
case greenBallCategory | blueRectangleCategory:
print("dead")
default:
print("missed")
}
}
func spawnRectangles() {
redRectangle.position = CGPoint(x: 0, y: -400)
redRectangle.size = CGSize(width: 200, height: 20)
blueRectangle.position = CGPoint(x: -300, y: -200)
blueRectangle.size = CGSize(width: 200, height: 20)
greenRectangle.position = CGPoint(x: 100, y: -550)
greenRectangle.size = CGSize(width: 200, height: 20)
self.addChild(redRectangle)
self.addChild(blueRectangle)
self.addChild(greenRectangle)
wall1.position = CGPoint(x: -367.04, y: 0)
wall1.size = CGSize(width: 20, height: 1350)
wall1.physicsBody = SKPhysicsBody(rectangleOf: wall1.size)
wall1.physicsBody?.isDynamic = false
wall1.physicsBody?.affectedByGravity = false
self.addChild(wall1)
wall2.position = CGPoint(x: 367.04, y: 0)
wall2.size = CGSize(width: 20, height: 1350)
wall2.physicsBody = SKPhysicsBody(rectangleOf: wall2.size)
wall2.physicsBody?.isDynamic = false
wall2.physicsBody?.affectedByGravity = false
self.addChild(wall2)
top.position = CGPoint(x: 0, y: 657)
top.size = CGSize(width: 765, height: 20)
top.physicsBody = SKPhysicsBody(rectangleOf: top.size)
top.physicsBody?.isDynamic = false
top.physicsBody?.affectedByGravity = false
self.addChild(top)
bottom.size = CGSize(width: 765, height: 20)
bottom.position = CGPoint(x: 0, y: -657)
bottom.physicsBody = SKPhysicsBody(rectangleOf: bottom.size)
bottom.physicsBody?.isDynamic = false
bottom.physicsBody?.affectedByGravity = false
self.addChild(bottom)
}
func physics(){
for ball in balls{
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height/2)
ball.physicsBody?.contactTestBitMask = blueRectangleCategory | greenRectangleCategory | redRectangleCategory
}
redRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
redRectangle.physicsBody?.affectedByGravity = false
redRectangle.physicsBody?.isDynamic = false
blueRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
blueRectangle.physicsBody?.affectedByGravity = false
blueRectangle.physicsBody?.isDynamic = false
greenRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
greenRectangle.physicsBody?.isDynamic = false
greenRectangle.physicsBody?.affectedByGravity = false
balls[0].physicsBody?.categoryBitMask = blueBallCategory
balls[1].physicsBody?.categoryBitMask = greenBallCategory
balls[2].physicsBody?.categoryBitMask = realRedBallCategory
redRectangle.physicsBody?.categoryBitMask = redRectangleCategory
blueRectangle.physicsBody?.categoryBitMask = blueRectangleCategory
greenRectangle.physicsBody?.categoryBitMask = greenRectangleCategory
}
func moveRectangles(){
let redMoveRight = SKAction.moveTo(x: 300, duration: 2)
let redMoveLeft = SKAction.moveTo(x: -280, duration: 2)
let redWholeMovement = SKAction.repeatForever(SKAction.sequence([redMoveRight,redMoveLeft]))
redRectangle.run(redWholeMovement)
let blueMoveRight = SKAction.moveTo(x: 300, duration: 2)
let blueMoveLeft = SKAction.moveTo(x: -280, duration: 1.5)
let blueWholeMovement = SKAction.repeatForever(SKAction.sequence([blueMoveRight,blueMoveLeft]))
blueRectangle.run(blueWholeMovement)
let greenMoveRight = SKAction.moveTo(x: 300, duration: 2)
let greenMoveLeft = SKAction.moveTo(x: -280, duration: 1.5)
let greenWholeMovement = SKAction.repeatForever(SKAction.sequence([greenMoveLeft,greenMoveRight]))
greenRectangle.run(greenWholeMovement)
}
func spawnBalls(){
let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
ball.position = CGPoint(x: 0, y: 250)
ball.size = CGSize(width: 70, height: 70)
self.addChild(ball)
}
}
I want a new ball to spawn at the top of the screen if a ball hits a same colored rectangle. Right now when I run the app a randomly colored ball is spawned at the top and when the user clicks the ball drops. If the ball makes contact with a moving rectangle of the same color of the ball the game is supposed to keep going. But it just ends after. If anyone could help that would be great.Thanks!

You only spawn one ball in spawnBalls(). So when you touch only one ball appears. You should try to move spawnBalls() to touchesBegan().

Related

Swift: No contact detection between nodes

Issue
This is my code for my game. A brick falls and hits a side of a square. To differentiate what side is hit, four triangles are spawned that make the square. They are invisible from a low opacity. I am not receiving any contact between the brick node and the triangle node. The brick piece just falls right through the square. Any help?
Game Code
import SpriteKit
class GameScene: SKScene {
let basicTop = SKSpriteNode(imageNamed: "basic top");
let basicBottom = SKSpriteNode(imageNamed: "basic bottom");
let basicLeft = SKSpriteNode(imageNamed: "basic left");
let basicRight = SKSpriteNode(imageNamed: "basic right");
let brickTop = SKSpriteNode(imageNamed: "Top Side");
let brickBottom = SKSpriteNode(imageNamed: "Bottom Side");
let brickLeft = SKSpriteNode(imageNamed: "Left Side");
let brickRight = SKSpriteNode(imageNamed: "Right Side copy 2");
let basicBrick = SKSpriteNode(imageNamed: "Basic Brick")
override func didMove(to view: SKView) {
isUserInteractionEnabled = true
layoutScene()
}
func layoutScene() {
backgroundColor = UIColor(red: 10/255, green: 75/255, blue: 150/255, alpha: 1.0)
spawnBrick()
spawnBasicTop()
spawnBasicBottom()
spawnBasicLeft()
spawnBasicRight()
backgroundScene()
spawnBasicBrick()
setupPhysics()
}
func setupPhysics() {
physicsWorld.gravity = CGVector(dx: 0.0, dy: -0.1)
physicsWorld.contactDelegate = self
}
func spawnBrick() {
let randomFunc = [self.spawnbrickTop, self.spawnbrickBottom, self.spawnbrickLeft, self.spawnbrickRight]
let randomResult = Int(arc4random_uniform(UInt32(randomFunc.count)))
randomFunc[randomResult]()
}
func spawnbrickTop() {
brickTop.size = CGSize(width: 210, height: 105)
brickTop.name = "BrickTop"
brickTop.position = CGPoint(x: frame.midX, y: frame.maxY)
brickTop.zPosition = 1
//physics stuff begins here
brickTop.physicsBody = SKPhysicsBody(circleOfRadius: max(brickTop.size.width / 2,
brickTop.size.height / 2))
brickTop.physicsBody?.categoryBitMask = PhysicsCategories.brickTopCategory
brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
PhysicsCategories.basicBottomCategory |
PhysicsCategories.basicLeftCategory |
PhysicsCategories.basicRightCategory
brickTop.physicsBody?.collisionBitMask = PhysicsCategories.none
//bye bye physics
addChild(brickTop)
}
func spawnbrickBottom() {
brickBottom.size = CGSize(width: 150, height: 101)
brickBottom.name = "BrickBottom"
brickBottom.position = CGPoint(x: frame.midX, y: frame.maxY)
brickBottom.zPosition = 1
//physics stuff begins here
brickBottom.physicsBody = SKPhysicsBody(circleOfRadius: max(brickBottom.size.width / 2,
brickBottom.size.height / 2))
brickBottom.physicsBody?.categoryBitMask = PhysicsCategories.brickBottomCategory
brickBottom.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
PhysicsCategories.basicBottomCategory |
PhysicsCategories.basicLeftCategory |
PhysicsCategories.basicRightCategory
brickBottom.physicsBody?.collisionBitMask = PhysicsCategories.none
//bye bye physics
addChild(brickBottom)
}
func spawnbrickLeft() {
brickLeft.size = CGSize(width: 170, height: 80)
brickLeft.name = "BrickLeft"
brickLeft.position = CGPoint(x: frame.midX, y: frame.maxY)
brickLeft.zPosition = 1
//physics stuff begins here
brickLeft.physicsBody = SKPhysicsBody(circleOfRadius: max(brickLeft.size.width / 2,
brickLeft.size.height / 2))
brickLeft.physicsBody?.categoryBitMask = PhysicsCategories.brickLeftCategory
brickLeft.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
PhysicsCategories.basicBottomCategory |
PhysicsCategories.basicLeftCategory |
PhysicsCategories.basicRightCategory
brickLeft.physicsBody?.collisionBitMask = PhysicsCategories.none
//bye bye physics
addChild(brickLeft)
}
func spawnbrickRight() {
brickRight.size = CGSize(width: 140, height: 95)
brickRight.name = "BrickRight"
brickRight.position = CGPoint(x: frame.midX, y: frame.maxY)
brickRight.zPosition = 1
//physics stuff begins here
brickRight.physicsBody = SKPhysicsBody(circleOfRadius: max(brickRight.size.width / 2,
brickRight.size.height / 2))
brickRight.physicsBody?.categoryBitMask = PhysicsCategories.brickRightCategory
brickRight.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
PhysicsCategories.basicBottomCategory |
PhysicsCategories.basicLeftCategory |
PhysicsCategories.basicRightCategory
brickRight.physicsBody?.collisionBitMask = PhysicsCategories.none
//bye bye physics
addChild(brickRight)
}
func turnBasicTop() {
basicTop.run(SKAction.rotate(byAngle: .pi/2, duration: 0.25))
}
func turnBasicBottom() {
basicBottom.run(SKAction.rotate(byAngle: .pi/2, duration: 0.25))
}
func turnBasicLeft() {
basicLeft.run(SKAction.rotate(byAngle: .pi/2, duration: 0.25))
}
func turnBasicRight() {
basicRight.run(SKAction.rotate(byAngle: .pi/2, duration: 0.25))
}
func turnBasicBrick() {
basicBrick.run(SKAction.rotate(byAngle: .pi/2, duration: 0.25))
}
func gameOver() {
print("Game Over!")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
turnBasicTop()
turnBasicBottom()
turnBasicLeft()
turnBasicRight()
turnBasicBrick()
}
func spawnBasicBrick() {
basicBrick.size = CGSize(width: 200, height: 177.6)
basicBrick.position = CGPoint(x: frame.midX, y: frame.minY + basicBrick.size.width)
basicBrick.zPosition = 1
basicBrick.physicsBody = SKPhysicsBody(rectangleOf: basicBrick.size)
basicBrick.physicsBody?.categoryBitMask = PhysicsCategories.basicBrickCategory
basicBrick.physicsBody?.isDynamic = false
basicBrick.physicsBody?.allowsRotation = true
addChild(basicBrick)
}
func spawnBasicTop() {
basicTop.size = CGSize(width: 400, height: 400)
basicTop.position = CGPoint(x: 230, y: 200)
basicTop.zPosition = 1
basicTop.alpha = 0.3
basicTop.name = "BasicTop"
//physics stuff begins here
basicTop.physicsBody = SKPhysicsBody(rectangleOf: basicTop.size)
basicTop.physicsBody?.categoryBitMask = PhysicsCategories.basicTopCategory
basicTop.physicsBody?.isDynamic = false
basicTop.physicsBody?.allowsRotation = true
//bye bye physics
addChild(basicTop)
}
func spawnBasicBottom() {
basicBottom.size = CGSize(width: 400, height: 400)
basicBottom.position = CGPoint(x: 230, y: 200)
basicBottom.zPosition = 1
basicBottom.alpha = 0.3
basicBottom.name = "BasicBottom"
//physics stuff begins here
basicBottom.physicsBody = SKPhysicsBody(rectangleOf: basicBottom.size)
basicBottom.physicsBody?.categoryBitMask = PhysicsCategories.basicBottomCategory
basicBottom.physicsBody?.isDynamic = false
//bye bye physics
addChild(basicBottom)
}
func spawnBasicLeft() {
basicLeft.size = CGSize(width: 400, height: 400)
basicLeft.position = CGPoint(x: 230, y: 200)
basicLeft.zPosition = 1
basicLeft.alpha = 0.3
basicLeft.name = "BasicLeft"
//physics stuff begins here
basicLeft.physicsBody = SKPhysicsBody(rectangleOf: basicLeft.size)
basicLeft.physicsBody?.categoryBitMask = PhysicsCategories.basicLeftCategory
basicLeft.physicsBody?.isDynamic = false
//bye bye physics
addChild(basicLeft)
}
func spawnBasicRight() {
basicRight.size = CGSize(width: 400, height: 400)
basicRight.position = CGPoint(x: 230, y: 200)
basicRight.zPosition = 1
basicRight.alpha = 0.3
basicRight.name = "BasicRight"
//physics stuff begins here
basicRight.physicsBody = SKPhysicsBody(rectangleOf: basicRight.size)
basicRight.physicsBody?.categoryBitMask = PhysicsCategories.basicRightCategory
basicRight.physicsBody?.isDynamic = false
//bye bye physics
addChild(basicRight)
}
func backgroundScene() {
let constructionSite = SKSpriteNode(imageNamed: "Background Image")
constructionSite.size = frame.size
constructionSite.position = CGPoint(x: frame.midX, y: frame.midY)
constructionSite.zPosition = -1
addChild(constructionSite)
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
//01
//10
//11
let contactMask = contact.bodyA.categoryBitMask |
contact.bodyB.categoryBitMask
if contactMask == PhysicsCategories.brickTopCategory |
(PhysicsCategories.basicTopCategory) {
if let brickTop = contact.bodyA.node?.name == "BrickTop" ? contact.bodyA.node
as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
if brickTop == basicTop {
print("Correct!")
brickTop.run(SKAction.fadeOut(withDuration: 0.05), completion: {
brickTop.removeFromParent()
self.spawnBrick()
})
}
}
else if contactMask == PhysicsCategories.brickBottomCategory |
(PhysicsCategories.basicBottomCategory) {
if let brickBottom = contact.bodyA.node?.name == "BrickBottom" ? contact.bodyA.node
as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
if brickBottom == basicBottom {
print("Correct!")
brickBottom.run(SKAction.fadeOut(withDuration: 0.05), completion: {
brickBottom.removeFromParent()
self.spawnBrick()
})
}
}
else if contactMask == PhysicsCategories.brickLeftCategory |
(PhysicsCategories.basicLeftCategory) {
if let brickLeft = contact.bodyA.node?.name == "BrickLeft" ? contact.bodyA.node
as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
if brickLeft == basicLeft {
print("Correct!")
brickLeft.run(SKAction.fadeOut(withDuration: 0.05), completion: {
brickLeft.removeFromParent()
self.spawnBrick()
})
}
}
else if contactMask == PhysicsCategories.brickRightCategory |
(PhysicsCategories.basicRightCategory) {
if let brickRight = contact.bodyA.node?.name == "BrickRight" ? contact.bodyA.node
as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
if brickRight == basicRight {
print("Correct!")
brickRight.run(SKAction.fadeOut(withDuration: 0.05), completion: {
brickRight.removeFromParent()
self.spawnBrick()
})
}
}
else {
gameOver()
}
}
}
}
}
}
}
Settings File:
enum PhysicsCategories {
static let none: UInt32 = 0
static let brickCategory: UInt32 = 0x1//01
static let brickTopCategory: UInt32 = 0x1 //01
static let brickBottomCategory: UInt32 = 0x1//01
static let brickLeftCategory: UInt32 = 0x1//01
static let brickRightCategory: UInt32 = 0x1//01
static let basicTopCategory: UInt32 = 0x1 //10; shifts all bits to the left
static let basicBottomCategory: UInt32 = 0x1 //10; shifts all bits to the left
static let basicLeftCategory: UInt32 = 0x1 //10; shifts all bits to the left
static let basicRightCategory: UInt32 = 0x1 //10; shifts all bits to the left
static let basicBrickCategory: UInt32 = 0x1
}

SpriteKit - didBegin contact is called 30 times instead of 1 time

I am making a little FlappyBird clone and have got everything working as it should until I changed the physics body of the bird to be exact to the texture. Now what it does is when it flies through the gap in the pipes it counts 30 points instead of just 1 point.
This only happens when I use the texture exact physics body which I need because the bird isn't round nor rectangular.
How would I go about making the collision so it only collides once with each gap node. I have tried setting the categoryBitBask to 0 after the contact but then all the gaps after don't add to the point count anymore at all.
Here is the full game code:
var score = 0
class GameScene: SKScene, SKPhysicsContactDelegate {
var bird = SKSpriteNode()
var bg = SKSpriteNode()
var ground = SKSpriteNode()
var scoreLabel = SKLabelNode(fontNamed: "Candice")
var gameOverLabel = SKLabelNode(fontNamed: "Candice")
var countbg = SKSpriteNode()
var timer = Timer()
enum ColliderType: UInt32 {
case Bird = 1
case Object = 2
case Gap = 4
}
var gameOver = false
let swooshSound = SKAction.playSoundFileNamed("sfx_swooshing.wav", waitForCompletion: false)
let pointSound = SKAction.playSoundFileNamed("sfx_point.wav", waitForCompletion: false)
let hitSound = SKAction.playSoundFileNamed("sfx_hit.wav", waitForCompletion: false)
#objc func makePipes() {
let movePipes = SKAction.move(by: CGVector(dx: -2 * self.frame.width, dy: 0), duration: TimeInterval(self.frame.width / 150))
let removePipes = SKAction.removeFromParent()
let moveAndRemovePipes = SKAction.sequence([movePipes, removePipes])
let gapHeight = bird.size.height * 2.8
let movementAmount = arc4random() % UInt32(self.frame.height) / 2
let pipeOffset = CGFloat(movementAmount) - self.frame.height / 4
let pipeTexture = SKTexture(imageNamed: "pipe1.png")
let pipe1 = SKSpriteNode(texture: pipeTexture)
pipe1.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeTexture.size().height / 2 + gapHeight / 2 + pipeOffset)
pipe1.zPosition = 2
pipe1.run(moveAndRemovePipes)
pipe1.physicsBody = SKPhysicsBody(rectangleOf: pipeTexture.size())
pipe1.physicsBody!.isDynamic = false
pipe1.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
pipe1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe1.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(pipe1)
let pipe2Texture = SKTexture(imageNamed: "pipe2.png")
let pipe2 = SKSpriteNode(texture: pipe2Texture)
pipe2.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY - pipeTexture.size().height / 2 - gapHeight / 2 + pipeOffset)
pipe2.zPosition = 2
pipe2.run(moveAndRemovePipes)
pipe2.physicsBody = SKPhysicsBody(rectangleOf: pipe2Texture.size())
pipe2.physicsBody!.isDynamic = false
pipe2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(pipe2)
let gap = SKNode()
gap.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeOffset)
gap.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 1, height: gapHeight))
gap.physicsBody!.isDynamic = false
gap.run(moveAndRemovePipes)
gap.physicsBody!.contactTestBitMask = ColliderType.Bird.rawValue
gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue
gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue
self.addChild(gap)
}
func didBegin(_ contact: SKPhysicsContact) {
if gameOver == false {
if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue {
score += 1
scoreLabel.text = String(format: "%05d", score)
run(pointSound)
} else {
self.speed = 0
run(hitSound)
gameOver = true
timer.invalidate()
bird.removeFromParent()
let changeSceneAction = SKAction.run(changeScene)
self.run(changeSceneAction)
}
}
}
//MARK: Change to Game Over Scene
func changeScene(){
let sceneToMoveTo = GameOverScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
setupGame()
}
func setupGame() {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.makePipes), userInfo: nil, repeats: true)
let groundTexture = SKTexture(imageNamed: "ground.png")
let moveGroundAnimation = SKAction.move(by: CGVector(dx: -groundTexture.size().width, dy: 0), duration: 7)
let shiftGroundAnimation = SKAction.move(by: CGVector(dx: groundTexture.size().width, dy: 0), duration: 0)
let moveGroundForever = SKAction.repeatForever(SKAction.sequence([moveGroundAnimation, shiftGroundAnimation]))
var i: CGFloat = 0
while i < 3 {
ground = SKSpriteNode(texture: groundTexture)
ground.position = CGPoint(x: self.size.width * i, y: self.size.height / 7.65)
ground.zPosition = 3
ground.run(moveGroundForever)
self.addChild(ground)
i += 1
}
let bottom = SKNode()
bottom.position = CGPoint(x: self.frame.midX, y: self.size.height / 7)
bottom.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.width, height: 1))
bottom.physicsBody!.isDynamic = false
bottom.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
bottom.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
bottom.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(bottom)
let bgTexture = SKTexture(imageNamed: "bg.png")
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bg.size = self.frame.size
bg.zPosition = 1
self.addChild(bg)
let birdTexture = SKTexture(imageNamed: "flappy1.png")
let bird2Texture = SKTexture(imageNamed: "flappy2.png")
let bird3Texture = SKTexture(imageNamed: "flappy3.png")
let bird4Texture = SKTexture(imageNamed: "flappy4.png")
let bird5Texture = SKTexture(imageNamed: "flappy5.png")
let bird6Texture = SKTexture(imageNamed: "flappy6.png")
let animation = SKAction.animate(with: [birdTexture, bird2Texture, bird3Texture, bird4Texture, bird5Texture, bird6Texture], timePerFrame: 0.1)
let makeBirdFlap = SKAction.repeatForever(animation)
bird = SKSpriteNode(texture: birdTexture)
bird.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bird.setScale(1)
bird.zPosition = 6
bird.run(makeBirdFlap)
self.addChild(bird)
bird.physicsBody = SKPhysicsBody.init(circleOfRadius: birdTexture.size().height / 2)
//bird.physicsBody = SKPhysicsBody(texture: birdTexture, size: birdTexture.size())
bird.physicsBody!.isDynamic = false
bird.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
bird.physicsBody!.categoryBitMask = ColliderType.Bird.rawValue
bird.physicsBody!.collisionBitMask = ColliderType.Bird.rawValue
let countbg = SKSpriteNode(imageNamed: "count_bg.png")
countbg.position = CGPoint(x: self.size.width / 4.8, y: self.size.height * 0.94)
countbg.setScale(0.8)
countbg.zPosition = 4
addChild(countbg)
scoreLabel.fontSize = 80
scoreLabel.text = String(format: "%05d", score)
scoreLabel.fontColor = SKColor(red: 218/255, green: 115/255, blue: 76/255, alpha: 1)
scoreLabel.position = CGPoint(x: self.size.width / 4, y: self.size.height * 0.94)
scoreLabel.zPosition = 5
addChild(scoreLabel)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameOver == false {
bird.physicsBody!.isDynamic = true
bird.physicsBody!.velocity = CGVector(dx: 0, dy: 0)
bird.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 280))
//run(swooshSound)
} else {
gameOver = false
score = 0
self.speed = 1
self.removeAllChildren()
setupGame()
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
If you would be using RxSwift, you would be able to easily get rid of those extra events easily by using debounce() or throttle() or distinctUntilChanged(). If you are willing to try this approach, give RxSpriteKit framework a go. Otherwise, store a timestamp of the last contact and ignore the following contacts until some time period elapses.

How to create a subview inside an SKScene?

Before "Buy Ship" is pressed So I am trying to create a shop where players can buy new ships. When the player hits the "buy button" image I want a combination of images and texts to become visible which acts as a sort of conformation screen. Hopefully you can see here what I mean. I would also greatly appreciate if you could tell me how to dim everything besides the conformation box. After "Buy Ship" is pressed.
This is what my code looks like so far:
import Foundation
import SpriteKit
class ShopPage1: SKScene{
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
let balance = SKLabelNode(fontNamed: "The Bold Font")
balance.text = "$\(balanceAmount)"
balance.fontSize = 100
balance.fontColor = SKColor.green
balance.position = CGPoint(x: self.size.width/2, y: self.size.height*0.87)
balance.zPosition = 1
self.addChild(balance)
let backToMainMenuButton = SKSpriteNode(imageNamed: "backButton2")
backToMainMenuButton.position = CGPoint(x: self.size.width*0.25, y: self.size.height*0.89)
backToMainMenuButton.zPosition = 1
backToMainMenuButton.size = CGSize(width: 200, height: 200)
backToMainMenuButton.name = "backToMainMenuButton"
self.addChild(backToMainMenuButton)
let shipNameLabel = SKLabelNode(fontNamed: "The Bold Font")
shipNameLabel.text = "Stealth"
shipNameLabel.fontSize = 200
shipNameLabel.fontColor = SKColor.white
shipNameLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.60)
shipNameLabel.zPosition = 1
shipNameLabel.name = "shipNameLabel"
self.addChild(shipNameLabel)
let nextShipButton = SKSpriteNode(imageNamed: "nextShipButton1")
nextShipButton.position = CGPoint(x: self.size.width*0.75, y: self.size.height*0.40)
nextShipButton.zPosition = 1
nextShipButton.size = CGSize(width: 300, height: 300)
nextShipButton.name = "nextShipButton"
self.addChild(nextShipButton)
let nextShipClick = SKLabelNode(fontNamed: "The Bold Font")
nextShipClick.text = "▲"
nextShipClick.fontSize = 300
nextShipClick.fontColor = UIColor.clear
nextShipClick.position = CGPoint(x: self.size.width*0.753, y: self.size.height*0.36)
nextShipClick.zPosition = 2
nextShipClick.name = "nextShipClick"
self.addChild(nextShipClick)
let shipForSale = SKSpriteNode(imageNamed: "playerShip4")
shipForSale.position = CGPoint(x: self.size.width/2, y: self.size.height*0.40)
shipForSale.zPosition = 1
shipForSale.size = CGSize(width: 150, height: 300)
self.addChild(shipForSale)
let shipPodium = SKSpriteNode(imageNamed: "shipPodium")
shipPodium.position = CGPoint(x: self.size.width*0.527, y: self.size.height*0.31)
shipPodium.zPosition = 1
shipPodium.size = CGSize(width: 1200, height: 70)
self.addChild(shipPodium)
let shipsCostLabel = SKLabelNode(fontNamed: "The Bold Font")
shipsCostLabel.text = "$500"
shipsCostLabel.fontSize = 200
shipsCostLabel.fontColor = SKColor.white
shipsCostLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.20)
shipsCostLabel.zPosition = 1
self.addChild(shipsCostLabel)
let shipBuyButton = SKSpriteNode(imageNamed: "shipBuyButton")
shipBuyButton.position = CGPoint(x: self.size.width*0.54, y: self.size.height*0.15)
shipBuyButton.zPosition = 1
shipBuyButton.size = CGSize(width: 1500, height: 900)
shipBuyButton.name = "shipBuyButton"
self.addChild(shipBuyButton)
let conformationBackground = SKSpriteNode(imageNamed: "conformationBackground")
conformationBackground.position = CGPoint(x: self.size.width*0.51, y: self.size.height*0.40)
conformationBackground.zPosition = 2
conformationBackground.size = CGSize(width: 1300, height: 1400)
conformationBackground.name = "conformationBackground"
self.addChild(conformationBackground)
let conformationScreenTextTop = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextTop.text = "Are you sure you wish to"
conformationScreenTextTop.fontSize = 80
conformationScreenTextTop.fontColor = SKColor.white
conformationScreenTextTop.position = CGPoint(x: self.size.width/2, y: self.size.height*0.46)
conformationScreenTextTop.zPosition = 3
self.addChild(conformationScreenTextTop)
let conformationScreenTextBottom = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextBottom.text = "pruchase this ship?"
conformationScreenTextBottom.fontSize = 80
conformationScreenTextBottom.fontColor = SKColor.white
conformationScreenTextBottom.position = CGPoint(x: self.size.width/2, y: self.size.height*0.41)
conformationScreenTextBottom.zPosition = 3
self.addChild(conformationScreenTextBottom)
let conformationScreenTextYes = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextYes.text = "Yes"
conformationScreenTextYes.fontSize = 150
conformationScreenTextYes.fontColor = SKColor.green
conformationScreenTextYes.position = CGPoint(x: self.size.width*0.30, y: self.size.height*0.30)
conformationScreenTextYes.zPosition = 3
self.addChild(conformationScreenTextYes)
let conformationScreenTextNo = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextNo.text = "No"
conformationScreenTextNo.fontSize = 150
conformationScreenTextNo.fontColor = SKColor.red
conformationScreenTextNo.position = CGPoint(x: self.size.width*0.70, y: self.size.height*0.30)
conformationScreenTextNo.zPosition = 3
self.addChild(conformationScreenTextNo)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let tappedNode = atPoint(pointOfTouch)
let tappedNodeName = tappedNode.name
if tappedNodeName == "nextShipClick"{
let sceneToMoveTo = ShopPage2(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
if tappedNodeName == "backToMainMenuButton"{
let sceneToMoveTo = MainMenuScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
}
}
}
As Whirlwind said in his comment you can create an SKNode to the center of your scene (position CGPoint.zero) prepare it with all your stuff and hide it with the alpha properties set to 0 and put it's zPosition to -1 (under all the other visible nodes of your scene).
So when you button will be pressed, you simply change the zPosition to an highest value and the alpha to 1. To make more realistic these action s you could use some animations like:
extension UIView {
func fadeIn(_ duration:TimeInterval=1.0) {
UIView.animate(withDuration: duration, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 1.0 // Instead of a specific instance of, say, birdTypeLabel, we simply set [thisInstance] (ie, self)'s alpha
}, completion: nil)
}
func fadeOut(_ duration:TimeInterval=1.0) {
UIView.animate(withDuration: duration, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.alpha = 0.0
}, completion: nil)
}
}
I have figured out how to get the conformation screen to work. Thanks to #AlessandroOrnano for all the help! I have attached my code below for future reference. If anyone has a more efficient way of doing this I would greatly appreciate any suggestions.
import Foundation
import SpriteKit
class ShopPage1: SKScene{
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
let balance = SKLabelNode(fontNamed: "The Bold Font")
balance.text = "$\(balanceAmount)"
balance.fontSize = 100
balance.fontColor = SKColor.green
balance.position = CGPoint(x: self.size.width/2, y: self.size.height*0.87)
balance.zPosition = 1
self.addChild(balance)
let backToMainMenuButton = SKSpriteNode(imageNamed: "backButton2")
backToMainMenuButton.position = CGPoint(x: self.size.width*0.25, y: self.size.height*0.89)
backToMainMenuButton.zPosition = 1
backToMainMenuButton.size = CGSize(width: 200, height: 200)
backToMainMenuButton.name = "backToMainMenuButton"
self.addChild(backToMainMenuButton)
let shipNameLabel = SKLabelNode(fontNamed: "The Bold Font")
shipNameLabel.text = "Stealth"
shipNameLabel.fontSize = 200
shipNameLabel.fontColor = SKColor.white
shipNameLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.60)
shipNameLabel.zPosition = 1
shipNameLabel.name = "shipNameLabel"
self.addChild(shipNameLabel)
let nextShipButton = SKSpriteNode(imageNamed: "nextShipButton1")
nextShipButton.position = CGPoint(x: self.size.width*0.75, y: self.size.height*0.40)
nextShipButton.zPosition = 1
nextShipButton.size = CGSize(width: 300, height: 300)
nextShipButton.name = "nextShipButton"
self.addChild(nextShipButton)
let nextShipClick = SKLabelNode(fontNamed: "The Bold Font")
nextShipClick.text = "▲"
nextShipClick.fontSize = 300
nextShipClick.fontColor = UIColor.clear
nextShipClick.position = CGPoint(x: self.size.width*0.753, y: self.size.height*0.36)
nextShipClick.zPosition = 2
nextShipClick.name = "nextShipClick"
self.addChild(nextShipClick)
let shipForSale = SKSpriteNode(imageNamed: "playerShip4")
shipForSale.position = CGPoint(x: self.size.width/2, y: self.size.height*0.40)
shipForSale.zPosition = 1
shipForSale.size = CGSize(width: 150, height: 300)
self.addChild(shipForSale)
let shipPodium = SKSpriteNode(imageNamed: "shipPodium")
shipPodium.position = CGPoint(x: self.size.width*0.527, y: self.size.height*0.31)
shipPodium.zPosition = 1
shipPodium.size = CGSize(width: 1200, height: 70)
self.addChild(shipPodium)
let shipsCostLabel = SKLabelNode(fontNamed: "The Bold Font")
shipsCostLabel.text = "$500"
shipsCostLabel.fontSize = 200
shipsCostLabel.fontColor = SKColor.white
shipsCostLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.20)
shipsCostLabel.zPosition = 1
self.addChild(shipsCostLabel)
let shipBuyButton = SKSpriteNode(imageNamed: "shipBuyButton")
shipBuyButton.position = CGPoint(x: self.size.width*0.54, y: self.size.height*0.15)
shipBuyButton.zPosition = 1
shipBuyButton.size = CGSize(width: 1500, height: 900)
shipBuyButton.name = "shipBuyButton"
self.addChild(shipBuyButton)
let shipBuyButtonClick = SKLabelNode(fontNamed: "The Bold Font")
shipBuyButtonClick.text = "▅▅"
shipBuyButtonClick.fontSize = 300
shipBuyButtonClick.fontColor = UIColor.clear
shipBuyButtonClick.position = CGPoint(x: self.size.width/2, y: self.size.height*0.05)
shipBuyButtonClick.zPosition = 2
shipBuyButtonClick.name = "shipBuyButtonClick"
self.addChild(shipBuyButtonClick)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let tappedNode = atPoint(pointOfTouch)
let tappedNodeName = tappedNode.name
if tappedNodeName == "nextShipClick"{
let sceneToMoveTo = ShopPage2(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
if tappedNodeName == "backToMainMenuButton"{
let sceneToMoveTo = MainMenuScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
if tappedNodeName == "shipBuyButtonClick"{
let sceneToMoveTo = ShopPage1ConformationScreen(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
}
}
}
This is the code for ShopPage1ConformationScreen:
import Foundation
import SpriteKit
let shipForSale = SKSpriteNode(imageNamed: "playerShip4")
class ShopPage1ConformationScreen: SKScene{
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
let balance = SKLabelNode(fontNamed: "The Bold Font")
balance.text = "$\(balanceAmount)"
balance.fontSize = 100
balance.fontColor = SKColor.green
balance.position = CGPoint(x: self.size.width/2, y: self.size.height*0.87)
balance.zPosition = 1
self.addChild(balance)
let backToMainMenuButton = SKSpriteNode(imageNamed: "backButton2")
backToMainMenuButton.position = CGPoint(x: self.size.width*0.25, y: self.size.height*0.89)
backToMainMenuButton.zPosition = 1
backToMainMenuButton.size = CGSize(width: 200, height: 200)
backToMainMenuButton.name = "backToMainMenuButton"
self.addChild(backToMainMenuButton)
let shipNameLabel = SKLabelNode(fontNamed: "The Bold Font")
shipNameLabel.text = "Stealth"
shipNameLabel.fontSize = 200
shipNameLabel.fontColor = SKColor.white
shipNameLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.60)
shipNameLabel.zPosition = 1
shipNameLabel.name = "shipNameLabel"
self.addChild(shipNameLabel)
let nextShipButton = SKSpriteNode(imageNamed: "nextShipButton1")
nextShipButton.position = CGPoint(x: self.size.width*0.75, y: self.size.height*0.40)
nextShipButton.zPosition = 1
nextShipButton.size = CGSize(width: 300, height: 300)
nextShipButton.name = "nextShipButton"
self.addChild(nextShipButton)
let nextShipClick = SKLabelNode(fontNamed: "The Bold Font")
nextShipClick.text = "▲"
nextShipClick.fontSize = 300
nextShipClick.fontColor = UIColor.clear
nextShipClick.position = CGPoint(x: self.size.width*0.753, y: self.size.height*0.36)
nextShipClick.zPosition = 2
nextShipClick.name = "nextShipClick"
self.addChild(nextShipClick)
shipForSale.position = CGPoint(x: self.size.width/2, y: self.size.height*0.40)
shipForSale.zPosition = 1
shipForSale.size = CGSize(width: 150, height: 300)
self.addChild(shipForSale)
let shipPodium = SKSpriteNode(imageNamed: "shipPodium")
shipPodium.position = CGPoint(x: self.size.width*0.527, y: self.size.height*0.31)
shipPodium.zPosition = 1
shipPodium.size = CGSize(width: 1200, height: 70)
self.addChild(shipPodium)
let shipsCostLabel = SKLabelNode(fontNamed: "The Bold Font")
shipsCostLabel.text = "$500"
shipsCostLabel.fontSize = 200
shipsCostLabel.fontColor = SKColor.white
shipsCostLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.20)
shipsCostLabel.zPosition = 1
self.addChild(shipsCostLabel)
let shipBuyButton = SKSpriteNode(imageNamed: "shipBuyButton")
shipBuyButton.position = CGPoint(x: self.size.width*0.54, y: self.size.height*0.15)
shipBuyButton.zPosition = 1
shipBuyButton.size = CGSize(width: 1500, height: 900)
shipBuyButton.name = "shipBuyButton"
self.addChild(shipBuyButton)
let conformationBackground = SKSpriteNode(imageNamed: "conformationBackground")
conformationBackground.position = CGPoint(x: self.size.width*0.51, y: self.size.height*0.40)
conformationBackground.zPosition = 2
conformationBackground.size = CGSize(width: 1300, height: 1400)
conformationBackground.name = "conformationBackground"
self.addChild(conformationBackground)
let conformationScreenTextTop = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextTop.text = "Are you sure you wish to"
conformationScreenTextTop.fontSize = 80
conformationScreenTextTop.fontColor = SKColor.white
conformationScreenTextTop.position = CGPoint(x: self.size.width/2, y: self.size.height*0.46)
conformationScreenTextTop.zPosition = 3
conformationScreenTextTop.name = "comformationScreenTextTop"
self.addChild(conformationScreenTextTop)
let conformationScreenTextBottom = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextBottom.text = "purchase this ship?"
conformationScreenTextBottom.fontSize = 80
conformationScreenTextBottom.fontColor = SKColor.white
conformationScreenTextBottom.position = CGPoint(x: self.size.width/2, y: self.size.height*0.41)
conformationScreenTextBottom.zPosition = 3
conformationScreenTextBottom.name = "conformationScreenTextBottom"
self.addChild(conformationScreenTextBottom)
let conformationScreenTextYes = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextYes.text = "Yes"
conformationScreenTextYes.fontSize = 150
conformationScreenTextYes.fontColor = SKColor.green
conformationScreenTextYes.position = CGPoint(x: self.size.width*0.30, y: self.size.height*0.30)
conformationScreenTextYes.zPosition = 3
conformationScreenTextYes.name = "conformationScreenTextYes"
self.addChild(conformationScreenTextYes)
let conformationScreenTextNo = SKLabelNode(fontNamed: "The Bold Font")
conformationScreenTextNo.text = "No"
conformationScreenTextNo.fontSize = 150
conformationScreenTextNo.fontColor = SKColor.red
conformationScreenTextNo.position = CGPoint(x: self.size.width*0.70, y: self.size.height*0.30)
conformationScreenTextNo.zPosition = 3
conformationScreenTextNo.name = "conformationScreenTextNo"
self.addChild(conformationScreenTextNo)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let tappedNode = atPoint(pointOfTouch)
let tappedNodeName = tappedNode.name
if(balanceAmount >= 500){
if tappedNodeName == "conformationScreenTextYes"{
player = shipForSale
balanceAmount -= 500
let sceneToMoveTo = ShopPage1(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
}
if tappedNodeName == "conformationScreenTextNo"{
let sceneToMoveTo = ShopPage1(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
}
}
}
For additional shop pages just copy and paste these sets of codes. With the exception of changing the the tapped nodes around to the correct order in which you wish to move from page to page.

Swift 3 Update Label Node with Incrementing Integer

I am new to coding, so be kind. I am creating a game in Swift 3, similar to Flappy Bird, and am having a problem with my score node. I have created a Label Node for the score but when the player contacts the scoreDetect node no score is added. I can't work out whether I've coded the section that adds a point incorrectly or whether my physics code is incorrect. Any help is appreciated. Thanks.
import SpriteKit
import GameplayKit
struct PhysicsCategory {
static let player : UInt32 = 0x1 << 1
static let roof : UInt32 = 0x1 << 2
static let floor : UInt32 = 0x1 << 3
static let lowerObstacle : UInt32 = 0x1 << 4
static let upperObstacle : UInt32 = 0x1 << 5
static let scoreDetect : UInt32 = 0x1 << 6
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var bgColor = UIColor(red: 39/255, green: 41/255, blue: 56/255, alpha: 1.0)
var roof = SKSpriteNode()
var floor = SKSpriteNode()
var lowerObstacle = SKSpriteNode()
var upperObstacle = SKSpriteNode()
var player = SKSpriteNode()
var randomValue = Int()
var scoreDetect = SKSpriteNode()
var scoreLabel = SKLabelNode()
var scoreValue = Int()
var logo = SKSpriteNode()
var gameStarted = Bool()
override func didMove(to view: SKView) {
createPlayer()
createTiles()
createScoreLabel()
physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.0)
backgroundColor = bgColor
let delay = SKAction.wait(forDuration: 3)
let repeatingAction = SKAction.run(repeatingSequence)
let sequence = SKAction.sequence([ delay, repeatingAction ])
run(SKAction.repeatForever(sequence))
}
// Random Selector For Obstacles
func randomSelector() -> Int {
let array = [1, 2, 3]
return Int(arc4random_uniform(UInt32(array.count)))
}
// Player Rules
func createPlayer() {
player = SKSpriteNode(imageNamed: "Player")
player.setScale(0.4)
player.position = CGPoint(x: -player.size.width, y: 0)
player.zPosition = 2
addChild(player)
player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Player"), size: player.size)
player.physicsBody?.categoryBitMask = PhysicsCategory.player
player.physicsBody?.collisionBitMask = PhysicsCategory.roof | PhysicsCategory.floor | PhysicsCategory.upperObstacle | PhysicsCategory.lowerObstacle | PhysicsCategory.scoreDetect
player.physicsBody?.contactTestBitMask = PhysicsCategory.roof | PhysicsCategory.floor | PhysicsCategory.upperObstacle | PhysicsCategory.lowerObstacle | PhysicsCategory.scoreDetect
player.physicsBody?.allowsRotation = false
player.physicsBody?.affectedByGravity = true
player.physicsBody?.isDynamic = false
}
// Create Background
func createTiles() {
roof = SKSpriteNode(imageNamed: "Roof")
roof.position = CGPoint(x: 0, y: self.frame.height / 2 - roof.size.height / 2)
roof.zPosition = 1
addChild(roof)
roof.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Roof"), size: roof.size)
roof.physicsBody?.categoryBitMask = PhysicsCategory.roof
roof.physicsBody?.collisionBitMask = PhysicsCategory.player
roof.physicsBody?.contactTestBitMask = PhysicsCategory.player
roof.physicsBody?.allowsRotation = false
roof.physicsBody?.affectedByGravity = false
roof.physicsBody?.isDynamic = false
floor = SKSpriteNode(imageNamed: "Floor")
floor.position = CGPoint(x: 0, y: -self.frame.height / 2)
floor.zPosition = 1
addChild(floor)
floor.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Floor"), size: floor.size)
floor.physicsBody?.categoryBitMask = PhysicsCategory.floor
floor.physicsBody?.collisionBitMask = PhysicsCategory.player
floor.physicsBody?.contactTestBitMask = PhysicsCategory.player
floor.physicsBody?.allowsRotation = false
floor.physicsBody?.affectedByGravity = false
floor.physicsBody?.isDynamic = false
}
// Obstacle Spawn Rules
func createObstacle() {
if (randomSelector() == 1) {
lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 1")
upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 3")
scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))
upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 2 + 12)
lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height - 15)
scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
}
else {
if (randomSelector() == 2) {
lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 2")
upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 2")
scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))
upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 1.9)
lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height / 1.5)
scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
}
else {
lowerObstacle = SKSpriteNode(imageNamed: "Fire Barrel 3")
upperObstacle = SKSpriteNode(imageNamed: "Fire Barrel 1")
scoreDetect = SKSpriteNode(color: UIColor.red, size: CGSize(width: 32, height: frame.height))
upperObstacle.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width / 2, y: self.frame.height / 2 - upperObstacle.size.height / 1.5 + 4)
lowerObstacle.position = CGPoint(x: self.frame.width / 2 + lowerObstacle.size.width / 2, y: -self.frame.height / 2 + lowerObstacle.size.height / 1.75 + 7)
scoreDetect.position = CGPoint(x: self.frame.width / 2 + upperObstacle.size.width, y: 0)
}
}
lowerObstacle.zPosition = 2
lowerObstacle.setScale(0.8)
lowerObstacle.physicsBody = SKPhysicsBody(rectangleOf: lowerObstacle.size)
lowerObstacle.physicsBody?.categoryBitMask = PhysicsCategory.lowerObstacle
lowerObstacle.physicsBody?.collisionBitMask = PhysicsCategory.player
lowerObstacle.physicsBody?.contactTestBitMask = PhysicsCategory.player
lowerObstacle.physicsBody?.allowsRotation = false
lowerObstacle.physicsBody?.affectedByGravity = false
lowerObstacle.physicsBody?.isDynamic = false
upperObstacle.zPosition = 2
upperObstacle.setScale(0.8)
upperObstacle.physicsBody = SKPhysicsBody(rectangleOf: upperObstacle.size)
upperObstacle.physicsBody?.categoryBitMask = PhysicsCategory.upperObstacle
upperObstacle.physicsBody?.collisionBitMask = PhysicsCategory.player
upperObstacle.physicsBody?.contactTestBitMask = PhysicsCategory.player
upperObstacle.physicsBody?.allowsRotation = false
upperObstacle.physicsBody?.affectedByGravity = false
upperObstacle.physicsBody?.isDynamic = false
scoreDetect.physicsBody?.categoryBitMask = PhysicsCategory.scoreDetect
scoreDetect.physicsBody?.collisionBitMask = PhysicsCategory.player
scoreDetect.physicsBody?.contactTestBitMask = PhysicsCategory.player
scoreDetect.physicsBody?.allowsRotation = false
scoreDetect.physicsBody?.affectedByGravity = false
scoreDetect.physicsBody?.isDynamic = false
addChild(lowerObstacle)
addChild(upperObstacle)
addChild(scoreDetect)
lowerObstacle.run(
SKAction.sequence([
SKAction.wait(forDuration: 6),
SKAction.removeFromParent()
])
)
upperObstacle.run(
SKAction.sequence([
SKAction.wait(forDuration: 6),
SKAction.removeFromParent()
])
)
scoreDetect.run(
SKAction.sequence([
SKAction.wait(forDuration: 6),
SKAction.removeFromParent()
])
)
}
// Create Spawn and Move Sequence
func repeatingSequence() {
createObstacle()
let moveLowerObstacle = SKAction.moveBy(x: -self.frame.width - lowerObstacle.size.width * 2, y: 0, duration: 5)
lowerObstacle.run(moveLowerObstacle)
let moveUpperObstacle = SKAction.moveBy(x: -self.frame.width - upperObstacle.size.width * 2, y: 0, duration: 5)
upperObstacle.run(moveUpperObstacle)
let moveScoreDetect = SKAction.moveBy(x: -self.frame.width - upperObstacle.size.width * 2, y: 0, duration: 5)
scoreDetect.run(moveScoreDetect)
}
func createScoreLabel() {
scoreLabel = SKLabelNode(fontNamed: "Arial")
scoreLabel.fontSize = 22
scoreLabel.position = CGPoint(x: 305, y: -638)
scoreLabel.horizontalAlignmentMode = .center
scoreLabel.verticalAlignmentMode = .center
scoreLabel.text = "SCORE: \(scoreValue)"
scoreLabel.fontColor = UIColor.white
scoreLabel.zPosition = 4
addChild(scoreLabel)
}
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == PhysicsCategory.scoreDetect && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.scoreDetect {
scoreValue += 1
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
player.physicsBody?.isDynamic = true
let impulse = CGVector(dx: 0, dy: 200)
player.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
player.physicsBody?.applyImpulse(impulse)
}
override func update(_ currentTime: TimeInterval) {
}
}
You are properly updating the scoreValue property. However you also need to update what is shown inside the scoreLabel accordingly to the new value of scoreValue.
So replace this
var scoreValue = Int()
with this
var scoreValue = Int() {
didSet {
scoreLabel.text = self.scoreValue.description
}
}
Now every time scoreValue changes, the scoreLabel is updated automatically.

Use random number (arc4random_uniform) to display random shapes

The purpose for this code is to do random number to display random shapes but the simulator displays them in the same spot which is the bottom left corner of the screen, for some reason the random for the position which is a is not working.
Code:
import UIKit
import SpriteKit
import Darwin
class StartGame: SKScene {
var scoreLabel = SKLabelNode(fontNamed: "cholkDuster")
var square = SKSpriteNode(imageNamed: "square")
var circle = SKSpriteNode(imageNamed: "circle")
var rectangle = SKSpriteNode(imageNamed: "rectangle")
var triangle = SKSpriteNode(imageNamed: "triangle")
let bg = SKSpriteNode(imageNamed: "background.png")
var score = 0
override func didMoveToView(view: SKView) {
//random number for the shapes
var timecreatShapes = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("creatShapes"), userInfo: nil, repeats: true)
//background image
bg.position = CGPoint(x: CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
bg.size.width = self.frame.size.width
bg.size.height = self.frame.size.height
self.addChild(bg)
self.scoreLabel.text = "0"
self.scoreLabel.fontSize = 42
self.scoreLabel.position = CGPoint(x: CGRectGetMidX(self.frame) , y: CGRectGetMidY(self.frame))
self.addChild(scoreLabel)
scoreLabel.zPosition = 2
self.physicsWorld.gravity = CGVectorMake(0, -0.5)
//declaring a square image
square.size = CGSize(width: 150, height: 100)
square.color = SKColor.redColor()
square.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
square.physicsBody?.dynamic = true
square.physicsBody?.allowsRotation = false
//declaring a circle image
circle.size = CGSize(width: 150, height: 100)
circle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
circle.physicsBody?.dynamic = true
circle.physicsBody?.allowsRotation = false
//declaring a triangle
triangle.size = CGSize(width: 150, height: 100)
triangle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
triangle.physicsBody?.dynamic = true
triangle.physicsBody?.allowsRotation = false
//declaring rectangle
rectangle.size = CGSize(width: 150, height: 100)
rectangle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
rectangle.physicsBody?.dynamic = true
rectangle.physicsBody?.allowsRotation = false
}
func creatShapes () {
var x = Int ( arc4random_uniform(4) + 1)
var a = CGFloat ( arc4random_uniform(1000) + 1)
switch(x){
case 1:
circle.position = CGPoint (x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"circle"))
case 2:
square.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"square"))
case 3:
rectangle.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"rectangle"))
case 4:
triangle.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"triangle"))
default:
break
}
println(x)
println(a)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (self.nodeAtPoint(location) == self.square || self.nodeAtPoint(location) == self.triangle || self.nodeAtPoint(location) == self.circle || self.nodeAtPoint(location) == self.rectangle){
self.score++
}
self.scoreLabel.text = String(self.score)
}
}