How to fix this NSTimer issue? - swift

Everything is fine until I use NSTimer to run the tree, that the images of tree is gone. I use SKview to show the physic then I find out that the code is still run, just only the image is gone. How can I fix it?
Part 1
class PlayScene: SKScene {
var BG6 = SKSpriteNode()
var balloon = SKSpriteNode()
var tree1 = SKSpriteNode()
var tree2 = SKSpriteNode()
Part 2
override func didMoveToView(view: SKView) {
MakeBG()
// add balloon
var ballontexture = SKTexture(imageNamed: "Balloon.png")
balloon = SKSpriteNode(texture: ballontexture)
balloon.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/5)
balloon.physicsBody = SKPhysicsBody(rectangleOfSize: balloon.size)
balloon.physicsBody?.dynamic = true
balloon.physicsBody?.allowsRotation = false
balloon.zPosition = 5
self.addChild(balloon)
var timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("MakeTree"), userInfo: nil, repeats: true)
var ground = SKNode()
ground.position = CGPointMake(0, 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width,1))
ground.physicsBody?.dynamic = false
self.addChild(ground)
}
Part 3
func MakeBG(){
// chen hinh nen
//BG1
var BG1texture = SKTexture(imageNamed: "BG2")
var BG1 = SKSpriteNode(texture: BG1texture)
BG1.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
BG1.size.height = self.size.height
var BG1move = SKAction.moveToY(-self.frame.size.height, duration: 90)
BG1.runAction(BG1move)
self.addChild(BG1)
//BG2
var BG2texture = SKTexture(imageNamed: "BG3")
var BG2 = SKSpriteNode(texture: BG2texture)
BG2.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2 + self.frame.size.height)
BG2.size.height = self.size.height
var BG2move = SKAction.moveToY(-self.frame.size.height, duration: 140)
BG2.runAction(BG2move)
self.addChild(BG2)
//BG3
var BG3texture = SKTexture(imageNamed: "BG4")
var BG3 = SKSpriteNode(texture: BG3texture)
BG3.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2 + self.frame.size.height*2)
BG3.size.height = self.size.height
var BG3move = SKAction.moveToY(-self.frame.size.height, duration: 195)
BG3.runAction(BG3move)
self.addChild(BG3)
//BG4
var BG4texture = SKTexture(imageNamed: "BG5")
var BG4 = SKSpriteNode(texture: BG4texture)
BG4.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2 + self.frame.size.height*3)
BG4.size.height = self.size.height
var BG4move = SKAction.moveToY(-self.frame.size.height, duration: 250)
BG4.runAction(BG4move)
self.addChild(BG4)
//BG5
var BG5texture = SKTexture(imageNamed: "BG6")
var BG5 = SKSpriteNode(texture: BG5texture)
BG5.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2 + self.frame.size.height*4)
BG5.size.height = self.size.height
var BG5move = SKAction.moveToY(-self.frame.size.height, duration: 305)
BG5.runAction(BG5move)
self.addChild(BG5)
// BG6
var BG6texture = SKTexture(imageNamed: "BG7")
BG6 = SKSpriteNode(texture: BG6texture)
BG6.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2 + self.frame.size.height*5 + self.frame.size.height*5)
BG6.size.height = self.size.height
BG6.runAction(SKAction.moveTo(CGPoint(x: self.size.width/2 , y: self.size.height/2), duration: 276.5))
self.addChild(BG6)
}
func MakeTree(){
// between
let between = balloon.size.width
// random
var movementAmount = arc4random() % UInt32(self.frame.size.height/2)
var treeoffset = CGFloat(movementAmount) - self.frame.size.height/4
// move tree
var treemove = SKAction.moveByX(0, y: -self.frame.size.width*2, duration: NSTimeInterval(self.frame.size.height/50))
var treeremove = SKAction.removeFromParent()
var treemoveandremove = SKAction.sequence([treemove, treeremove])
// add tree1
var tree1texture = SKTexture(imageNamed: "C2.png")
tree1 = SKSpriteNode(texture: tree1texture)
tree1.position = CGPointMake(CGRectGetMidX(self.frame) - tree1texture.size().width/2 - between + treeoffset, CGRectGetMidY(self.frame) + self.frame.size.height)
tree1.runAction(treemoveandremove)
tree1.physicsBody = SKPhysicsBody(rectangleOfSize: tree1.size)
tree1.physicsBody?.dynamic = false
self.addChild(tree1)
// add tree2
var tree2texture = SKTexture(imageNamed: "C1.png")
tree2 = SKSpriteNode(texture: tree2texture)
tree2.position = CGPointMake(CGRectGetMidX(self.frame) + tree2texture.size().width/2 + between + treeoffset, CGRectGetMidY(self.frame) + self.frame.size.height)
tree2.runAction(treemoveandremove)
tree2.physicsBody = SKPhysicsBody(rectangleOfSize: tree2.size)
tree2.physicsBody?.dynamic = false
[enter image description here][1]
self.addChild(tree2)
}

