amalfilemons amalfilemons - 10 days ago 5
Swift Question

No collisions being detected in subclassed nodes

I'm writing a game. It is not detecting any collisions, even though I can see the physics bodies as I have that view turned on.

To set-up the physics world in the game scene, I've coded the following above the class declaration:

struct PhysicsCategory {
static let None: UInt32 = 0
static let Chicken: UInt32 = 0b1
static let Edge: UInt32 = 0b10
}


Then, within the actual class of the scene:

override func didMove(to view: SKView) {
setupNodes()
setupTrial()

let playableRect = CGRect(x: 0, y: 0, width: size.width/2, height: size.height/2)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: playableRect)
self.physicsWorld.contactDelegate = self
self.physicsBody!.categoryBitMask = PhysicsCategory.Edge
self.physicsBody!.contactTestBitMask = PhysicsCategory.Chicken

// This is important for handling all the custom events
enumerateChildNodes(withName: "//*", using: { node, _ in
// we need to limit this to chickens only
if let customNode = node as? CustomNodeEvents {
customNode.didMoveToScene()
}
})
}


Here is the code to detect collisions:

func didBegin(_ contact: SKPhysicsContact) {
print("something happened")
let collision = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

if collision == PhysicsCategory.Chicken | PhysicsCategory.Edge {
print("it works!")
}
}


The nodes I'd like to animate are chickens. I want the game to detect when they collide with the edges of the world above.

My chicken subclass is this:

class TargetNode: SKSpriteNode, CustomNodeEvents, InteractiveNode {

func didMoveToScene() {
isUserInteractionEnabled = true

anchorPoint = CGPoint(x: 0, y: 0)
let playableRect = CGRect(x: self.anchorPoint.x, y: self.anchorPoint.y, width: self.size.width, height: self.size.height)

physicsBody = SKPhysicsBody(edgeLoopFrom: playableRect)
physicsBody!.isDynamic = true
physicsBody!.categoryBitMask = PhysicsCategory.Chicken
physicsBody!.contactTestBitMask = PhysicsCategory.Edge | PhysicsCategory.Chicken
physicsBody!.velocity = CGVector(dx: 100, dy: 0)
}
}


EDIT: The nodes are being added to the scene using this method in the game scene file.

func generateItems(targetNumber: Int, target: Bool) {
let movingItems = true
for _ in 0...(targetNumber - 1) {
if (target) {
let name = createTarget()
let targetNode = TargetNode(imageNamed: name)
targetNode.name = name
fgNode.addChild(targetNode)
targetNode.position = generateRandomLocation()
//if movingItems { animateTargets(targetNode) }
}
}

Answer

setting your chicken to a SKPhysicsBody(edgeLoopFrom :_) is a bad idea. instead try SKPhysicsBody(rectangleOf :_) to draw a rectangle shape around your chicken, the type of shape you want to draw can very, check the docs for more information.

Moreover to check weather the chickens have made contact with the playableRect

remove self.physicsBody!.contactTestBitMask = PhysicsCategory.Chicken because we don't want to check if the rect has made contact with the chicken we want to know if the chicken has made contact with the playable Rect. So keep contactTestBitMask on the chicken.

remove : | PhysicsCategory.Chicken from your chicken subclass, unless you want to check weather the chickens collide with each other as well.

lastly: check for collisions, if the chicken makes contact with the playableRect

  func didBegin(_ contact: SKPhysicsContact) {

    if contact.bodyA.categoryBitMask == PhysicsCategory.Chicken && contact.bodyB.categoryBitMask == PhysicsCategory.Edge {
       print("Chickens have collided with edge")
    }

    }