2
votes

The code below is from a project I am currently working on, I have been trying to teach myself Swift language and Sprite Kit for the past few days and this is my first attempt at a game, it is a Flappy Bird type game. I ran into a problem today when I was trying to write the code for the collision detection. When the bird touches one of the pipes the game is supposed to pause. However when I run the code and the bird touches the pipe, nothing happens, the bird just bounces off of it. I have read many tutorials and watched many videos on this subject to try and resolve my problem and haven't had any luck. I have written all of the collision detection code that I learned off of the last video I watched in the code below. Could anyone please tell me what I am doing wrong. Any advice would be greatly appreciated, thank you.

//
//  GameScene.swift
//  Bird Flappy Game
//
//  Created by Brandon Ballard on 1/4/15.
//  Copyright (c) 2015 Brandon Ballard. All rights reserved.
//

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

    var bird = SKSpriteNode()
    var pipeUpTexture = SKTexture()
    var pipeDownTexture = SKTexture()
    var pipesMoveAndRemove = SKAction()

    let pipeGap = 150.0

    enum ColliderType:UInt32 {
        case BIRD = 1
        case PIPE = 2
    }

    override func didMoveToView(view: SKView) {
        /* Setup your scene here */


        backgroundColor = SKColor.cyanColor()

        //physics
        self.physicsWorld.gravity = CGVectorMake(0.0, -15.0);
        self.physicsWorld.contactDelegate = self

        func didBeginContact(contact: SKPhysicsContactDelegate) {
            scene?.view?.paused = true
            bird.setScale(12.0)
        }


        //Bird
        var birdTexture = SKTexture(imageNamed:"Bird")
        birdTexture.filteringMode = SKTextureFilteringMode.Nearest

        bird = SKSpriteNode(texture: birdTexture)
        bird.setScale(0.6)
        bird.position = CGPoint(x: 375, y: self.frame.size.height * 0.6)

        bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height / 2.0)
        bird.physicsBody?.dynamic = true
        bird.physicsBody?.allowsRotation = true
        bird.physicsBody?.affectedByGravity = true
        bird.physicsBody!.categoryBitMask = ColliderType.BIRD.rawValue
        bird.physicsBody!.contactTestBitMask = ColliderType.PIPE.rawValue
        bird.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue

        self.addChild(bird)

        //Ground
        var groundTexture = SKTexture(imageNamed: "Ground")

        var sprite = SKSpriteNode(texture: groundTexture)
        sprite.setScale(2.0)
        sprite.position = CGPointMake(self.size.width / 2, sprite.size.height / 2.0)


        self.addChild(sprite)

        var ground = SKNode()

        ground.position = CGPointMake(0, groundTexture.size().height + 0)
        ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width,     groundTexture.size().height * 2.0))

        ground.physicsBody?.dynamic = false
        self.addChild(ground)



        //Pipes

        //Create the Pipes

        pipeUpTexture = SKTexture(imageNamed: "PipeUp")
        pipeDownTexture = SKTexture(imageNamed: "PipeDown")

        //Movement of Pipes

        let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width)
        let movePipes = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
        let removePipes = SKAction.removeFromParent()

        pipesMoveAndRemove = SKAction.sequence([movePipes,removePipes])

        //Spawn Pipes

        let spawn = SKAction.runBlock({() in self.spawnPipes()})
        let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
        let spawnThenDelay = SKAction.sequence([spawn,delay])
        let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)

        self.runAction(spawnThenDelayForever)
    }

    func spawnPipes() {

        let pipePair = SKNode()
        pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0)
        pipePair.zPosition = -10

        let height = UInt32(self.frame.size.height / 4)
        let y = arc4random() % height + height

        var pipeDown = SKSpriteNode(texture: pipeDownTexture)
        pipeDown.setScale(2.0)////////
        pipeDown.position = CGPointMake(3.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap) )

        pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
        pipeDown.physicsBody?.dynamic = false
        pipeDown.physicsBody!.affectedByGravity = false
        pipeDown.physicsBody!.categoryBitMask = ColliderType.PIPE.rawValue
        pipeDown.physicsBody!.contactTestBitMask = ColliderType.BIRD.rawValue
        pipeDown.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
        pipePair.addChild(pipeDown)

        var pipeUp = SKSpriteNode(texture: pipeUpTexture)
        pipeUp.setScale(2.0)
        pipeUp.position = CGPointMake(0.0, CGFloat(y))

        pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size )
        pipeUp.physicsBody?.dynamic = false
        pipeUp.physicsBody!.affectedByGravity = false
        pipeUp.physicsBody!.categoryBitMask = ColliderType.PIPE.rawValue
        pipeUp.physicsBody!.contactTestBitMask = ColliderType.BIRD.rawValue
        pipeUp.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
        pipePair.addChild(pipeUp)

        pipePair.runAction(pipesMoveAndRemove)
        self.addChild(pipePair)

    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        /* Called when a touch begins */

        for touch: AnyObject in touches {



            let location = touch.locationInNode(self)

            bird.physicsBody?.velocity = CGVectorMake( 0, 0 )
            bird.physicsBody?.applyImpulse(CGVectorMake(0,25))



        }
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
}
2
When you run your game, does the bird collide with the pipes onscreen ?Trevör
Yes, the bird collides and bounces offBCRwar1
If you add a println to the didBeginContact, nothing appears in the console ?Trevör
I have tried println to the didBeginContact, that was a suggestion in a video I watched, however nothing appeared in the console when the bird touched the pipeBCRwar1
I don't see at all what's wrong with your code (but maybe I'm not experimented enough with SpriteKit), could you add a println(self.physicsWorld.contactDelegate) to the update function to see what comes out in the console ?Trevör

2 Answers

3
votes

From what I can see, you only need to DETECT collisions, not actually simulate them. For this, you need to set only the contactTestBitMask of the physicsBodies. You can set the collisionBitMask as 0.

bird.physicsBody!.collisionBitMask = 0

pipe.physicsBody!.collisionBitMask = 0

Also, as hamobi has already said, the didBeginContact method needs to be outside the didMoveToView method with the override keyword. (This question has the exact same problem as yours)

class GameScene: SKScene, SKPhysicsContactDelegate {
    // ...
    override func didMoveToView(view: SKView) {
        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)

        // set as delegate:
        self.physicsWorld.contactDelegate = self

        // ..
    }

    // should be called now
    func didBeginContact(contact: SKPhysicsContact){
        scene?.view?.paused = true
            bird.setScale(12.0)
    }
}
2
votes

You put your didBeginContact INSIDE of didMoveToView. It's not callable from there. Put it in the body of your class