Why isn't my collision/contact working in Swift? - swift

I've been working on contacts/collisions in my new game. I just coded this, and it's not working correctly. Here is my code:
Square Details:
square.position = CGPointMake(self.size.width/2, self.size.height/1.5)
square.zPosition = 35
square.size = CGSize(width: 40, height: 40)
square.physicsBody = SKPhysicsBody(rectangleOfSize: square.size)
square.physicsBody?.affectedByGravity = false
square.physicsBody?.categoryBitMask = squareGroup
square.physicsBody?.collisionBitMask = obstacleGroup
square.physicsBody?.contactTestBitMask = obstacleGroup
self.addChild(square)
Obstacle Details (Obstacle 1 and 2 are the same):
obstacle1.physicsBody = SKPhysicsBody(rectangleOfSize: obstacle1.size)
obstacle1.physicsBody?.affectedByGravity = false
obstacle1.physicsBody?.dynamic = true
obstacle1.physicsBody?.mass = 10000
obstacle1.physicsBody?.categoryBitMask = obstacleGroup
obstacle1.physicsBody?.collisionBitMask = squareGroup
obstacle1.physicsBody?.contactTestBitMask = squareGroup
Here is my code for contacts between them and the category groups:
var squareGroup : UInt32 = 0x1 << 0
var obstacleGroup : UInt32 = 0x1 << 1
func didBeginContact(contact: SKPhysicsContact) {
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
firstBody = contact.bodyA
}
if firstBody.categoryBitMask == 1 && secondBody.categoryBitMask == 2{
let newScene = GameScene(size: self.size)
_ = SKTransition.fadeWithDuration(1)
self.view?.presentScene(newScene)
}
}
If anyone could help me that'd be great. Ask questions in the comments.

if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
firstBody = contact.bodyA
}
At the else statement you have firstBody = contact.bodyB and firstBody = contact.bodyA
I think you whanted to write secondBody = contact.bodyA
Also add double check for contact
if (firstBody.categoryBitMask == 0x1 << 1 && secondBody.categoryBitMask == 2) || (firstBody.categoryBitMask == 0x1 << 2 && secondBody.categoryBitMask == 1){
//enter code here
}

Related

Sprite not disappearing

Here is my code. I am trying to create a space shooter game and when the alien hits the bottom of the screen, I want the player to disappear. I'm not exactly sure what is wrong with this code.
func gameOver() {
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.categoryBitMask = borderCategory
func didBegin(_ contact: SKPhysicsContact) {
var firstBody:SKPhysicsBody
var secondBody:SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if (firstBody.categoryBitMask & alienCategory) != 0 && (secondBody.categoryBitMask & borderCategory) != 0 {
player.removeFromParent()
}

Swift Spritekit Collision Handling

This is my first attempt with SpriteKit and I'm having trouble getting my collision right with bitmasks.
I have three categories, If player hits lit, I want to increase the score and move the lit node off screen, else, I want to call my gameover() function. I've tried a lot of variations and can't see to get anything but general collision to be recognized. I've defined the category and contact bitmasks for each node as well.
let playerCategory: UInt32 = 1
let razzCategory: UInt32 = 2
let litCategory: UInt32 = 4
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else
{
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask & playerCategory) == 0 && (secondBody.categoryBitMask & litCategory) == 1)
{
lit.position.x = 400
score += 1
}
else {
gameOver()
}
}
if ((firstBody.categoryBitMask & playerCategory) == 0 && (secondBody.categoryBitMask & litCategory) == 1) Translates to the following in english.
If Firstbody AND playerCategory = 0 AND SecondBody And litCategory = 1
If Firstbody AND 1 = 0 AND SecondBody And 4 = 1
Now let's define Firstbody as playerCategory and SecondBody as litCategory
If playerCategory AND playerCategory = 0 AND litCategory and litCategory = 1
If 1 AND 1 = 0 AND 4 AND 4 = 1
If 1 = 0 AND 4 = 1
As you can see, this fails, and this method is always going to fail because if the second half of your test (SecondBody AND litCategory) can only have a value of 0 or 4, those 2 values will never be 1.
To correct the issue, you want to make sure that whatever body you are checking is equal to the category you are looking for
if ((firstBody.categoryBitMask & playerCategory) == playerCategory && (secondBody.categoryBitMask & litCategory) == litCategory)
What this says is if the firstBody is a member of the category playerCategory and the secondBody is a member of litCategory, then perform the following operatiion.
Below is the complete fix for your function:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else
{
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask & playerCategory) == playerCategory && (secondBody.categoryBitMask & litCategory) == litCategory)
{
lit.position.x = 400
score += 1
}
else {
gameOver()
}
}

