Collide Type Source Error - Spritekit Swift Game

Collide type source error - spritekit swift game

So the issue now is that you have two definition for your masks:

Remove this one:

enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}

Use only this one:

    enum CollideType: Int {

case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4

func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}

Correct all code to match with CollideType definitions.

Correct this line in didBeginContact:

let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue

with:

let bitMaskAAndB = contact.bodyA.categoryBitMask == CollideType.Floor.toMask() ? contact.bodyB.categoryBitMask : CollideType.Ball.toMask()

If you have correct all you will don't have yet this error:

// ball and ceil => ERROR

UberJump Tutorial SpriteKit error

It seems like there could be an issue with your checkNodeRemoval function depending on how you're inheriting from the GameObjectNode. Something you could try is taking the checkNodeRemoval function out and checking directly in your update method.

// Remove game objects that have passed by
foregroundNode.enumerateChildNodesWithName("NODE_PLATFORM", usingBlock: {
(node, stop) in
print("found platform node")
if self.player.position.y > node.position.y + 300.0 {
print("attempt to remove platform")
platform.removeFromParent()
}
})

foregroundNode.enumerateChildNodesWithName("NODE_STAR", usingBlock: {
(node, stop) in
print("found star node")
if self.player.position.y > node.position.y + 300.0 {
print("attempt to remove star")
star.removeFromParent()
}
})

Swift/SpriteKit Multiple Collision Detection?

Several problems here.

  1. You're defining categories in a way that keeps them from being easily tested.
  2. You're testing categories in a way that doesn't get you the unique answers you want.
  3. You've confused your code by trying to track up to four bodies in one contact. Any contact will always have exactly two bodies.

Let's solve them one at a time...

1. Defining Categories

