Search code examples
swiftsprite-kittouchsknode

How to add 1 point every time SKNode is touched


I created a game involving falling balls. Every time the player taps a ball, they're supposed to get a point. I set up the score label, but it just stays at 0.

Is there something wrong with my code?

I use a GameElements.swift file as an extension. Here is the file:

extension GameScene {
    //1st Ball//
    func createPlayer() -> SKNode {
        
        let playerNode = SKNode()
        playerNode.position = CGPoint(x:self.size.width / 2, y:440)
        
        let sprite = SKSpriteNode(imageNamed: "Ball")
        sprite.name = "ballPoints"
        playerNode.addChild(sprite)
        
        playerNode.physicsBody = SKPhysicsBody(circleOfRadius: 120)
        
        playerNode.physicsBody?.dynamic = true
        playerNode.physicsBody?.allowsRotation = false
        
        playerNode.physicsBody?.restitution = 3
        playerNode.physicsBody?.friction = 0
        playerNode.physicsBody?.angularDamping = 0
        playerNode.physicsBody?.linearDamping = 0
        
        playerNode.physicsBody?.usesPreciseCollisionDetection = true
        
        
        playerNode.physicsBody?.categoryBitMask = CollisionBitMask.Player
        
        playerNode.physicsBody?.categoryBitMask = 0
        
        return playerNode
    }
}

Here is the GameScene.swift file:

class GameScene: SKScene {
    
    var foreground: SKNode!
    var hud: SKNode!
    var firstBall: SKNode!
    
    var scoreLabel: SKLabelNode!
    
    private var score = 0
    override func didMoveToView(view: SKView) {
        
        
        scoreLabel = SKLabelNode(fontNamed:"Geared-Slab")
        scoreLabel.fontColor = UIColor.blackColor()
        scoreLabel.position = CGPoint( x: self.frame.midX, y: 3 * self.frame.size.height / 4 )
        scoreLabel.fontSize = 100.0
        scoreLabel.zPosition = 100
        scoreLabel.text = String(score)
        self.addChild(scoreLabel)
    }
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)
            if(firstBall.containsPoint(location)) {
                firstBall.physicsBody?.velocity = CGVectorMake(0, 600)
                firstBall.physicsBody?.applyImpulse(CGVectorMake(0, 1100))
                
                
            }
            if
                let touch : UITouch! = touches.first,
                let tappedSprite = nodeAtPoint(touch!.locationInNode(self)) as? SKSpriteNode,
                let scoreLabel = childNodeWithName("scoreLabel") as? SKLabelNode
                where tappedSprite.name == "ballPoints" {
                score += 1
                scoreLabel.text = "Score: \(score)"
            }
        }
    }
    
    override init(size:CGSize) {
        super.init(size: size)
        
        foreground = SKNode()
        addChild(foreground)
        
        
        //1st Ball//
        firstBall = createPlayer()
        foreground.addChild(firstBall)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

I know this is a lot of code, but I want experts to be able to test the code themselves. For background, I was following this tutorial: https://www.youtube.com/watch?v=0gOi_2Jwt28 up until a certain point.

enter image description here


Solution

  • Step 1

    First of all let's create a class for the Ball

    class Ball: SKSpriteNode {
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            let scene = self.scene as! GameScene
            scene.score += 1
        }
    }
    

    Step 2

    Then inside createPlayer() let's replace this

    let sprite = SKSpriteNode(imageNamed: "Ball")
    

    with this

    let sprite = Ball(imageNamed: "Ball")
    sprite.userInteractionEnabled = true
    

    Step 3

    Let's remove the touchesBegan from GameScene.

    Update

    This code is working as expected for me

    class GameScene: SKScene {
    
        var scoreLabel: SKLabelNode!
        var ball: Ball!
        private var score = 0 {
            didSet {
                scoreLabel.text = "\(score)"
                print(score)
    
            }
        }
    
        override func didMoveToView(view: SKView) {
            let ball = Ball()
            ball.position = CGPoint(x:frame.midX, y: frame.midY)
            addChild(ball)
        }
    
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            // this is called when you tap outside of the Ball
            // use self.ball to make the ball to jump
        }
    }
    
    class Ball: SKSpriteNode {
    
        init() {
            let texture = SKTexture(imageNamed: "ball")
            super.init(texture: texture, color: .clearColor(), size: texture.size())
            userInteractionEnabled = true
        }
    
    
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            let scene = self.scene as! GameScene
            scene.score += 1
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    

    enter image description here