jlp28 jlp28 - 1 year ago 113
Swift Question

Change texture of individual nodes in didBeginContact

I've created a simple game where I have a match hover over candles (the odd description lends itself to my question) and the player scores a point when the match comes in contact with the wick. However, if it comes into contact with the anything else (like the 'wax' part of the candle), the game is over. The player controls the match by tapping on the screen.

My candle, being the wick and the coloured part, is created as follows (I have removed irrelevant parts, like the series of random textures):

func makeCandles() {

//Node properties and randomisation
let candle = SKNode()
let randomCandle = Int(arc4random_uniform(UInt32(candleTexture.count)))
let randomTexture = candleTexture[randomCandle] as SKTexture
let random = arc4random_uniform(17)
candle.position = CGPoint(x: self.frame.size.width, y: CGFloat(random * 12) - 120)

let chosenCandle = SKSpriteNode(texture: randomTexture)
chosenCandle.position = CGPoint(x: 0, y: self.frame.size.height / 2)
chosenCandle.physicsBody = SKPhysicsBody(rectangleOfSize: chosenCandle.size)
chosenCandle.physicsBody?.dynamic = false
chosenCandle.physicsBody?.categoryBitMask = self.candleCategory
chosenCandle.physicsBody?.contactTestBitMask = self.matchCategory
chosenCandle.physicsBody?.collisionBitMask = 0
chosenCandle.physicsBody?.restitution = 0

let wickArea = SKSpriteNode(texture: wickTexture)
wickArea.name = "wickNode"
wickArea.position = CGPoint(x: 0, y: self.frame.size.height / 1.3)
wickArea.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: wickArea.size.width / 4, height: wickArea.size.height))
wickArea.physicsBody?.dynamic = false
wickArea.physicsBody?.categoryBitMask = self.wickCategory
wickArea.physicsBody?.contactTestBitMask = self.matchCategory
wickArea.physicsBody?.collisionBitMask = 0
wickArea.zPosition = 11
wickArea.physicsBody?.restitution = 0

//Add the node and zPosition
chosenCandle.zPosition = 12

The candles are then created in a runBlock:

let createCandles = SKAction.runBlock({() in self.makeCandles()})
let briefPause = SKAction.waitForDuration(averageDelay, withRange: randomDelay)
let createAndPause = SKAction.sequence([createCandles, briefPause])
let createAndPauseForever = SKAction.repeatActionForever(createAndPause)

This is my function that changes the texture which is called in didBeginContact:

func updateFlame() {

if let newNode: SKNode = self.childNodeWithName("//wickNode") {
let updateTexture = SKAction.setTexture(flameTexture, resize: true)



This is my didBeginContact function:

func didBeginContact(contact: SKPhysicsContact) {

if contact.bodyA.categoryBitMask == wickCategory || contact.bodyB.categoryBitMask == wickCategory {
score += 1
scoreLabel.text = "\(score)"

} else {

My problem is that it only changes the first node to a flame, and doesn't change any others. Even if it is the second or third wick on which contact is detected, only the first created wick is changed (the first one that comes across the screen). I know that contact is being detected on each node and that that works fine, because the score updates every time the match comes into contact with a wick.

What am I doing wrong that is stopping the texture of each node that individually comes into contact with the match from changing? Everything else is working just fine, but this part has had me beat for a week and everything I've tried doesn't work. This is the closest I've gotten.

Answer Source

After much trial and error, I have finally figured out how to make each node change texture when contact occurs! This is my code for that part:

func didBeginContact(contact: SKPhysicsContact) {

    let collision : UInt32 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)

    if collision == (matchCategory | candleCategory | cakeCategory) {

    if (contact.bodyA.categoryBitMask == wickCategory) {
        let newWick = contact.bodyA.node
        let updateTexture = SKAction.setTexture(flameTexture, resize: true)

    } else if (contact.bodyB.categoryBitMask == wickCategory) {
        let newWick = contact.bodyB.node
        let updateTexture = SKAction.setTexture(flameTexture, resize: true)


I followed the logic of this question (even though I wanted to set the texture, not remove it) and it worked perfectly: removeFromParent() Doesn't Work in SpriteKit.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download