You want to define collision categories so that each kind of body in your game uses its own bit in the mask. (You've got a good idea using Swift's binary literal notation, but you're defining categories that overlap.) Here's an example of non-overlapping categories:

struct PhysicsCategory: OptionSet {
let rawValue: UInt32
init(rawValue: UInt32) { self.rawValue = rawValue }

static let enemy = PhysicsCategory(rawValue: 0b001)
static let bullet = PhysicsCategory(rawValue: 0b010)
static let spiral = PhysicsCategory(rawValue: 0b100)
}

I'm using a Swift OptionSet type for this, because it makes it easy to make and test for combinations of unique values. It does make the syntax for defining my type and its members a bit unwieldy compared to an enum, but it also means I don't have to do a lot of boxing and unboxing raw values later, especially if I also make convenience accessors like this one:

extension SKPhysicsBody {
var category: PhysicsCategory {
get {
return PhysicsCategory(rawValue: self.categoryBitMask)
}
set(newValue) {
self.categoryBitMask = newValue.rawValue
}
}
}

Also, I'm using the binary literal notation and extra whitespace and zeroes in my code so that it's easy to make sure that each category gets its own bit — enemy gets only the least significant bit, bullet the next one, etc.

2 & 3. Testing & Tracking Categories

I like to use a two-tiered approach to contact handlers. First, I check for the kind of collision — is it a bullet/enemy collision or a bullet/spiral collision or a spiral/enemy collision? Then, if necessary I check to see which body in the collision is which. This doesn't cost much in terms of computation, and it makes it very clear at every point in my code what's going on.

func didBegin(_ contact: SKPhysicsContact) {
// Step 1. To find out what kind of contact we have,
// construct a value representing the union of the bodies' categories
// (same as the bitwise OR of the raw values)
let contactCategory: PhysicsCategory = [contact.bodyA.category, contact.bodyB.category]

if contactCategory.contains([.enemy, .bullet]) {
// Step 2: We know it's an enemy/bullet contact, so there are only
// two possible arrangements for which body is which:
if contact.bodyA.category == .enemy {
self.handleContact(enemy: contact.bodyA.node!, bullet: contact.bodyB.node!)
} else {
self.handleContact(enemy: contact.bodyB.node!, bullet: contact.bodyA.node!)
}
} else if contactCategory.contains([.enemy, .spiral]) {
// Here we don't care which body is which, so no need to disambiguate.
self.gameOver()

} else if contactCategory.contains([.bullet, .spiral]) {
print("bullet + spiral contact")
// If we don't care about this, we don't necessarily
// need to handle it gere. Can either omit this case,
// or set up contactTestBitMask so that we
// don't even get called for it.

} else {
// The compiler doesn't know about which possible
// contactCategory values we consider valid, so
// we need a default case to avoid compile error.
// Use this as a debugging aid:
preconditionFailure("Unexpected collision type: \(contactCategory)")
}
}

Extra Credit

Why use if statements and the OptionSet type's contains() method? Why not do something like this switch statement, which makes the syntax for testing values a lot shorter?

switch contactCategory {
case [.enemy, .bullet]:
// ...
case [.enemy, .spiral]:
// ...

// ...

default:
// ...
}

The problem with using switch here is that it tests your OptionSets for equality — that is, case #1 fires if contactCategory == [.enemy, .bullet], and won't fire if it's [.enemy, .bullet, .somethingElse].

With the contact categories we've defined in this example, that's not a problem. But one of the nice features of the category/contact bit mask system is that you can encode multiple categories on a single item. For example:

struct PhysicsCategory: OptionSet {
// (don't forget rawValue and init)
static let ship = PhysicsCategory(rawValue: 0b0001)
static let bullet = PhysicsCategory(rawValue: 0b0010)
static let spiral = PhysicsCategory(rawValue: 0b0100)
static let enemy = PhysicsCategory(rawValue: 0b1000)
}

friendlyShip.physicsBody!.category = [.ship]
enemyShip.physicsBody!.category = [.ship, .enemy]
friendlyBullet.physicsBody!.category = [.bullet]
enemyBullet.physicsBody!.category = [.bullet, .enemy]

In a situation like that, you could have a contact whose category is [.ship, .bullet, .enemy] — and if your contact handling logic is testing specifically for [.ship, .bullet], you'll miss it. If you use contains instead, you can test for the specific flags you care about without needing to care whether other flags are present.

Stop objects from colliding using SpriteKit

There is a lot of documentation on these topics, but here is a practical example.

The power of categoryBitMasks

Pretend you have a collection of three nodes pool, basketball and bowlingball. Now, obviously, we want the basketball and bowlingball to collide with the each other. So you set the collisionBitMasks like so:

basketball.physicsBody?.collisionBitMask    = UInt32(2)
bowlingball.physicsBody?.collisionBitMask = UInt32(2)

Great. Now, we want the bowlingball to sink to the bottom of the pool, and the basketball to collide with the pool (might be more of a splash, but bear with me). How would we do this? We could try:

pool.physicsBody?.collisionBitMask = UInt32(2) // ?

But wait, that would make the basketball AND the bowlingball collide with the pool. We only want the basketball to collide with the pool , whereas we want the bowlingball to ignore the pool and sink straight to the bottom with no collisions. This is where categoryBitMasks come in handy:

let basketballBitMask     = UInt32(1)
let bowlingballBitMask = UInt32(2)
let poolBitMask = UInt32(4) // Why 4? See next section

basketball.physicsBody?.categoryBitMask = basketballBitMask
bowlingball.physicsBody?.categoryBitMask = bowlingballBitMask
pool.physicsBody?.categoryBitMask = poolBitMask

Because each object has a unique number assigned to it, you can now pick and choose which objects you'd like another object to collide with:

// basketball physics body collides with bowlingball(2) OR pool(4)
basketball.physicsBody?.collisionBitMask = bowlingballBitMask | poolBitMask
// ( '|' = logical OR operator)

// bowlingball physics body only collides with basketball(1)
bowlingball.physicsBody?.collisionBitMask = basketballBitMask

// pool physics body only collides with basketball(1)
pool.physicsBody?.collisionBitMask = basketballBitmask

If you're not sure what the strange '|' symbol is doing, I highly recommend the swift documentation on advanced operators to help you understand what's happening here.

Why not just use collisionBitMasks?

Okay so we've set some bit masks. But how are they used? If we only have two objects why can't we just compare collisionBitMasks?

Simply put, that's just not how it works. When a bowlingball comes into contact with the pool, the SpriteKit physics engine will AND ('&') together the bowlingball's categoryBitMask with the pool's collisionBitMask (or vice versa; the result is the same):

objectsShouldCollide = (bowlingball.physicsBody?.categoryBitMask & 
pool.physicsBody?.collisionBitMask)
// objectsShouldCollide = (ob010 & 0b100) = 0b000

Because the bowlingball's categoryBitMask and the pool's collisionBitMask have zero bits in common, objectsShouldCollide is equal to zero, and SpriteKit will stop the objects from colliding.

But, in your case, you're not setting your objects' categoryBitMasks. So they have a default value of 2^32, or 0xFFFFFFFF (hexadecimal representation) or in binary, 0b11111111111111111111111111111111. So when an "object" hits a "second" object, SpriteKit does this:

objectsShouldCollide = (0b11111111111111111111111111111111 & // Default categoryBitMask for "object" 
0b00000000000000000000000000000001) // collisionBitMask for "second" object
// = 0b00000000000000000000000000000001

So when you haven't defined the object's categoryBitMask, no matter what you set as the second object's collisionBitMask, objectsShouldCollide will never be zero, and they will always collide.

Note: you could set an object's collisionBitMask to 0; but then that object would never be able to collide with anything.

Using powers of 2 (0,1,2,4,8, etc.) for categoryBitMasks

Now let's say we wanted to include multiple bowlingballs that collided with each other. Easy:

bowlingball.physicsBody?.collisionBitMask  = basketballBitMask | bowlingballBitMask
// bowlingball collision bit mask (in binary) = 0b10 | 0b01 = 0b11
// bowlingball collision bit mask (in decimal) = 2 | 1 = 3

Here you can see that if we had set the pools physicsCategory to UInt32(3), it would no longer be distinguishable from a bowlingball or basketball.

Further suggestions

Learn to name variables with purpose, even if you're just using them for testing (although, coincidentally, "object and second object" worked quite well).

Use a struct for bitmasks to simplify your code and improve readability:

struct PhysicsCategory {
static let Obj1 : UInt32 = 0b1 << 0
static let Obj2 : UInt32 = 0b1 << 1
static let Obj3 : UInt32 = 0b1 << 2
static let Obj4 : UInt32 = 0b1 << 3
}

obj1.physicsBody?.categoryBitmask = PhysicsCategory.Obj1 // etc

Flipped x-scale breaks collision handling (SpriteKit 7.1)

I'm convinced this is a bug in SpriteKit.

Anyway, here is one solution for the problem (Actually, this is more a workaround than a real solution but...): Wrap the sprite in a container node. Also, container node holds the physicsBody while the child node is merely a graphics node. This way you can safely flip the sprite using xScale without affecting the physics of the node.

// Init
{
SKSpriteNode* turtleSprite = [SKSpriteNode spriteNodeWithImageNamed:@"turtle.png"];
self.turtleSprite = turtleSprite;

SKNode* turtleWrapper = [SKNode node];
turtleWrapper.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:turtleSprite.size.width/2];
turtleWrapper.physicsBody.categoryBitMask = 2;
turtleWrapper.physicsBody.collisionBitMask = 1;
turtleWrapper.physicsBody.contactTestBitMask = 1;

[turtleWrapper addChild:turtleSprite];
[self.world addChild:turtleWrapper];
}

