简体   繁体   中英

How to detect no collision in a sprite kit game

I'm doing a game where you have to capture candies using a spider hung by a thread, as I show in this link: Game screenshot (I'm new here so I can't post images yet). I already have the movement of the spider from left to right and also I'm able to catch the candies using SKAction moving through 'Y', my only issue is I didn't figure it out yet how to know if the spider don't capture any candy, during his movement, I was trying use the allContactedBodies function when the action finish but the count of the array returned is always zero. Any suggestions?

Here is the code :

class GameScene: SKScene, SKPhysicsContactDelegate {

    private var rope = SKSpriteNode(imageNamed: "rope")
    private var anchor = SKSpriteNode(imageNamed: "anchor")
    private var currentCharacter: SKSpriteNode!
    private var candy: SKSpriteNode!
    var direction : String = "backward"

    var lastCandyAdded: TimeInterval = 0
    let candyVelocity: CGFloat = 4.0

    let characterBitMask  : UInt32 = 0x1 << 1
    let candyBitMask: UInt32 = 0x1 << 2

    let characterVelocity: CGFloat = 18.0
    var direction : String = "backward"

    override func didMove(to view: SKView) {
        self.physicsWorld.contactDelegate = self

        self.addAnchor()
        self.addRope()
        self.addCharacter()

        let jointOneFixed = SKPhysicsJointFixed.joint(withBodyA: anchor.physicsBody!, bodyB: rope.physicsBody!, anchor: anchor.position)
        self.physicsWorld.add(jointOneFixed);

        let jointTwoFixed = SKPhysicsJointFixed.joint(withBodyA: rope.physicsBody!, bodyB: currentCharacter.physicsBody!, anchor: currentCharacter.position)
        self.physicsWorld.add(jointTwoFixed);
    }

