[Swift 2] Day 6 - Game Challenge #1 Solution + Demos


#21

What troubles you about the high score ?


#22

Thanks! I’m going to be uploading videos on how to do something similar to this (this week and next week).


#23

Are you still stuck?


#24

I am not :slight_smile: figured my problem, but now I am battling a EXC_BAD_ACCESS :frowning:
It happens on collision, but not all the time and it’s pissing me off :slight_smile: It can happen on the first time or on the 254-th collision…so yeah :slight_smile:


#25

Any insight into what’s going on?

What are you doing that could be failing?

Any error messages or lines of code?


#26

Nope, still can’t figure it out. Happens on contact, but only once in a while :confused:
Here is what I get:


#27

Just battling another issue, somehow if I add anything at contact.contactPoint now ( SKNode, SKSpriteNode ) it will appear at the bottom left corner, at 0,0
I check the coord of the contact point and they are good.
Tried adding these to different layers, still the same thing…
However if I add an Emitter, then it’s all good, goes where I need it to …


#28

post code for collisions stuff.


#29

Here is it, including the few extra functions that take part as well:

 //  CONTACT        CONTACT              CONTACT                     CONTACT 
    
    
    func didBeginContact(contact: SKPhysicsContact) {
        
        //        println("collision")
        
        if contact.bodyA.categoryBitMask == asteroidCategory && contact.bodyB.categoryBitMask == shipCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory && contact.bodyA.categoryBitMask == shipCategory {
                
                var asteroidBody: SKPhysicsBody!
                // do stuff
                if contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask {
                    
                    //body A is the Asteroid
                    asteroidBody = contact.bodyA
//                    asteroidBody.node?.removeFromParent()
                    
                    
                } else {
                    asteroidBody = contact.bodyB
//                    asteroidBody.node?.removeFromParent()
                }
                
                                                                    // HIT FUNCTION at BOTTOM
               hit()
                
        }
        
        if contact.bodyA.categoryBitMask == asteroidCategory2 && contact.bodyB.categoryBitMask == shipCategory && slowTrue == false ||
            contact.bodyB.categoryBitMask == asteroidCategory2 && contact.bodyA.categoryBitMask == shipCategory && slowTrue == false {
                
                var asteroidBody: SKPhysicsBody!
                let contactVector = contact.contactNormal
                let contactImpulse = contact.collisionImpulse
                //                playerShip.physicsBody?.applyImpulse(CGVector(dx: -contactVector.dx, dy: -contactVector.dy))
                
                // do stuff
                if contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask {
                    
                    //body A is the Asteroid
                    asteroidBody = contact.bodyA
//                    asteroidBody.node?.removeFromParent()
                    
                    
                } else {
                    //body B is the Asteroid
                    asteroidBody = contact.bodyB
//                    asteroidBody.node?.removeFromParent()
                }
                
                
//                playAudio("jump.wav", loops: 0)
                playerShipSpeed = 150
                
                
                slow = SKEmitterNode(fileNamed: "slow.sks")
                slow.position = CGPoint(x: 0, y: 0)
                slow.name = "slow"
                slow.zPosition = 1
                
                playerShip.addChild(slow)
                playerShipTop.color = SKColor(red: 0.2, green: 0.7, blue: 0.2, alpha: 1.0)
                playerShipTop.colorBlendFactor = 0.8
                slowTrue = true
                delay(3, { () -> () in
                    
                    self.playerShipSpeed = 500
                    self.slow.removeFromParent()
                    self.playerShipTop.colorBlendFactor = 0.2
                    self.slowTrue = false
                    
                })
                
                
                
                
        }
        
        if contact.bodyA.categoryBitMask == asteroidCategory3 && contact.bodyB.categoryBitMask == shipCategory && slowTime == false ||
            contact.bodyB.categoryBitMask == asteroidCategory3 && contact.bodyA.categoryBitMask == shipCategory && slowTime == false {
                
                
                var asteroidBody: SKPhysicsBody!
                let contactVector = contact.contactNormal
                let contactImpulse = contact.collisionImpulse
                //                playerShip.physicsBody?.applyImpulse(CGVector(dx: -contactVector.dx, dy: -contactVector.dy))
                
                // do stuff
                if contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask {
                    
                    //body A is the Asteroid
                    asteroidBody = contact.bodyA
//                    asteroidBody.node?.removeFromParent()
                    
                    
                } else {
                    asteroidBody = contact.bodyB
//                    asteroidBody.node?.removeFromParent()
                }
                
                
//                playAudio("jump.wav", loops: 0)
                physicsWorld.gravity = CGVectorMake(0.0, -(0.1))
                
                playerShipTop.color = SKColor(red: 0.2, green: 0.2, blue: 0.9, alpha: 1.0)
                playerShipTop.colorBlendFactor = 0.8
                slowTime = true
                
                
                delay(3, { () -> () in
                    
                    self.gravityVar = ((CGFloat(score) / 30) + 0.2)
                    self.physicsWorld.gravity = CGVectorMake(0.0, -(self.gravityVar))
                    self.playerShipTop.colorBlendFactor = 0.2
                    self.slowTime = false
                })
                
                
                
                
        }

        
        
        if contact.bodyA.categoryBitMask == asteroidCategory && contact.bodyB.categoryBitMask == rocketCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory && contact.bodyA.categoryBitMask == rocketCategory ||
            contact.bodyA.categoryBitMask == asteroidCategory2 && contact.bodyB.categoryBitMask == rocketCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory2 && contact.bodyA.categoryBitMask == rocketCategory ||
            contact.bodyA.categoryBitMask == asteroidCategory3 && contact.bodyB.categoryBitMask == rocketCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory3 && contact.bodyA.categoryBitMask == rocketCategory
            
        {
            
            explosion(contact.contactPoint)
            dropPosition = contact.contactPoint
            dropItem(dropPosition)
            scored()
            contact.bodyA.node?.removeFromParent()
            contact.bodyB.node?.removeFromParent()
            
            
            
            
        }
        
        if contact.bodyA.categoryBitMask == asteroidCategory && contact.bodyB.categoryBitMask == bulletCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory && contact.bodyA.categoryBitMask == bulletCategory ||
            contact.bodyA.categoryBitMask == asteroidCategory2 && contact.bodyB.categoryBitMask == bulletCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory2 && contact.bodyA.categoryBitMask == bulletCategory ||
            contact.bodyA.categoryBitMask == asteroidCategory3 && contact.bodyB.categoryBitMask == bulletCategory ||
            contact.bodyB.categoryBitMask == asteroidCategory3 && contact.bodyA.categoryBitMask == bulletCategory
            
        {
            println(contact.contactPoint)
            dropPosition = CGPoint(x: contact.contactPoint.x, y: contact.contactPoint.y)
            dropItem(dropPosition)
            let newItemBG = SKNode()
            let newItem = rocket()
            newItemBG.position = contact.contactPoint
            gameScene.addChild(newItemBG)
            newItemBG.addChild(newItem)
            scored()
            contact.bodyA.node?.removeFromParent()
            contact.bodyB.node?.removeFromParent()
            
            
            
            
        }
        
        if contact.bodyA.categoryBitMask == drop_bulletCategory && contact.bodyB.categoryBitMask == shipCategory ||
           contact.bodyB.categoryBitMask == drop_bulletCategory && contact.bodyA.categoryBitMask == shipCategory
        
        {
            
            if currentWeapon == 1 {
                
                if weaponLevel < 3 {
                            weaponLevel++
                            shoot()
                }
            } else {
                currentWeapon = 1
                weaponLevel = 1
                shoot()
                
                
            }
            
            
            
            
        }


        
        
        if  contact.bodyA.categoryBitMask == shipCategory && contact.bodyB.categoryBitMask == borderCategory ||
            contact.bodyB.categoryBitMask == borderCategory && contact.bodyA.categoryBitMask == shipCategory {
                
                println("border hit")
        }
        
    }
    
    func explosion(atPoint: CGPoint) {
        
        var explosion: SKEmitterNode!
        //generate emmitter
        explosion = SKEmitterNode(fileNamed: "explosion")
        explosion.position = atPoint
        explosion.name = "rocketFlare"
        explosion.xScale = 0.2
        explosion.yScale = 0.2
        explosion.zPosition = 8
        addChild(explosion)
        delay(0.3) {
            explosion.removeFromParent()
        }
        
    }