// Elsewhere
{
self.turtleSprite.xScale *= -1;
}

Issue with updating score based on collision detection in SpriteKit

I have solved the issue myself after some reading from Apple's documentation and experimenting different options. Issue was that the didBeginContact method that is a default method provided by SpriteKit to detect contacts and collisions, was called multiple times as Joern tried to explain in his answer. But objects involved in collision in my game are not of irregular shapes. One kind of objects are oval shaped while the other kind of object is of more or less rectangular shape.Yet the method was being called more than once whenever the contact was made between two objects.

How did I solve it?
I tried applying the technique Joern suggested although I knew it wasn't the real solution I was looking but more of a temporary cover up. But surprisingly it did not work for my game as score would still increment randomly. I removed my oval shaped sprites and replaced them with simple round solid colour sprites just in case my oval shaped sprites were not smooth near the edges. Even then the problem continued that led me to Apple's documentation on this link a link. I came to know that to have best performance from a physical body and better accuracy for collision detection, one should go for simpler physical bodies when possible. A Circular physical body is most performance efficient as it is pretty fast to process and the simplest. Rectangular physics body comes next, followed by a polygonal physics body and physics body from an image texture on last. More complex the phycis body is, more is going to be computational cost and chances of losing accuracy increase. I had created physical bodies of my colliding objects using image texture. Physical bodies created from texture somehow were the cause (or at least in my case) why didContactMethod was being called multiple times. Even physical body of a simple round sprite created from texture was incrementing score by 2 instead of 1. I changed the code to create physical bodies of circular shape for my oval shaped sprites and everything is perfect now without needing to change category for to be removed nodes or any boolean flag.

Avoiding multiple calls to didBeginContact method by use of Boolean flags or any other way can be a cover up but not the solution which works in few cases but won't work in others. Try using simplest physics bodies where possible especially when you start getting inaccurate results from collisions and contacts.



Related Topics



Leave a reply



Submit