0
votes

The problem: When the coin spawns, it's physicsBody appears right underneath the spriteNode. Also, when the player comes in contact with the coin's physicsBody, the player bounces off of the physicsBody and the game ends.

What the output should be: The coin's physisBody should be aligned properly with the coin spriteNode. When the player comes in contact with the coin, the coin should disappear and +1 should be added to the proper label.

The current code:

struct ColliderType {

static let playerCategory: UInt32 = 0x1 << 0

static let boundary: UInt32 = 0x1 << 1
​  
​static let coinCategory: UInt32 = 0x1 << 2
​
​static let bodyA: UInt32 = 0x1 << 4
​
​static let bodyB: UInt32 = 0x1 << 8

}

override func didMoveToView(view: SKView) {

var coinInt = 0
​
​
​
​self.physicsWorld.gravity = CGVectorMake(0.0, -7.0)
physicsWorld.contactDelegate = self

player = SKSpriteNode(imageNamed: "player")
player.zPosition = 1
player.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width / 5.12)
player.physicsBody?.dynamic = true
player.physicsBody?.allowsRotation = false

self.addChild(player)

generateCoins()

​
​
coin = SKSpriteNode( imageNamed: "coin")
coin.physicsBody? = SKPhysicsBody(circleOfRadius: coin.size.height / 10)
coin.physicsBody?.dynamic = false
coin.physicsBody?.allowsRotation = false
coin.zPosition = 1
​self.addChild(coin)
​
player.physicsBody?.categoryBitMask = ColliderType.playerCategory
​player.physicsBody?.contactTestBitMask = ColliderType.boundary
player.physicsBody?.collisionBitMask = ColliderType.coinCategory | ColliderType.boundary

coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

func didPlayerCollideWithCoin(player: SKSpriteNode, coin: SKSpriteNode) {



self.coin.removeFromParent()

self.coin += 1

coinLabel.text = "\(coinInt)"

}

​
​    
​
​func generateCoins()  {

if(self.actionForKey("spawning") != nil){return}

let coinTimer = SKAction.waitForDuration(7, withRange: 2)

let spawnCoin = SKAction.runBlock {

self.coin = SKSpriteNode( imageNamed: "coin")

self.coin.physicsBody = SKPhysicsBody(circleOfRadius: self.coin.size.height / 10)

self.coin.name = "coin"

self.coin.physicsBody?.dynamic = false

self.coin.physicsBody?.allowsRotation = false

var coinPosition = Array<CGPoint>()

coinPosition.append((CGPoint(x:340, y:103)))

coinPosition.append((CGPoint(x:340, y:148)))

coinPosition.append((CGPoint(x:340, y:218)))

coinPosition.append((CGPoint(x: 340, y:343)))

let spawnLocation = coinPosition[Int(arc4random_uniform(UInt32(coinPosition.count)))]

let action = SKAction.repeatActionForever(SKAction.moveToX(+self.xScale, duration: 4.4))

self.coin.runAction(action)

self.coin.position = spawnLocation

self.addChild(self.coin)

print(spawnLocation)

}

let sequence = SKAction.sequence([coinTimer, spawnCoin])

self.runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")

}
​​
func didBeginContact(contact:SKPhysicsContact)  {

let bodyA: SKPhysicsBody = contact.bodyA

let bodyB: SKPhysicsBody = contact.bodyB

if ((bodyA.categoryBitMask == ColliderType.playerCategory) &&     (bodyB.categoryBitMask == ColliderType.coinCategory)){

didPlayerCollideWithCoin(bodyA.node as! SKSpriteNode, coin: bodyB.node as! SKSpriteNode)

}

}
3
You already asked this, no? (stackoverflow.com/questions/37580673/…)rebusB
Any particular reason why you're using bits shifts of 0, 1, 2, 4 & 8 instead of 0, 1, 2, 3, 4 etc? Carry on like that and you'll only have 16 and 32 and then you've run out.Steve Ives

3 Answers

4
votes

I would recommend that you read these documentation first!

contactTestBitMask - A mask that defines which categories of bodies cause intersection notifications with a current physics body.

When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a nonzero value, an SKPhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.

collisionBitmask - A mask that defines which categories of physics bodies can collide with this physics body.

When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a nonzero value, this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.

Remove this code to solve the colliding issue

coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

Try to see if this solves your SpriteNode alignment issue

 var coinTexture = SKTexture(imageNamed: "coin")
 coin = SKSpriteNode(texture:coinTexture)
1
votes

Also, I would recommend changing how you're defining your Category Bitmasks. Since you're already doing bit shifting with <<, you don't need to shift by powers of two. That's what the bit shifting does for you. Try changing your code to this:

static let playerCategory: UInt32 = 0x1 << 0    
static let boundary: UInt32 = 0x1 << 1    ​  
​static let coinCategory: UInt32 = 0x1 << 2    ​
​static let bodyA: UInt32 = 0x1 << 3    ​
​static let bodyB: UInt32 = 0x1 << 4

This won't help with your problem, but this is good to know.

0
votes

I actually found a workaround that works much better for my game, where I sublcass SKNode to represent objects like missiles that have different damage, terrain cells, etc. I set the collision bit masks to all my objects to be the same (i.e., they all need to interact with each other. Then to loop through all collisions with player and also get a pointer to the proper object that it's colliding with, I do the following

for (int i=0; i<[self.physicsBody.allContactedBodies count]; i++) { SKPhysicsBody* contactedBody = self.physicsBody.allContactedBodies[i]; if (contactedBody != NULL && [contactedBody.node isKindOfClass:[TerrainCell class]]) { NSLog(@"BUMPED INTO TERRAIN"); TerrainCell* collisionObject = (TerrainCell*)contactedBody.node; // do more stuff specific to TerrainCell } }