    func addAnchor(){
        anchor.position = CGPoint(x: self.size.width / 2, y: self.size.height + 1)
        anchor.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        anchor.setScale(1)
        anchor.zPosition = 2
        anchor.name = "anchor"
        anchor.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: anchor.size.width, height: anchor.size.height))
        anchor.physicsBody?.affectedByGravity = false
        anchor.physicsBody?.friction = 0;
        anchor.physicsBody?.linearDamping = 0;
        anchor.physicsBody?.mass = 10;
        self.addChild(anchor)
    }

    func addCharacter() {
        let characterName: String = UserDefaults.standard.string(forKey: "current_character")!
        currentCharacter = SKSpriteNode(imageNamed: characterName);
        currentCharacter.position = CGPoint(x: self.size.width / 2, y: self.size.height - 400)
        currentCharacter.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        currentCharacter.setScale(0.43)
        currentCharacter.zPosition = 2
        currentCharacter.name = "character"
        currentCharacter.physicsBody = SKPhysicsBody(rectangleOf: currentCharacter.size)
        currentCharacter.physicsBody?.categoryBitMask = characterBitMask
        currentCharacter.physicsBody?.contactTestBitMask = candyBitMask
        currentCharacter.physicsBody?.collisionBitMask = candyBitMask;
        currentCharacter.physicsBody?.affectedByGravity = false;
        currentCharacter.physicsBody?.friction = 0;
        currentCharacter.physicsBody?.linearDamping = 0;
        currentCharacter.physicsBody?.mass = 20;
        self.addChild(currentCharacter)
    }

    func addRope() {
        rope.position = CGPoint(x: anchor.position.x, y: anchor.position.y - 70)
        rope.setScale(0.65)
        rope.zPosition = 1
        rope.name = "rope"
        rope.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: rope.size.width, height: rope.size.height))
        rope.physicsBody?.affectedByGravity = false;
        rope.physicsBody?.friction = 0;
        rope.physicsBody?.linearDamping = 0;
        rope.physicsBody?.mass = 5;
        rope.physicsBody?.allowsRotation = false
        self.addChild(rope)
    }

    func addCandy() {
        let number = Int.random(min: 1, max: 24)
        let candyWord = "candie"
        let candyTexture = SKTexture(imageNamed: "\(candyWord)\(number)")
        candy = SKSpriteNode(texture: candyTexture)
        candy.zPosition = 3
        candy.setScale(0.40)
        candy.physicsBody = SKPhysicsBody(circleOfRadius: max(candy.size.width / 2, candy.size.height / 2))
        candy.physicsBody?.isDynamic = true
        candy.name = "candy"
        candy.physicsBody?.categoryBitMask = candyBitMask
        candy.physicsBody?.contactTestBitMask = characterBitMask
        candy.physicsBody?.collisionBitMask = characterBitMask
        candy.physicsBody?.affectedByGravity = false
        candy.position = CGPoint(x: self.frame.size.width + 20, y: self.frame.size.height / 2 + 150)
        self.addChild(candy)
    }

    func moveCandy() {
        self.enumerateChildNodes(withName: "candy", using: {(node, stop) -> Void in
            if let candy = node as? SKSpriteNode {
                candy.position = CGPoint(x: candy.position.x - self.candyVelocity, y: candy.position.y)
                if candy.position.x < 0 {
                    candy.removeFromParent()
                }
            }
        })
    }

    override func update(_ currentTime: TimeInterval) {
        self.moveCandy()
        self.moveCharacter()
        if currentTime - self.lastCandyAdded >  0.75 {
            self.lastCandyAdded = currentTime + Double.random(min: 0.00, max: 0.60)
            self.addCandy()
        }
    }

    func collisionBetween(candy: SKNode, object: SKNode) {
        let moveUp = SKAction.moveBy(x: 0, y: 100, duration:0.0)
        let shrinkRope = SKAction.animate(with: [SKTexture(imageNamed: "rope")], timePerFrame: 0)

        let moveUpBlock = SKAction.run({
            self.anchor.run(moveUp)
        })
        let shrinkRopeBlock = SKAction.run({
            self.rope.run(shrinkRope)
        })

        let sequence = SKAction.sequence([SKAction.wait(forDuration: 0.07), shrinkRopeBlock, moveUpBlock])
        self.run(sequence)

        candy.removeFromParent()
    }

    func didBegin(_ contact: SKPhysicsContact) {
        guard let nodeA = contact.bodyA.node else { return }
        guard let nodeB = contact.bodyB.node else { return }

        if nodeA.name == "candy" && nodeB.name == "character" {
            collisionBetween(candy: nodeA, object: nodeB)
        } else if nodeA.name == "character" && nodeB.name == "candy" {
            collisionBetween(candy: nodeB, object: nodeA)
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
        let moveDown = SKAction.moveBy(x: 0, y: -100, duration:0.0)
        let stretchRope = SKAction.animate(with: [SKTexture(imageNamed: "rope_stretch")], timePerFrame: 0)

        let moveDownBlock = SKAction.run({
            self.anchor.run(moveDown, completion: {
               var physicBodies = self.currentCharacter.physicsBody?.allContactedBodies();

                // This count is always zero
                print(physicBodies?.count)

            })
        })
        let stretchRopeBlock = SKAction.run({
            self.rope.run(stretchRope)
        })

        let sequence = SKAction.sequence([moveDownBlock, stretchRopeBlock])
        self.run(sequence)
    }

    func moveCharacter(){
        self.enumerateChildNodes(withName: "anchor", using: {(node, stop) -> Void in
            if let anchorNode = node as? SKSpriteNode {
                if anchorNode.position.x < 120 {
                    anchorNode.position = CGPoint(x: anchorNode.position.x + self.characterVelocity, y: anchorNode.position.y)
                    self.direction = "forward"
                } else if anchorNode.position.x > self.size.width - 120 {
                    anchorNode.position = CGPoint(x: anchorNode.position.x - self.characterVelocity, y: anchorNode.position.y)
                    self.direction = "backward"
                } else if self.direction == "forward" {
                    anchorNode.position = CGPoint(x: anchorNode.position.x + self.characterVelocity, y: anchorNode.position.y)
                    self.direction = "forward"
                } else {
                    anchorNode.position = CGPoint(x: anchorNode.position.x - self.characterVelocity, y: anchorNode.position.y)
                    self.direction = "backward"
                }
            }
        })
    }
}

First of all you have a lot of code in this question...too much, it makes it hard to focus on what is really happening. You are also missing a block of code for moveCharacter().

You should strongly look at creating subclasses for your player, rope and (mostly)candies. I would also look into creating an array of candies initially so that you are not dynamically creating physics objects during run time.

As for your question wouldn't it be as simple as creating a couple of variables in your class

private var isMoving = false
private var didGetCandy = false

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    //prevent the user from firing the move while in the middle of a move
    guard !isMoving else { return }
    isMoving = true

    let moveDownBlock = SKAction.run({
        self.anchor.run(moveDown) {
           //this is an appreviated form of a 'completion' block
           self.isMoving = false
           print("did I get a candy \(didGetCandy)")
        }
    })
}

func collisionBetween(candy: SKNode, object: SKNode) {
    didGetCandy = true
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM