0

I want to override collisions in SpriteKit.

The idea is that I have a ball which bounces around the scene. When didBeginContact detects contact between an edge and the ball, I want the ball to rebound in a random direction and speed.

import SpriteKit


class GameScene: SKScene, SKPhysicsContactDelegate {

let kEdgeCollisionCategory:UInt32 = 0x1 << 1
let kSquareCollisionCategory:UInt32 = 0x1 << 2

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

    // Physics world
    self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
    self.physicsWorld.contactDelegate = self       

    // Edge
    let frameEdges = SKNode()
    frameEdges.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
    frameEdges.physicsBody?.categoryBitMask = kEdgeCollisionCategory
    self.addChild(frameEdges)

// Sprite
    var sprite = SKSpriteNode(imageNamed: "blue")
    sprite.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(sprite.size.width, sprite.size.height))
    sprite.physicsBody?.restitution = 1.0
    sprite.physicsBody?.linearDamping = 0.0
    sprite.physicsBody?.angularDamping = 0.0
    sprite.physicsBody?.friction = 0.0
    sprite.physicsBody?.dynamic = true
    sprite.physicsBody?.categoryBitMask = kSquareCollisionCategory
    sprite.physicsBody?.collisionBitMask = kEdgeCollisionCategory
    sprite.physicsBody?.contactTestBitMask = kEdgeCollisionCategory
    self.addChild(sprite)
}



func didBeginContact(contact: SKPhysicsContact) {

    var firstBody:SKPhysicsBody?
    var second:SKPhysicsBody?


    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    }
    else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    var randomX = CGFloat(arc4random_uniform(UInt32(4))))
    var randomY = CGFloat(arc4random_uniform(UInt32(4))))

    if firstBody!.categoryBitMask == kSquareCollisionCategory && secondBody!.categoryBitMask == kEdgeCollisionCategory {
        firstBody!.velocity = (CGVectorMake(firstBody!.velocity.dx * randomX, firstBody!.velocity.dy * randomY))
    }

}

}

benblanchard
  • 19
  • 1
  • 5

2 Answers2

0

Upon contact you can apply a force or impulse to the ball depending on the ball's current vector. For example, upon contact the ball's vector is (30,-20). This example vector translates to the ball moving right and and down. You can then apply a new vector making the ball move left and up (-20, 25). You can use arc4random to set new values or set static ones.

If you need, read up on using vectors with physics bodies.

sangony
  • 11,636
  • 4
  • 39
  • 55
0

Your problem is here ,

 if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
    firstBody = contact.bodyA
    secondBody = contact.bodyB
}
else {
    firstBody = contact.bodyB
    secondBody = contact.bodyA
}

This means first body has categoryBitMask of kEdgeCollisionCategory and second body has categoryBitMask of kSquareCollisionCategory. So change this to,

 if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
    firstBody = contact.bodyB
    secondBody = contact.bodyA
}
else {
    firstBody = contact.bodyA
    secondBody = contact.bodyB
}

To get random number use this,

int minSpeed = 1;
int maxSpeed = 20;
int randNum = rand() % (max-min) + min;

Then apply impulse over the required body.

Jaffer Sheriff
  • 1,444
  • 13
  • 33