简体   繁体   中英

How to detect collisions in Sprite Kit?

I am trying to delete an object (an orb node) when the character comes into contact but it just acts like a circle and the character falls off when it gets on top. I deleted the code for the collision detection because I have no idea if it is right.

Here is my code for GameScene.swift:

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {
override init(size:CGSize){
    super.init(size:size)

    let CollisionCategoryPlayer
    : UInt32 = 0x1 << 1

    let CollisionCategoryPowerUpOrbs
    : UInt32 = 0x1 << 2

    character.physicsBody?.categoryBitMask = CollisionCategoryPlayer
    character.physicsBody?.contactTestBitMask = CollisionCategoryPowerUpOrbs
    character.physicsBody?.collisionBitMask = 0

    orbNode.physicsBody?.categoryBitMask = CollisionCategoryPowerUpOrbs
    orbNode.physicsBody?.collisionBitMask = 0
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

//variables
let character = SKSpriteNode(imageNamed:"square_red.png")
let floor = SKSpriteNode(imageNamed: "platform.jpg")
let platform1 = SKSpriteNode(imageNamed: "platform2.png")
let platform2 = SKSpriteNode(imageNamed: "platform2.png")
let orbNode = SKSpriteNode(imageNamed: "PowerUp.png")
var characterSize:CGFloat = 0.2
var foodCount = 0

override func didMoveToView(view: SKView) {
    //World Physics
    self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
    self.physicsWorld.contactDelegate = self
    self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
    //Character
    character.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
    character.setScale(characterSize)
    character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
    character.physicsBody?.allowsRotation = false
    self.addChild(character)
    //floor
    floor.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)*0.2)
    floor.setScale(2.0)
    floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.size)
    floor.physicsBody?.dynamic = false
    self.addChild(floor)

    //platform one
    platform1.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)*0.7)
    platform1.setScale(0.4)
    platform1.physicsBody = SKPhysicsBody(rectangleOfSize: platform1.size)
    platform1.physicsBody?.dynamic = false
    self.addChild(platform1)

    //platform two
    platform2.position = CGPoint(x: CGRectGetMidX(self.frame)*1.4, y: CGRectGetMidY(self.frame)*1)
    platform2.setScale(0.4)
    platform2.physicsBody = SKPhysicsBody(rectangleOfSize: platform2.size)
    platform2.physicsBody?.dynamic = false
    self.addChild(platform2)

    //orbNode
    orbNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
    orbNode.setScale(0.2)
    self.addChild(orbNode)
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    character.removeActionForKey("moveAction")
    character.removeActionForKey("shrink")
    character.removeActionForKey("rotate")
}

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch:AnyObject in touches {
        let location = touch.locationInNode(self)

        if location.x < CGRectGetMidX(self.frame) && location.y < CGRectGetMidY(self.frame)*0.7{
            //shrinks with each movement
            characterSize-=0.005
           let moveAction = SKAction.repeatActionForever(SKAction.moveByX(-30, y: 0, duration: 0.1))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
             character.runAction(moveAction, withKey: "moveAction")
            character.runAction(shrink, withKey: "shrink")
        } else if location.x > CGRectGetMidX(self.frame) && location.y < CGRectGetMidY(self.frame)*0.7{
            //shrinks with each movement
            characterSize-=0.005
            let moveAction = SKAction.repeatActionForever(SKAction.moveByX(30, y: 0, duration: 0.1))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
            character.runAction(moveAction, withKey: "moveAction")
            character.runAction(shrink, withKey: "shrink")
        } else if location.y > character.position.y + 15  {
            //shrinks with each movement
            characterSize-=0.005
            character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
            character.runAction(shrink, withKey: "shrink")
                        }
    }

    func didBeginContact(contact: SKPhysicsContact){

    }
func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */

        }

}
}

You should group your physics body, you code seems to be all over the place. Also the reason you get the error is because you are settings the physics body before setting the player and missing some for the Orbs.

Here is your same code rewritten and I think a bit more readable and understandable.

import SpriteKit

/// Physics category
struct PhysicsCategory {
    static let player: UInt32 = 0x1 << 0
    static let orb: UInt32 = 0x1 << 1
    static let floor: UInt32 = 0x1 << 2
    static let platform: UInt32 = 0x1 << 3
 }

/// Image names
struct ImageName {
     static let platform1 = "platform2.png"
     static let platform2 = "platform2.png"