Multiple Collision Detection in SpriteKit

I have a dynamic yellow SpriteNode in motion with a categoryBitMask and a contactTestBitMask and it's intended to collide with the static red rectangle SpriteNodes with their own categoryBitMasks and contactTestBitMasks.
I would like to call a function only when both the rectangles have been hit by the yellow sprite? Does anyone know how to do that? I currently have the following code below that I use to check for the collusion with one rectangle.
func didBeginContact(contact: SKPhysicsContact) {
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.categoryBitMask == kYellowCatergory && secondBody.categoryBitMask == kRectangleTarget {
//self.functionToCall()
}
}

didBeginContact not called : this instance is unique to me

So, I am still experimenting with Sprite Kit for my first time ever, and I would like to test for collision. So, I searched around a bit in Apple's documentation, around Stack Overflow, online tutorials, and other forums. However, I was unable to find something a tip or code that makes what I am doing work. So, here are the relevant pieces of code:
This is the code for an obstacle:
func createObstacle(){
var ball = SKShapeNode(circleOfRadius: 20)
var width = UInt32(self.frame.width)
var random_number = arc4random_uniform(width)
ball.position = CGPointMake(CGFloat(random_number), frame.height+20)
ball.strokeColor = SKColor.blackColor()
ball.glowWidth = 1.0
ball.fillColor = SKColor.darkGrayColor()
ball.physicsBody = SKPhysicsBody(circleOfRadius: 20)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody?.categoryBitMask = 6
ball.physicsBody?.dynamic = true
self.addChild(ball)
}
This is relevant code for the thing that it would collide with:
let circle = SKShapeNode(circleOfRadius: 20)
circle.physicsBody = SKPhysicsBody(circleOfRadius: 20)
circle.fillColor = SKColor.blueColor()
circle.strokeColor = SKColor.blueColor()
circle.glowWidth = 1.0
circle.physicsBody?.categoryBitMask = 4
circle.physicsBody?.dynamic = true
circle.physicsBody?.affectedByGravity = false
And this is the code for contact:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody!
var secondBody: SKPhysicsBody!
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask == 4 && secondBody.categoryBitMask == 6) || (firstBody.categoryBitMask == 6 && secondBody.categoryBitMask == 4)){
println("HI")
}else{println("NO")}
}
Sadly, nothing is being printed at all, so something's wrong. Any idea why this doesn't work?
Your class should have delegate SKPhysicsContactDelegate.
class GameScene: SKScene, SKPhysicsContactDelegate {
In didMoveToView write this:
physicsWorld.contactDelegate = self
EDIT
Define CategoryBitMask like this
struct PhysicsCategory {
static let circleCategory : UInt32 = 0b1 // 1
static let ballCategory : UInt32 = 0b10 // 2
}
Give CategoryBitMask to circle and ball
circle.physicsBody?.categoryBitMask = PhysicsCategory.circleCategory
ball.physicsBody?.categoryBitMask = PhysicsCategory.ballCategory
Then check contact like this:
(func didBeginContact(contact: SKPhysicsContact) {
if ((contact.bodyA.categoryBitMask == 0b1 && contact.bodyB.categoryBitMask == 0b10 ) || ( contact.bodyA.categoryBitMask == 0b1 && contact.BodyB.categoryBitMask == 0b1 ))
println("Contact")
}
}
Sorry for typos didnt used editor

Overriding collisions in SpriteKit

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))
}
}
}
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.
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.