If I understood your question correctly, then you want to know why your "tree" is gone.
It appears that your MakeTree() method moves all the tree sprite nodes off the screen:
var treemove = SKAction.moveByX(0, y: -self.frame.size.width*2, duration: NSTimeInterval(self.frame.size.height/50))
Also, you shouldn't use NSTimers in SpriteKit. Use SKAction.waitForDuration instead. Like this:
let delay = SKAction.waitForDuration(3)
someNode.runAction(delay) {
//run code here after 3 seconds
}

Related

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.

Swift 3 Expect Argument Error

I am creating some functions in order to make a game similar to Flappy Bird. I am a complete beginner and am trying to understand everything fully as I go before moving on. I have been able to get my obstacle to move but when I attempt to put it into a function to allow me more flexibility later on with multiple obstacles I receive an error.
'Cannot convert type '()' to expected argument type 'SKAction'
class GameScene : SKScene, SKPhysicsContactDelegate {
var Player = SKSpriteNode()
var Ground = SKSpriteNode()
var Roof = SKSpriteNode()
var Background = SKSpriteNode()
let Obstacle1 = SKSpriteNode(imageNamed: "Fire Barrel 1")
override func didMove(to view: SKView) {
// Create Background Color
backgroundColor = bgColor
// Set World Gravity
self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.0)
// Create Player
Player = SKSpriteNode(imageNamed: "Player")
Player.setScale(0.5)
Player.position = CGPoint(x: -self.frame.width / 2 + 100, y: -Player.frame.height / 2)
self.addChild(Player)
// Create Ground
Ground = SKSpriteNode(imageNamed: "BGTileBtm")
Ground.anchorPoint = CGPoint(x: 0,y: 0.5)
Ground.position = CGPoint(x: -self.frame.width / 2, y: -self.frame.height / 2)
self.addChild(Ground)
// Create Roof
Roof = SKSpriteNode(imageNamed: "BGTileTop")
Roof.anchorPoint = CGPoint(x: 1,y: 1)
Roof.position = CGPoint(x: -self.frame.width / 2, y: self.frame.height / 2 - Roof.frame.height)
Roof.zRotation = CGFloat(M_PI)
self.addChild(Roof)
// Set Physics Rules
Player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Player"), size: Player.size)
Player.physicsBody!.affectedByGravity = true
Player.physicsBody!.allowsRotation = false
Ground.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ground"), size: Ground.size)
Ground.physicsBody!.affectedByGravity = false
Ground.physicsBody!.isDynamic = false
// Obstacle
func addObstacle1(){
Obstacle1.position = CGPoint(x: self.frame.width / 2, y: -self.frame.height / 2 + Obstacle1.frame.height)
Obstacle1.zPosition = 1
addChild(Obstacle1)
}
func moveObstacle1(){
let distance = CGVector(dx: -self.frame.width, dy: 0)
let moveDistance = SKAction.move(by: distance, duration: 5)
run(moveDistance)
}
addObstacle1()
Obstacle1.run(moveObstacle1())
}
Change the declaration of moveObstacle1 to this:
func moveObstacle1() -> SKAction{
let distance = CGVector(dx: -self.frame.width, dy: 0)
let moveDistance = SKAction.move(by: distance, duration: 5)
return moveDistance
}
EDIT:
Regarding your comment,
run is a method. When you call it, it runs the SKAction you passed in. That's it! What you are trying to do is run(moveObstacle1()). What does that mean exactly? How can you pass a method call as a parameter? At runtime, the return value of moveObstacle1() is passed to run. In other words, for run(moveObstacle1()) to compile, moveObstacle1() must return a value using the return statement. And that value must be of type SKAction, since that's the thing you're passing to run.
return is used to return a value from a moveObstacle1(), so that you can call run(moveObstacle1()).
run is just a regular old method.
Change:
Obstacle1.run()
To:
Obstacle1.run(SKAction(moveObstacle1()))
The error message is pretty clear, you need to pass a SKAction to your SKSpriteNode.
Edit
import SpriteKit
import GameplayKit
class GameScene : SKScene, SKPhysicsContactDelegate {
var Player = SKSpriteNode()
var Ground = SKSpriteNode()
var Roof = SKSpriteNode()
var Background = SKSpriteNode()
let Obstacle1 = SKSpriteNode(imageNamed: "Spaceship")
let sprite = SKSpriteNode(imageNamed:"Spaceship")
override func didMove(to view: SKView) {
// Create Background Color
backgroundColor = UIColor.green
// Set World Gravity
self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.0)
// Create Player
Player = SKSpriteNode(imageNamed: "Player")
Player.setScale(0.5)
Player.position = CGPoint(x: -self.frame.width / 2 + 100, y: -Player.frame.height / 2)
self.addChild(Player)
// Create Ground
Ground = SKSpriteNode(imageNamed: "BGTileBtm")
Ground.anchorPoint = CGPoint(x: 0,y: 0.5)
Ground.position = CGPoint(x: -self.frame.width / 2, y: -self.frame.height / 2)
self.addChild(Ground)
// Create Roof
Roof = SKSpriteNode(imageNamed: "BGTileTop")
Roof.anchorPoint = CGPoint(x: 1,y: 1)
Roof.position = CGPoint(x: -self.frame.width / 2, y: self.frame.height / 2 - Roof.frame.height)
Roof.zRotation = CGFloat(M_PI)
self.addChild(Roof)
// Set Physics Rules
Player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Player"), size: Player.size)
Player.physicsBody!.affectedByGravity = true
Player.physicsBody!.allowsRotation = false
Ground.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ground"), size: Ground.size)
Ground.physicsBody!.affectedByGravity = false
Ground.physicsBody!.isDynamic = false
sprite.size = CGSize(width:50, height: 50)
sprite.position = CGPoint(x:self.frame.midX, y:self.frame.midY);
self.addChild(sprite)
Obstacle1.run(SKAction(moveObstacle1()))
}
func moveObstacle1(){
let action = SKAction.moveTo(x: self.frame.size.width * 2, duration: 20)
sprite.run(action)
}
}

