Keep in mind this is in Sprite Kit. Basically I want a way to have my in-game upgrades on a timer that allows the user to get the upgrade after the timer has finished. The user would touch the button once to start the timer, and once it gets to zero, it stops itself. I can't get it to stop, however.
import Foundation
import SpriteKit
var timer1Cycle = 0
var timer1Time = 10000
var timer1 = Timer()
var timer1IsOn = false
class SkillPointsScene: SKScene{
func updateTimer1() {
timer1Time -= 1
timer1Label.text = " \(timer1Time) :Kepler-22b units"
}
func startTimer1(){
if timer1IsOn == false {
timer1 = Timer.scheduledTimer(timeInterval: 0.0004, target: self, selector: #selector(SkillPointsScene.updateTimer1), userInfo: nil, repeats: true)
timer1IsOn = true
}
}
func stopTimer1() {
timer1.invalidate()
timer1Time = 0
timer1Label.text = "Research Complete"
timer1IsOn = false
}
Here is the image button to start counting down from 10000:
let oneLifeImage = SKSpriteNode(imageNamed: "gun1")
let timer1Label = SKLabelNode(fontNamed: "theBoldFontt")
// runs as soon as the screen loads every time
override func didMove(to view: SKView) {
if timer1Time <= 0 {
self.stopTimer1()
}
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
timer1Label.text = " "
timer1Label.fontSize = 35
timer1Label.fontColor = SKColor.white
timer1Label.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.82)
timer1Label.zPosition = 100
self.addChild(timer1Label)
oneLifeImage.setScale(1)
oneLifeImage.position = CGPoint(x: self.size.width/2, y: self.size.height*0.75)
oneLifeImage.zPosition = 2
self.addChild(oneLifeImage)
And here is where the button is touched:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let wait = SKAction.wait(forDuration: 1.5)
if oneLifeImage.contains(pointOfTouch){
if timer1Cycle == 0 {
timer1Time = 10000
}
if timer1Cycle == 1 {
timer1Time = 25000
}
if timer1IsOn == false {
startTimer1()
timer1Cycle -= 1
}
I get it to start the count down, but it never stops on its own. I don't know what to do now; I can't find any information on this because it is in Swift 3 with Sprite Kit, not the normal single view that everybody seems to know how to use.
Related
I have a SpriteKit game and I am using a SKAction to move my meteor (the meteors are the enemies) all the way to the end of the screen where the player (the player is at the bottom of the screen, and they can only move on the x-axis to dodge meteors not the y) must dodge these meteors. Right I'm only trying to get one meteor on the screen at a time which moves towards the direction of the player using SKAction. There should only be on meteor at a time on the screen, but I get the error 'Attempted to add a SKNode which already has a parent'. My SKAction adds the meteor to the screen but then deletes it after the meteor has moved to its destination which is all then way to the bottom of the screen. So why am I getting this error and how can I fix it?
NOTE: The SKAction removes the meteor from the screen by using meteor.removeFromParent()
Here is my code:
import SpriteKit
import GameplayKit
import UIKit
class GameScene: SKScene, SKPhysicsContactDelegate{
let player = SKSpriteNode(imageNamed: "spaceship")
let stars = SKSpriteNode(imageNamed: "stars")
let meteor = SKSpriteNode(imageNamed: "meteor")
var scoreLabel = SKLabelNode(fontNamed: "AmericanTypewriter-Bold")
var score:Int = 0
var playerLost:Bool = false
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
print(frame.size.width)
print(frame.size.height)
stars.position = CGPoint(x:0, y:0)
stars.zPosition = 1
player.position = CGPoint(x:0, y:-320)
player.zPosition = 4
player.physicsBody = SKPhysicsBody(texture: player.texture!, size: player.size)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.isDynamic = false
player.physicsBody?.categoryBitMask = 2
player.physicsBody?.collisionBitMask = 2
player.physicsBody?.contactTestBitMask = 1
self.addChild(player)
self.addChild(stars)
self.addMeteor()
self.setLabel()
//spawnEnemySKAction()
}
func spawnEnemySKAction() {
let spawn = SKAction.run(addMeteor)
let waitToSpawn = SKAction.wait(forDuration: 1)
let spawnSequence = SKAction.sequence([spawn, waitToSpawn])
let spawnForever = SKAction.repeatForever(spawnSequence)
self.run(spawnForever)
}
func didBegin(_ contact: SKPhysicsContact) {
gameOver()
}
func addMeteor() {
meteor.physicsBody = SKPhysicsBody(texture: meteor.texture!, size: meteor.size)
meteor.physicsBody?.affectedByGravity = false
meteor.setScale(0.50)
meteor.position = CGPoint(x:Int(arc4random()%300),y:Int(arc4random()%600))
//meteor.position = CGPoint(x:0 , y:0)
meteor.zPosition = 4
let moveMeteor = SKAction.moveTo(y: player.position.y - 300, duration: 1.5)
let deleteMeteor = SKAction.removeFromParent()
let meteorSequence = SKAction.sequence([moveMeteor, deleteMeteor])
meteor.run(meteorSequence)
meteor.physicsBody?.categoryBitMask = 1
meteor.physicsBody?.collisionBitMask = 2
meteor.physicsBody?.contactTestBitMask = 2
self.addChild(meteor)
}
func fireBullet() {
let bullet = SKSpriteNode(imageNamed: "bullet")
bullet.position = player.position
bullet.setScale(0.5)
bullet.zPosition = 3
self.addChild(bullet)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet.run(bulletSequence)
}
func setLabel() {
scoreLabel.text = "Score: " + String(score)
scoreLabel.position = CGPoint(x: 290, y: 590)
scoreLabel.zPosition = 20
}
func gameOver() {
playerLost = true
var gameOverLabel: SKLabelNode!
gameOverLabel = SKLabelNode(fontNamed: "AmericanTypewriter-Bold")
gameOverLabel.text = "Game Over! You lost! Your score was: " + String(score)
gameOverLabel.zPosition = 10
gameOverLabel.position = CGPoint(x: 0, y:0)
self.addChild(gameOverLabel)
player.removeFromParent()
meteor.removeFromParent()
stars.removeFromParent()
scoreLabel.removeFromParent()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if playerLost == false {
fireBullet()
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in: self)
let previousPointOfTouch = touch.previousLocation(in: self)
let amountDragged = pointOfTouch.x - previousPointOfTouch.x
player.position.x += amountDragged
}
}
override func update(_ currentTime: TimeInterval) {
addMeteor()
if meteor.position.y < player.position.y - 300 && playerLost == false {
meteor.removeFromParent()
addMeteor()
if playerLost == false {
score += 1
}
scoreLabel.removeFromParent()
scoreLabel.text = "Score: " + String(score)
self.addChild(scoreLabel)
}
}
}
Thanks for taking the time to look at this question!
I simply had to remove the self.addChild(meteor) in the update function
I'm working on a game project with Xcode.
I've written the code that makes the ship shoot the projectiles, but I don't know what function to use to make the ship shoot automatically.
Could you help me? Thank you in advance!
Here's my code, from the GameScene :
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let projectile = SKSpriteNode(imageNamed: "projectile")
projectile.zPosition = 1
projectile.position = CGPoint(x: player.position.x, y: player.position.y)
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody?.isDynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.None
projectile.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(projectile)
let action = SKAction.moveTo(x: self.frame.width + projectile.size.width, duration: 0.5)
projectile.run(action, completion: {
projectile.removeAllActions()
projectile.removeFromParent()
})
}
Based on a comment by Jake I am assuming that you want the ship to fire "automatically" not repeating while holding the finger down.
You can use the update func to control the automatic shooting. in my example the update command fires every 1 second
private var updateTime: Double = 0
override func update(_ currentTime: TimeInterval) {
if updateTime == 0 {
updateTime = currentTime
}
if currentTime - updateTime > 1 {
self.shoot()
updateTime = currentTime
}
}
func shoot() {
let projectile = SKSpriteNode(imageNamed: "projectile")
projectile.zPosition = 1
projectile.position = CGPoint(x: player.position.x, y: player.position.y)
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody?.isDynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.None
projectile.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(projectile)
let action = SKAction.moveTo(x: self.frame.width + projectile.size.width, duration: 0.5)
projectile.run(action, completion: {
projectile.removeAllActions()
projectile.removeFromParent()
})
}
I followed many different tutorials on collision and created my own game where i want to declare a collision between a coin and a player. However, after implementing the collision code my two nodes are not responding to the collision...can someone help me out please?
import SpriteKit
import GameplayKit
// Collision categories
enum ColliderType: UInt32 {
case playerCase = 1
case coinCase = 2
case borderCase = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
let player = SKSpriteNode(imageNamed:"block")
let buttonDirLeft = SKSpriteNode(imageNamed: "left")
let buttonDirRight = SKSpriteNode(imageNamed: "right")
let coins = SKSpriteNode(imageNamed: "coins")
let background = SKSpriteNode(imageNamed: "background")
var pressedButtons = [SKSpriteNode]()
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
//score label
let points = SKLabelNode(text: "0")
points.position = CGPoint(x: 530, y: 260)
points.zPosition = 6
points.fontColor = UIColor.black
points.fontSize = 50
addChild(points)
//Set Background
background.zPosition = 1
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
background.size.width = 580
background.size.height = 320
addChild(background)
// Player
player.position = CGPoint(x: 250, y: 40)
player.zPosition = 2
player.texture?.filteringMode = .nearest
// player!.collisionBitMask = 0 //
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.height / 2.0)
player.physicsBody?.isDynamic = false
player.physicsBody?.allowsRotation = false
player.physicsBody?.affectedByGravity = false
player.physicsBody!.categoryBitMask = ColliderType.playerCase.rawValue
player.physicsBody!.contactTestBitMask = ColliderType.coinCase.rawValue
player.physicsBody!.collisionBitMask = ColliderType.coinCase.rawValue
self.addChild(player)
// button left
buttonDirLeft.position = CGPoint(x: 30, y: 35)
buttonDirLeft.zPosition = 4
buttonDirLeft.size.width = 270
buttonDirLeft.size.height = 320
buttonDirLeft.alpha = 0.0
self.addChild(buttonDirLeft)
// button right
buttonDirRight.position = CGPoint(x: 530, y: 35)
buttonDirRight.zPosition = 4
buttonDirRight.size.width = 270
buttonDirRight.size.height = 320
buttonDirRight.alpha = 0.0
self.addChild(buttonDirRight)
// setting border around game
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
//ENEMY SETTINGS START
//repeat coing spawning
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(spawnCoins),
SKAction.wait(forDuration: 1.0)])))
}
//coin settings
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
//spawn coins
func spawnCoins() {
// 2
let coins = SKSpriteNode(imageNamed: "coins")
coins.zPosition = 2
coins.size.width = 40
coins.size.height = 40
let action = SKAction.moveTo(y: -350, duration: TimeInterval(random(min: 1, max: 5)))
let remove = SKAction.run({coins.removeFromParent(); print("coins removed from scene")})
let sequence = SKAction.sequence([action,remove])
coins.physicsBody = SKPhysicsBody(rectangleOf: coins.size )
coins.physicsBody?.isDynamic = false
coins.physicsBody!.affectedByGravity = false
coins.physicsBody!.categoryBitMask = ColliderType.coinCase.rawValue
coins.physicsBody!.contactTestBitMask = ColliderType.playerCase.rawValue
coins.physicsBody!.collisionBitMask = ColliderType.playerCase.rawValue
coins.run(sequence)
coins.size.width = 20
coins.size.height = 20
coins.name = "coins"
// coins.physicsBody!.collisionBitMask = 0
coins.position = CGPoint(x: frame.size.width * random(min: 0, max: 1), y: frame.size.height + coins.size.height/2)
addChild(coins)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
/* Called before each frame is rendered */
if pressedButtons.index(of: buttonDirLeft) != nil {
player.position.x -= 3.0
}
if pressedButtons.index(of: buttonDirRight) != nil {
player.position.x += 3.0
}
// Update entities
}
//MOVEMENT FUNCTIONS START HERE
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// I check if they are already registered in the list
if button.contains(location) && pressedButtons.index(of: button) == nil {
pressedButtons.append(button)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// if I get off the button where my finger was before
if button.contains(previousLocation)
&& !button.contains(location) {
// I remove it from the list
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
// if I get on the button where I wasn't previously
else if !button.contains(previousLocation)
&& button.contains(location)
&& pressedButtons.index(of: button) == nil {
// I add it to the list
pressedButtons.append(button)
}}}}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
func didBeginContact(contact: SKPhysicsContact){
print("colliding!")
}
Contact will happen only if at least one body is dynamic. So either set your player or coin to be dynamic and if everything else is set correctly (if categories are set properly and didBeginContact method implementation is correct) your bodies will now collide / make contacts. If you are interested only in contacts, set collision bit mask to 0.
So I've got a class named FlashyPaddleEffect. I also mention it in another class, GameScene, but it doesn't apply any effect that it should. The paddle should be flashing blue and white colors, but it simply stays white. The paddle also should lose its physics body when it is blue.
If you need any other information, don't hesitate to ask.
NOTE: There might be problems with the code I gave (because of indents, it's quite tricky to make code by indenting 4 spaces every line, sorry).
import SpriteKit
import GameplayKit
class FlashyPaddleEffect {
var node = SKSpriteNode()
var ballNode = SKSpriteNode()
var updateTimer: Timer? = nil
var timer: Timer? = nil
#objc func changeNodeColor() {
switch node.color {
case SKColor.blue: node.color = SKColor.white
case SKColor.white: node.color = SKColor.blue
default: _ = 1 + 2
}
}
#objc func update() //I used the objc prefix to silence the warning the selectors of the timers produced. {
let previousPhysicsBody = node.physicsBody
if node.color == SKColor.blue {
node.physicsBody = nil
}
node.physicsBody = previousPhysicsBody
}
func make(applyEffectTo: SKSpriteNode, ball: SKSpriteNode) {
node = applyEffectTo
ballNode = ball
timer = Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(changeNodeColor), userInfo: nil, repeats: true)
updateTimer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(update), userInfo: nil, repeats: true)
_ = node
_ = timer
}
}
class GameScene: SKScene {
var ball = SKSpriteNode()
var player = SKSpriteNode()
var enemy = SKSpriteNode()
var scores = [0, 0]
var initScores = [0, 0]
var scoreLabels: [SKLabelNode]? = nil
let playLabel = SKLabelNode()
let timeLabel = SKLabelNode()
let timeUpLabel = SKLabelNode()
var secondsLeft: Int = 180
var initialTime: Int? = nil
var timer = Timer()
var amountOfPauseMenuCloses = 0
var resultsLabel = SKLabelNode()
let flashEffect = FlashyPaddleEffect() //I define a variable to mention the class easier later on.
override func didMove(to view: SKView) {
//Initialize nodes of the scene editor.
ball = self.childNode(withName: "Ball") as! SKSpriteNode
player = self.childNode(withName: "PPaddle") as! SKSpriteNode
enemy = self.childNode(withName: "EPaddle") as! SKSpriteNode
//Set styles for the Play Notification Label (referred to as PNL later)
playLabel.position = CGPoint(x: 0, y: 0)
playLabel.text = "Tap anywhere to play."
playLabel.name = "playLabel"
//Set styles for the Timer Label (referred to as Timer later)
timeLabel.position = CGPoint(x: 90, y: 0)
timeLabel.text = String(secondsLeft)
//Doing manipulations connected with scores here.
scores = [0, 0]
initScores = scores
scoreLabels = [self.childNode(withName: "PScoreLabel") as! SKLabelNode, self.childNode(withName: "EScoreLabel") as! SKLabelNode]
//Create a border for our ball to bounce off.
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
border.linearDamping = 0
border.angularDamping = 0
self.physicsBody = border
//To avoid the ball's damping.
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.angularDamping = 0
showPause() //Show the (pause) menu at the beginning
//Set a variable to refer to as a time standard later.
initialTime = secondsLeft
//The game timer.
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(reduceSecondFromTimer), userInfo: nil, repeats: true)
flashEffect.make(applyEffectTo: player, ball: ball) //This is where I reference the class in another class.
}
//A function to show the (pause) menu.
func showPause(hideNodes: Bool = true) {
self.addChild(playLabel)
if hideNodes == true {
ball.removeFromParent()
player.removeFromParent()
enemy.removeFromParent()
scoreLabels?[0].removeFromParent()
scoreLabels?[1].removeFromParent()
}
}
override func update(_ currentTime: TimeInterval) {
var alreadyChangedTextLabel = false
for i in scoreLabels! {
if i.name == "PScoreLabel" {i.text = String(scores[0])}
if i.name == "EScoreLabel" {i.text = String(scores[1])}
}
if ball.position.y <= player.position.y {scores[1] += 1}
if ball.position.y >= enemy.position.y {scores[0] += 1}
if secondsLeft == 0 {
showPause(hideNodes: false)
if alreadyChangedTextLabel == false {
timeUpLabel.text = "TIME UP! \(whoIsWinning(scores: scores)) won!"
alreadyChangedTextLabel = true
}
timeUpLabel.name = "timeUpLabel"
timeUpLabel.position = CGPoint(x: 0, y: 180)
if !(self.children.contains(timeUpLabel)) {
self.addChild(timeUpLabel)
}
timeLabel.removeFromParent()
}
if self.children.contains(playLabel) {
secondsLeft = initialTime!
}
timeLabel.text = String(secondsLeft)
let alignWithBall = SKAction.move(to: CGPoint(x: ball.position.x, y: enemy.position.y), duration: 0.8)
enemy.run(alignWithBall)
}
func initGame() {
//Initializing process for every game.
scores = initScores
ball.position = CGPoint(x: 0, y: 0)
if amountOfPauseMenuCloses == 1 {ball.physicsBody?.applyImpulse(CGVector(dx: 15, dy: 15))}
secondsLeft = initialTime!
timeLabel.text = String(secondsLeft)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for childNode in self.children {
if childNode.name == "playLabel" {
if self.children.contains(playLabel) {
playLabel.removeFromParent()
}
if !(self.children.contains(player)) {
self.addChild(player)
}
if !(self.children.contains(enemy)) {
self.addChild(enemy)
}
if !(self.children.contains(ball)) {
self.addChild(ball)
}
if !(self.children.contains((scoreLabels?[0])!)) {
self.addChild((scoreLabels?[0])!)
}
if !(self.children.contains((scoreLabels?[1])!)) {
self.addChild((scoreLabels?[1])!)
}
if !(self.children.contains(timeLabel)) {
self.addChild(timeLabel)
}
if self.children.contains(timeUpLabel) {
timeUpLabel.removeFromParent()
}
amountOfPauseMenuCloses += 1
initGame()
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
if self.nodes(at: t.location(in: self)).contains(player) {player.position.x = t.location(in: self).x}
}
}
func reduceSecondFromTimer() {
secondsLeft -= 1
}
func whoIsWinning(scores: Array<Int>) -> String {
var r: String? = nil
if scores[0] >= scores[1] {
r = "You"
}
if scores[1] >= scores[0] {
r = "Enemy"
}
return r!
}
}
Thanks a lot for answers.
P.S It's my first question ever so don't judge me strictly.
1) Do not use NSTimer use SKAction. I can see the way you are doing it you stack timer after timer, this is bad.
2) Do not have your temp variable global (node in this case), it makes code hard to read
3) Do not remove your physics body, simply remove the category.
func make(applyEffectTo: SKSpriteNode, ball: SKSpriteNode) {
ballNode = ball
let blue = SKAction.colorize(with SKColor.blue, colorBlendFactor: 1.0, duration sec: 0)
let white = SKAction.colorize(with SKColor.white, colorBlendFactor: 1.0, duration sec: 0)
let wait = SKAction.wait(for:0.6)
let turnOnPhysics = SKAction.run({applyEffectTo.physicsBody?.categoryBitmask = #######})
let turnOffPhysics = SKAction.run({applyEffectTo.physicsBody?.categoryBitmask = 0})
let seq = [blue, turnOffPhysics,wait,white,turnOnPhysics,wait]
let repeat = SKAction.repeatForever(seq)
applyEffectTo.run(repeat, withKey:"flashing")
}
Note: I have no idea what your categoryBitmask is, you need to fill it in
I know why I'm getting that error, but I can't figure out a way around it. I'm trying to have objects come appear and then be removed and the player should try to tap them before they're removed, but everytime the next node is about to appear it crashes. If i declare it inside its func then it all comes out but I can't tap on it...
Code:
let step = SKSpriteNode()
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
backgroundColor = UIColor.feelFreeToColor()
self.color = self.randomNumbersInt(3)
self.showBars()
self.showScore()
let spawn = SKAction.runBlock {
//self.color = self.randomNumbersInt(3)
self.showSteps()
}
let delay = SKAction.waitForDuration(1.5)
let spawnDelay = SKAction.sequence([spawn , delay])
let spawnDelayForever = SKAction.repeatActionForever(spawnDelay)
self.runAction(spawnDelayForever)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
var location = touch.locationInNode(self)
if self.nodeAtPoint(location) == step {
self.score += 1
}
}
}
func showSteps() {
let createSteps = SKAction.moveByX(0, y: -self.frame.height - 30 , duration: 10)
let removeSteps = SKAction.removeFromParent()
step.color = colors[randomNumbersInt(3)]!
step.size = CGSize(width: 275, height: 30)
step.position = CGPoint(x: self.frame.width * 0.5, y: self.frame.height * 0.75)
step.physicsBody = SKPhysicsBody(rectangleOfSize: step.size)
step.physicsBody?.categoryBitMask = Config.PhysicBodyType.Steps.rawValue
step.physicsBody?.affectedByGravity = false
step.physicsBody?.dynamic = false
step.zPosition = 1
step.runAction(SKAction.repeatActionForever(SKAction.sequence([createSteps, removeSteps])))
addChild(step)
}
In your showSteps function, declare the step node inside it, not at the top of your code, and also give it a name:
func showSteps() {
let step = SKSpriteNode()
...
step.name = "step"
step.color = colors[randomNumbersInt(3)]!
// etc
}
In your touchesBegan method, you have this if statement:
if self.nodeAtPoint(location) == step {
self.score += 1
}
You want to remove that node that you have hit, but now you can just check the name property like so:
if self.nodeAtPoint(location)?.name == "step" {
self.nodeAtPoint(location)?.removeFromParent()
self.score += 1
}
Please note that I am not super fluent in Swift, but I think you will probably need the ? in your if statement, as it might not exist (such as if you didn't tap on a specific node). Somebody more familiar with Swift is free to correct me.