Swift multiple node access

拜拜、爱过 提交于 2019-12-13 04:50:01

问题


Let's say we add the same node around 1000 times like shown in the code below. Is there any way to have access of every single platform?

For e.g., if there is a collision between the PlatformCategory and the PlayerCategory, the Platform that had the collision should change its color to green and run a SKAction.

Edit: Thanks to Whirlwind, I can get the platform that collides with the player change to green, while all other stay red. Now I need to set the collision properly, which means I only want the Player to collide with Platform when it is above it.

For e.g., the Player jumps from the 1. platform to the 2. platform. While jumping, it should not collide with the 2nd platform, only after it passed it.

class GameScene: SKScene, SKPhysicsContactDelegate {

let PlayerCategory   : UInt32 = 0x1 << 1
let PlatformCategory    : UInt32 = 0x1 << 2

var Platform: SKSpriteNode!
var Player: SKSpriteNode!

override func didMoveToView(view: SKView) {
    /* Setup your scene here */
    self.physicsWorld.contactDelegate = self
    self.physicsBody?.velocity = CGVectorMake(0, 0)
    .....
    SpawnPlayer()
    generatePlatforms()
 }

func SpawnPlatforms(position: CGPoint)->SKSpriteNode{

        Platform = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: self.frame.size.width, height: 25))
        Platform.position = position
        Platform.zPosition = 1

        Platform.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: self.frame.size.width, height: 25))
        Platform.physicsBody?.dynamic = false
        Platform.physicsBody?.restitution = 0.0
        Platform.physicsBody?.allowsRotation = false
        Platform.physicsBody?.usesPreciseCollisionDetection = true

        Platform.physicsBody?.categoryBitMask = PlatformCategory
        Platform.physicsBody?.contactTestBitMask = PlayerCategory
        Platform.physicsBody?.collisionBitMask = PlayerCategory

        return Platform
}

func generatePlatforms(){

    for i in 1...1000{

        let position = CGPoint(x: self.frame.size.width / 2, y: 140 * CGFloat(i))

        let platform = SpawnPlatforms(position)

        self.addChild(platform)
    }

}

func didBeginContact(contact: SKPhysicsContact) {

    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    let platform = contact.bodyB.node as! SKSpriteNode

    switch(contactMask) {

    case PlayerCategory | PlatformCategory:
        //either the contactMask was the bro type or the ground type
        print("Contact Made0")

        if(Player.position.y >= platform.position.y && Player.position.y <= platform.position.y + Player.size.height){
        Player.physicsBody?.collisionBitMask = PlatformCategory
        platform.color = SKColor.greenColor()
        }

    default:
        return

    }

}

func didEndContact(contact: SKPhysicsContact) {

    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    switch(contactMask) {

    case PlayerCategory | PlatformCategory:
        //either the contactMask was the bro type or the ground type
        print("Contact Made0")


    default:
        return

    }
}

回答1:


As I said, to detect contact in order to change the platform's color you have to do few things:

  • Conform to SKPhysicsDelegate protocol
  • Set physicsWorld's contactDelegate property appropriately
  • Implement didBeginContact method

Conforming to SKPhysicsDelegate protocol

The syntax for this task is easy:

class GameScene: SKScene,SKPhysicsContactDelegate
{//your GameScene properties and methods go here...}

Conforming to a protocol means that class has to implement required methods from that protocol. Methods specific for SKPhysicsDelegate protocol are didBeginContact and didEndContact. If you look into header file you will see this:

protocol SKPhysicsContactDelegate : NSObjectProtocol {

    optional func didBeginContact(contact: SKPhysicsContact)
    optional func didEndContact(contact: SKPhysicsContact)
}

Even if those methods are optional, we need them in order to get contact object which describes a contact.

Setting physicsWorld contact delegate property

The only code needed for this is:

self.physicsWorld.contactDelegate = self //self is a scene (eg. GameScene)

So when a physics contact occurs in a physics world we should be notified somehow. According to the docs, a contactDelegate property is a delegate which is called when that contact occurs. By setting the scene as a contact delegate we are delegating the responsibility of contact handling to it. And this where didBeginContact should be mentioned.

Here is how you should implement it (there are probably few more ways):

func didBeginContact(contact: SKPhysicsContact) {

        var firstBody, secondBody: SKPhysicsBody

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


        if ((firstBody.categoryBitMask & CharacterCategory) != 0 &&
            (secondBody.categoryBitMask & PlatformCategory != 0)) {

            //secondBody would be a platform

        }
     }
}

Here, you can easily change the color of one platform like this:

let platform = secondBody.node as SKSpriteNode
platform.color = UIColor.redColor()

or you can change a color of all platforms:

self.enumerateChildNodesWithName("platform", usingBlock: {
                    node, stop in
                    var platformNode = node as SKSpriteNode
                    platformNode.color = UIColor.redColor()
  })

Also I see you are using the code from this question :

https://stackoverflow.com/a/31454044/3402095

So I've edited it (changed didBeginContact) to show you on that example how to change sprite's color to red.



来源:https://stackoverflow.com/questions/33658734/swift-multiple-node-access

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!