Swift 3 Repeat Spawning of SKNode

I have a SKNode that spawns and moves across the screen. It all works as intended. I am, however, unsure how to make this occur multiple times. My desire is for the 'barrels' to spawn every 2 seconds. You can see my attempt in the code below.
class GameScene : SKScene, SKPhysicsContactDelegate {
var Player = SKSpriteNode()
var Ground = SKSpriteNode()
var Roof = SKSpriteNode()
var Background = SKSpriteNode()
let Obstacle1 = SKSpriteNode(imageNamed: "Fire Barrel 1")
override func didMove(to view: SKView) {
// Create Background Color
backgroundColor = bgColor
// Set World Gravity
self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.0)
// Create Player
Player = SKSpriteNode(imageNamed: "Player")
Player.setScale(0.5)
Player.position = CGPoint(x: -self.frame.width / 2 + 100, y: -Player.frame.height / 2)
self.addChild(Player)
// Create Ground
Ground = SKSpriteNode(imageNamed: "BGTileBtm")
Ground.anchorPoint = CGPoint(x: 0,y: 0.5)
Ground.position = CGPoint(x: -self.frame.width / 2, y: -self.frame.height / 2)
self.addChild(Ground)
// Create Roof
Roof = SKSpriteNode(imageNamed: "BGTileTop")
Roof.anchorPoint = CGPoint(x: 1,y: 1)
Roof.position = CGPoint(x: -self.frame.width / 2, y: self.frame.height / 2 - Roof.frame.height)
Roof.zRotation = CGFloat(M_PI)
self.addChild(Roof)
// Set Physics Rules
Player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Player"), size: Player.size)
Player.physicsBody!.affectedByGravity = true
Player.physicsBody!.allowsRotation = false
Ground.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ground"), size: Ground.size)
Ground.physicsBody!.affectedByGravity = false
Ground.physicsBody!.isDynamic = false
// Obstacle
func addObstacle1(){
Obstacle1.position = CGPoint(x: self.frame.width / 2, y: -self.frame.height / 2 + Obstacle1.frame.height)
Obstacle1.zPosition = 1
addChild(Obstacle1)
let distance = CGVector(dx: -self.frame.width, dy: 0)
let moveDistance = SKAction.move(by: distance, duration: 5)
Obstacle1.run(moveDistance)
}
let spawnObstacles = SKAction(addObstacle1())
let delay = SKAction.wait(forDuration: 2)
let sequence = SKAction.sequence([delay, spawnObstacles])
run(SKAction.repeatForever(sequence))
}
Begin with putting the addObstacle outside of didMove method. Then put the following in your didMove method:
_ = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(addObstacle1), userInfo: nil, repeats: true)
It should repeat your addObstacle every two seconds :)

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