func hit() {
    
    
    playAudio("jump.wav", loops: 0)
    if !justHit {            // we haven't been hit
        hits++
        updateHealth()
        println("Current Hits: \(hits)")
        if hits <= 2 {
        }
        justHit = true   // now we have been hit
        playerShip.physicsBody?.categoryBitMask = noContactCategory
        playerShip.physicsBody?.collisionBitMask = borderCategory
        
        blink()
        delay(3, { () -> () in
            
            self.playerShipTop.removeActionForKey("blink")
            self.playerShip.physicsBody?.categoryBitMask = shipCategory
            self.playerShip.physicsBody?.collisionBitMask = asteroidCategory | borderCategory
            self.justHit = false
            
        })
        
        
        smoke.particleAlpha += 0.3
        smoke.particleAlphaRange += 0.3
        colorBlend == 0.8
        
        
        if hits >= 3 {
            //game over
            gameOver()
        }
    
    }
}

    func blink() {
        
        let colorAction = SKAction.colorizeWithColor(SKColor.redColor(), colorBlendFactor: 0.55, duration: 1)
        let colorAction2 = SKAction.colorizeWithColor(SKColor.whiteColor(), colorBlendFactor: 0.9, duration: 0.5)
        let fadeOut = SKAction.fadeAlphaTo(0.2, duration: 0.1)
        let fadeIn = SKAction.fadeAlphaTo(1, duration: 0.1)
        let colorActionSequence = SKAction.sequence([fadeIn, fadeOut, fadeIn])
        let colorAnimation = SKAction.repeatActionForever(colorActionSequence)
        playerShipTop.runAction(colorAnimation, withKey: "blink")
        
    }
    
    
    func removeObjectsOffScreen() {
        
        
        // any asteroids off the screen ?
        
        asteroidLayer.enumerateChildNodesWithName("asteroid", usingBlock: { asteroid, stop in
            
            if asteroid.position.y < 0 {
                
                asteroid.removeFromParent()
                //                                println("asteroid removed")
            }
        })
        
        asteroidLayer.enumerateChildNodesWithName("rocket", usingBlock: { rocket, stop in
            
            if rocket.position.y > (screenH) {
                
                rocket.removeFromParent()
                println("rocket removed")
            }
        })
        
        asteroidLayer.enumerateChildNodesWithName("bullet", usingBlock: { bullet, stop in
            
            if bullet.position.y > (screenH) {
                
                bullet.removeFromParent()
                println("bullet removed")
            }
        })
        

        
    }
    
    func dropItem(atPoint: CGPoint) {
        
        
        let randomNumber = randomIntBetweenNumbers(1, secondNum: 30)
        
        if randomNumber < 30 {
            
            let droppedItemT = drop_bullet()
            droppedItemT.position = atPoint
            addChild(droppedItemT)
            
        }
    
    }

