Search code examples
swiftsprite-kitcollision-detectioncollision

spritekit objects not detect each other


I'm making a small game, like flappy bird. I have no idea why objects not "see" ourselves. I'm adding a Wall, Ground, and a Ghost, and what is pretty strange, Ghost detect a Ground, and vice versa, but Wall is still invisible. Why?

a ghost should stop on vertical rectangle (Wall), not fall on the ground. enter image description here

struct PhysicsCatagory{
    static let Ghost : UInt32 = 0x1 << 1  
    static let Wall : UInt32 = 0x1 << 2
    static let Ground : UInt32 = 0x1 << 3
}

class GameScene: SKScene{

   var Ground = SKSpriteNode()
   var Ghost = SKSpriteNode()
   var Wall = SKSpriteNode()



    override func didMove(to view: SKView) {

        /*******adding ground***/
        Ground = SKSpriteNode(imageNamed: "Ground")
        Ground.setScale(0.7)
        Ground.position = CGPoint(x: self.frame.midX, y: self.frame.minY)

        Ground.physicsBody = SKPhysicsBody(rectangleOf: Ground.size)
        Ground.physicsBody?.categoryBitMask = PhysicsCatagory.Ground
        Ground.physicsBody?.collisionBitMask = PhysicsCatagory.Ghost
        Ground.physicsBody?.contactTestBitMask = PhysicsCatagory.Ghost
        Ground.physicsBody?.affectedByGravity = false
        Ground.physicsBody?.isDynamic = false
        Ground.zPosition = 3
        self.addChild(Ground)

        /*******adding wall (not working)****/
        Wall = SKSpriteNode(imageNamed: "Wall")
        Wall.setScale(0.7)
        Wall.position = CGPoint(x: self.frame.midX, y: self.frame.midY + 100)

        Wall.physicsBody? = SKPhysicsBody(rectangleOf: Wall.size)
        Wall.physicsBody?.categoryBitMask = PhysicsCatagory.Wall
        Wall.physicsBody?.collisionBitMask = PhysicsCatagory.Ghost
        Wall.physicsBody?.contactTestBitMask = PhysicsCatagory.Ghost
        Wall.physicsBody?.affectedByGravity = false
        Wall.physicsBody?.isDynamic = false
        Wall.zPosition = 1
        self.addChild(Wall)


        /*******adding ghost***/
        Ghost = SKSpriteNode(imageNamed: "Ghost")
        Ghost.size = CGSize(width: 90, height: 100)
        Ghost.position = CGPoint(x: self.frame.midX, y: self.frame.maxY)

        Ghost.physicsBody = SKPhysicsBody(circleOfRadius: 50)
        Ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
        Ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Wall | PhysicsCatagory.Ground
        Ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Wall | PhysicsCatagory.Ground
        Ghost.physicsBody?.affectedByGravity = true
        Ghost.physicsBody?.isDynamic = true
        Ghost.zPosition = 2
        self.addChild(Ghost)

    }

Solution

  • Take a look at this:

    Wall.physicsBody? = SKPhysicsBody(rectangleOf: Wall.size)
    

    Notice the question mark here. It is used to specify optional chaining:

    Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil.

    Now, assignment is a part of an optional chaining too. So if a property is nil, the assignment will fail.

    In your case, a physicsBody property is nil, so none of the code on the right hand side of the = operator is evaluated.

    To make this work, do this:

    Wall.physicsBody = SKPhysicsBody(rectangleOf: Wall.size)
    

    Something unrelated to this, but a good thing to keep in mind:

    If you are interested in contact detection between two bodies, at least one has to be dynamic. I point this out because your Wall and Ground objects are static, meaning that no contacts will be detected between them no matter how you set the contact masks up.

    Oh, and yeah, use camelCase notation for naming classes, properties, and so on.