Error using waitforduration function

import SpriteKit
class GameScene: SKScene {
var greenBall = SKSpriteNode(imageNamed: "greenball")
var redBall = SKSpriteNode(imageNamed: "redball")
override func didMoveToView(view: SKView) {
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
backgroundColor = SKColor.purpleColor()
//
var bar0 = SKSpriteNode(imageNamed: "bar0")
var bar1 = SKSpriteNode(imageNamed: "bar1")
var bar2 = SKSpriteNode(imageNamed: "bar2")
var bar3 = SKSpriteNode(imageNamed: "bar3")
var bar4 = SKSpriteNode(imageNamed: "bar4")
var bar5 = SKSpriteNode(imageNamed: "bar5")
var bars = SKSpriteNode(imageNamed: "bar\(arc4random_uniform(6))")
var bartest = SKSpriteNode(imageNamed: "bar0")
bartest.position = CGPoint(x: frame.midX, y: frame.size.height * 0.633)
addChild(bartest)
var barra = SKShapeNode(rectOfSize: CGSize(width: frame.size.width, height: 10))
barra.name = "bar"
barra.fillColor = SKColor.whiteColor()
barra.position = CGPoint(x: frame.midX, y: frame.midY)
greenBall.position = CGPoint(x: frame.midX-100, y: frame.midY)
greenBall.yScale = 2
greenBall.xScale = 2
redBall.position = CGPoint(x: frame.midX+100, y: frame.midY)
redBall.yScale = 2
redBall.xScale = 2
self.addChild(redBall)
self.addChild(greenBall)
self.addChild(barra)
func makeBars() {
var randomTopOrBot = arc4random_uniform(2)
if randomTopOrBot == 0 {
var MaxY = frame.size.height * 0.951
var MinY = (frame.size.height * 0.633)-bars.size.height
var Range = CGFloat(MaxY - MinY)
var barsSpawnX = (frame.midX)
var barSpawnY = CGFloat(arc4random_uniform(UInt32(Range)))
bars.position = CGPoint(x: frame.midX, y: barSpawnY)
addChild(bars)
} else {
var MaxY = frame.size.height * 0.951
var MinY = (frame.size.height * 0.633)-bars.size.height
var Range = CGFloat(MaxY - MinY)
var barsSpawnX = (frame.midX)
var randomBetweenRange = CGFloat(arc4random_uniform(UInt32((Range))))
bars.position = CGPoint(x: frame.midX, y: (MinY+randomBetweenRange))
println(frame.size.height * 0.633)
addChild(bars)
}
}
let wait = SKAction.waitForDuration(3, withRange: 2)
let spawn = SKAction.runBlock { makeBars <--- this is where it's saying the problem is()
}
let sequence = SKAction.sequence([wait, spawn])
self.runAction(SKAction.repeatActionForever(sequence))
edit: So basically I've got 2 spawn locations I'm picking from, I randomly decide between the two with a random number, and now I'm wanting to apply the timer to the function makeBars, but it's telling me I can't reference the local function
This is giving me an error that says "cannot reference a local function with captures from another local function".
How can I fix this?
You declared your makerbars() method inside the didMoveToView method. So it was a function nesting problem after all, given the full code I was able to see the true issue.
Change your code to my modified and corrected version below:
import SpriteKit
class GameScene: SKScene {
var greenBall = SKSpriteNode(imageNamed: "greenball")
var redBall = SKSpriteNode(imageNamed: "redball")
override func didMoveToView(view: SKView) {
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
backgroundColor = SKColor.purpleColor()
//
var bar0 = SKSpriteNode(imageNamed: "bar0")
var bar1 = SKSpriteNode(imageNamed: "bar1")
var bar2 = SKSpriteNode(imageNamed: "bar2")
var bar3 = SKSpriteNode(imageNamed: "bar3")
var bar4 = SKSpriteNode(imageNamed: "bar4")
var bar5 = SKSpriteNode(imageNamed: "bar5")
var bartest = SKSpriteNode(imageNamed: "bar0")
bartest.position = CGPoint(x: frame.midX, y: frame.size.height * 0.633)
addChild(bartest)
var barra = SKShapeNode(rectOfSize: CGSize(width: frame.size.width, height: 10))
barra.name = "bar"
barra.fillColor = SKColor.whiteColor()
barra.position = CGPoint(x: frame.midX, y: frame.midY)
greenBall.position = CGPoint(x: frame.midX-100, y: frame.midY)
greenBall.yScale = 2
greenBall.xScale = 2
redBall.position = CGPoint(x: frame.midX+100, y: frame.midY)
redBall.yScale = 2
redBall.xScale = 2
self.addChild(redBall)
self.addChild(greenBall)
self.addChild(barra)
let wait = SKAction.waitForDuration(3, withRange: 2)
let spawn = SKAction.runBlock { self.makeBars() }
let sequence = SKAction.sequence([wait, spawn])
self.runAction(SKAction.repeatActionForever(sequence))
}
func makeBars() {
var bars = SKSpriteNode(imageNamed: "bar\(arc4random_uniform(6))")
var randomTopOrBot = arc4random_uniform(2)
if randomTopOrBot == 0 {
var MaxY = frame.size.height * 0.951
var MinY = (frame.size.height * 0.633)-bars.size.height
var Range = CGFloat(MaxY - MinY)
var barsSpawnX = (frame.midX)
var barSpawnY = CGFloat(arc4random_uniform(UInt32(Range)))
bars.position = CGPoint(x: frame.midX, y: barSpawnY)
addChild(bars)
} else {
var MaxY = frame.size.height * 0.951
var MinY = (frame.size.height * 0.633)-bars.size.height
var Range = CGFloat(MaxY - MinY)
var barsSpawnX = (frame.midX)
var randomBetweenRange = CGFloat(arc4random_uniform(UInt32((Range))))
bars.position = CGPoint(x: frame.midX, y: (MinY+randomBetweenRange))
println(frame.size.height * 0.633)
addChild(bars)
}
}
}