#30

@PaulSolt , btw there is a lot of code that I added, while trying to troubleshoot that will be taken out :slight_smile:


#31

Actually, just email me your Xcode project in a .zip file.

If I can run it, I’ll be able to see what’s going on.

Might be a simple fix, might not… only a quick look will help.

PaulSolt@iPhoneDev.tv


#32

Thanks. I’ll do that later today. I actually added some nil checks and some optionals and that seemed to have reduced the problem, but it is still there :slight_smile: I almost thought it was gone, but appeared after like 5 min … :smiley:


#33

Read my message for 3 more suggestions to try.


#34

Next task on the way is converting all Asteroids into their own subclass. :smile:


#35

Yes, I think I recommend subclasses SKNode instead of SKSpriteNode so that you can create a complex object (particles, images, etc).


#36

Yeah, I started as SKSpriteNode, as it was easier transition, but will eventually convert to SKNode.
I actually converted some of my objects to a subclass of SKNode and a lot weird things started happening :smile:
Took me a while to figure it out, as you have to be careful of which child of the node has the contact and collision masks and what you remove upon contact, but I think I got it :smiley:


#37

So finally got some time to get back to this and I have to say converting the asteroids to their own class does miracles :wink: Including for their removal. Instead of having the contact delegate put them in an array for removal I have the remove themselves from within their superclass. It converted 30+ lines of code into 3 and on top of it improved the performance.


#38

Great work!

I need to show how to do that in the lessons. Sorry it’s been so slow – too many things I’m doing at once.

Working on a coffee app, which is part of the real world apps course. http://BrewCoffeeApp.com

Demo’ing it on May 2nd, so that has me booked until then.


#39

Ok, since it’s in the name of Coffee brewing it’s ok :smiley:


#40

Once I finish this project I’ll clean it all up and upload it all on GitHub.