     // can do this for other images as well, but because you create loads of platforms its nice to have a refernce like this
}

  /// Always put your keys for removing actions etc into structs to avoid typos
 struct Key {
    static let moveAction = "moveAction"
    static let shrink = "shrink"
    static let rotate = "rotate"
  }

 /// GameScene
 class GameScene: SKScene, SKPhysicsContactDelegate {

//variables
let character = SKSpriteNode(imageNamed:"square_red.png")
let floor = SKSpriteNode(imageNamed: "platform.jpg")
var platform1 = SKSpriteNode()
var platform2 = SKSpriteNode()
let orbNode = SKSpriteNode(imageNamed: "PowerUp.png")
var characterSize:CGFloat = 0.2
var foodCount = 0

//didMoveToView
override func didMoveToView(view: SKView) {

    //World Physics
    self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
    self.physicsWorld.contactDelegate = self
    self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)

    //Character
    character.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
    character.setScale(characterSize)
    character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
    character.physicsBody?.allowsRotation = false
    character.physicsBody?.dynamic = true // must be true for collision to fire
    character.physicsBody?.affectedByGravity = false
    character.physicsBody?.categoryBitMask = PhysicsCategory.player
    character.physicsBody?.contactTestBitMask = PhysicsCategory.orb
    character.physicsBody?.collisionBitMask = PhysicsCategory.floor | PhysicsCategory.platform
    self.addChild(character)

    //floor
    floor.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)*0.2)
    floor.setScale(2.0)
    floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.size)
    floor.physicsBody?.dynamic = false
    floor.physicsBody?.affectedByGravity = false
    floor.physicsBody?.categoryBitMask = PhysicsCategory.floor
    ///floor.physicsBody?.contactTestBitMask = not needed for now as character is set
    ///floor.physicsBody?.collisionBitMask =  not needed for now as character is set

    self.addChild(floor)

    //platform one
    platform1 = createPlatform(ImageName.platform1)
    platform1.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)*0.7)
    platform1.setScale(0.4)
    self.addChild(platform1)

    //platform two
    platform2 = createPlatform(ImageName.platform2)
    platform2.position = CGPoint(x: CGRectGetMidX(self.frame)*1.4, y: CGRectGetMidY(self.frame)*1)
    platform2.setScale(0.4)
    self.addChild(platform2)

    //orbNode
    orbNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
    orbNode.setScale(0.2)
    orbNode.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
    orbNode.physicsBody?.allowsRotation = false
    orbNode.physicsBody?.dynamic = false
    orbNode.physicsBody?.affectedByGravity = false
    orbNode.physicsBody?.categoryBitMask = PhysicsCategory.orb
    //orbNode.physicsBody?.contactTestBitMask = // not needed for now because pla
    orbNode.physicsBody?.collisionBitMask = PhysicsCategory.platform //
    self.addChild(orbNode)
}

/// Create platform (this way you can crate multiple platforms and save yourself tones of code)
func createPlatform(imageNamed: String) -> SKSpriteNode {
    let platform = SKSpriteNode(imageNamed: imageNamed)
    platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
    platform.physicsBody?.dynamic = false
    platform.physicsBody?.affectedByGravity = false
    platform.physicsBody?.categoryBitMask = PhysicsCategory.platform
    //platform.physicsBody?.contactTestBitMask =  /// not needed unless you want didBeginContact
    platform.physicsBody?.collisionBitMask = 0 /// Not needed if you tell character to collide with it
    return platform
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    character.removeActionForKey(Key.moveAction)
    character.removeActionForKey(Key.shrink)
    character.removeActionForKey(Key.rotate)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        if location.x < CGRectGetMidX(self.frame) && location.y < CGRectGetMidY(self.frame)*0.7{
            //shrinks with each movement
            characterSize-=0.005
            let moveAction = SKAction.repeatActionForever(SKAction.moveByX(-30, y: 0, duration: 0.1))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
            character.runAction(moveAction, withKey: Key.moveAction)
            character.runAction(shrink, withKey: Key.shrink)
        } else if location.x > CGRectGetMidX(self.frame) && location.y < CGRectGetMidY(self.frame)*0.7{
            //shrinks with each movement
            characterSize-=0.005
            let moveAction = SKAction.repeatActionForever(SKAction.moveByX(30, y: 0, duration: 0.1))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
            character.runAction(moveAction, withKey: Key.moveAction)
            character.runAction(shrink, withKey: Key.shrink)
        } else if location.y > character.position.y + 15  {
            //shrinks with each movement
            characterSize-=0.005
            character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
            let shrink = SKAction.repeatActionForever(SKAction.scaleTo(characterSize, duration: 0.1))
            character.runAction(shrink, withKey: Key.shrink)
        }
    }
 }

 func didBeginContact(contact: SKPhysicsContact){

      var firstBody: SKPhysicsBody
      var secondBody: SKPhysicsBody

     if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
           firstBody = contact.bodyA
           secondBody = contact.bodyB
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
        }

       /// Player with Orb
       if (firstBody.categoryBitMask == PhysicsCategory.player) && (secondBody.categoryBitMask == PhysicsCategory.orb) {

            ///Player hit orb, remove Orb 
            secondBody.node?.removeFromParent()
       }
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */

     }

 }

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