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.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
Andrew
  • 1
  • 1
  • 6
    Please reduce your code to the bare essentials to reproduce your problem. Currently, there's a lot of code to parse through, obscuring whatever's causing the problem. –  Nov 13 '16 at 08:10
  • "it's quite tricky to make code by indenting 4 spaces every line."? You can configure XCode to do that properly. If you mean indenting 4 spaces here on StackOverflow: copy-paste your code, then select all the code in the question box, then click the "code" format icon {} and everything's indented by 4 extra spaces and turns into a code block. –  Nov 13 '16 at 08:12
  • As Evert said, it's very hard for people who wants to help to find where the actual problem is. Try to reproduce the problem with the least amount of code necessary and use that as an example (most of the time you'll be able to fix it by yourself by then). – Eendje Nov 13 '16 at 09:55

1 Answers1

1

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

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44