【问题标题】:How to detect no collision in a sprite kit game如何在精灵套件游戏中检测到没有碰撞
【发布时间】:2017-11-06 04:23:50
【问题描述】:

我正在做一个游戏,你必须使用挂在线上的蜘蛛来捕捉糖果,正如我在此链接中展示的那样:Game screenshot(我是新来的,所以我还不能发布图片)。我已经有了蜘蛛从左到右的运动,而且我可以使用 SKAction 在“Y”中移动来捕捉糖果,我唯一的问题是我还没有弄清楚如何知道蜘蛛是否没有t 捕获任何糖果,在他的运动过程中,我尝试在动作完成时使用 allContactedBodies 函数,但返回的数组计数始终为零。有什么建议吗?

代码如下:

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"
                }
            }
        })
    }
}

【问题讨论】:

    标签: ios sprite-kit game-physics skphysicsbody


    【解决方案1】:

    首先,您在这个问题中有很多代码......太多了,很难专注于真正发生的事情。您还缺少 moveCharacter() 的代码块。

    您应该认真考虑为您的播放器、绳索和(主要是)糖果创建子类。我还会考虑最初创建一个糖果数组,这样您就不会在运行时动态创建物理对象。

    至于你的问题是不是就像在你的类中创建几个变量那么简单

    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
    }
    

    【讨论】:

    • 嗨@Ron Myschuk,感谢您的建议,我将为角色、绳索和糖果创建类,并创建糖果数组以避免在运行时创建物理对象。但是你给我的解决方案不起作用,问题是在collisionBetween函数之前触发了动作完成,所以即使我得到一个糖果,变量“isMoving”仍然是false
    • 你的意思是“didGetCandy”还是假的吗?
    • 你能提供一些关于玩家如何移动的见解吗?我假设蜘蛛上下移动?我在这里看不到任何将蜘蛛移回的代码。您可以将 moveCharacter 的代码添加到您的问题中吗?
    • 是的,“didGetCandy”是假的。对不起
    • 我已经添加了moveCharacter()函数,但是这个函数只是将角色从左向右移动,上下移动是通过触摸屏幕触发的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多