Swift多节点访问

Posted

技术标签:

【中文标题】Swift多节点访问【英文标题】:Swift multiple node access 【发布时间】:2015-11-11 19:52:05 【问题描述】:

假设我们添加了大约 1000 次相同的节点,如下面的代码所示。有什么方法可以访问每个平台吗?

例如,如果 PlatformCategoryPlayerCategory 之间发生冲突,则发生冲突的平台应将其颜色更改为绿色并运行 SKAction

编辑:感谢 Whirlwind,我可以让与玩家发生碰撞的平台变为绿色,而所有其他平台保持红色。现在我需要正确设置碰撞,这意味着我只希望Player 在它上方时与Platform 碰撞。

例如,玩家从 1. 平台跳到 2. 平台。跳跃时,不能撞到第二个平台,只有经过第二个平台。

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

    

【问题讨论】:

这段代码没有意义,因为在很少创建平台之后,下一个平台将不在屏幕上。接下来是 SpawnPlatforms 方法有问题,因为您没有在本地创建平台节点(或者您不小心错过了那部分代码)。关于实际问题...要检测平台和玩家之间的接触,您必须遵守 SKPhysicsContactDelegate 协议,并将physicsWorld.contactDelegate 属性设置为您的场景。之后,您必须实现 didBeginContact 方法。如果您需要代码示例,请告诉我。 SpawnPlatforms 将在屏幕外创建节点,因为它们都将在 y 轴上向下移动(相机已设置)。我知道如何检测 2 个对象之间的碰撞,唯一的问题在于我创建了 1000 个 SKSpriteNode 节点,而我不能为例如改变与玩家碰撞的平台的颜色,而不是全部。 是的,但它仍然不是一个高效的解决方案...因为屏幕外节点仍在节点树中并占用资源...理想情况下,您应该在屏幕顶部上方生成一个平台,然后向下移动所有平台,然后从底部移除第一个平台。您可以更改平台的颜色。您在 didBeginContact 方法中执行此操作... 碰撞发生时您可以访问平台。为什么你需要一次访问它们?如果您出于某种原因想一次访问它们,您可以将它们全部命名为“Platform”,并以“Platform”的名称枚举子项。我觉得你想多了。只需从SKPhysicsContact 获得平台,您就可以在didBeginContact 获得。 【参考方案1】:

正如我所说,要检测接触以更改平台的颜色,您必须做几件事:

符合 SKPhysicsDelegate 协议 适当设置physicsWorld 的contactDelegate 属性 实现 didBeginContact 方法

符合 SKPhysicsDelegate 协议

这个任务的语法很简单:

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

符合协议意味着类必须实现该协议所需的方法。 SKPhysicsDelegate 协议的特定方法是 didBeginContact 和 didEndContact。如果你查看头文件,你会看到:

protocol SKPhysicsContactDelegate : NSObjectProtocol 

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

即使这些方法是可选的,我们也需要它们来获取描述联系人的联系人对象。

设置physicsWorld联系人委托属性

唯一需要的代码是:

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

因此,当物理世界中发生物理接触时,我们应该以某种方式得到通知。根据文档,contactDelegate 属性是在发生联系时调用的委托。通过将场景设置为联系人代表,我们将处理联系人的责任委托给它。这应该提到 didBeginContact。

这是你应该如何实现它(可能还有更多的方法):

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

        
     

在这里,您可以像这样轻松更改一个平台的颜色:

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

或者您可以更改所有平台的颜色:

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

我还看到你正在使用这个问题的代码:

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

所以我对其进行了编辑(更改了 didBeginContact),以在该示例中向您展示如何将精灵的颜色更改为红色。

【讨论】:

首先,很抱歉回复晚了。其次,现在我可以将与玩家碰撞的平台的颜色更改为绿色,而不是更改所有平台的颜色。但是我怎样才能实现播放器仅在其上方时才与平台发生碰撞呢?我编辑了我的代码。 @Albert 你的意思是你想在玩家降落在平台表面后改变平台的颜色? 不,我得到了所有的颜色。我希望只有当玩家在平台上方时才有玩家和平台交叉点,所以如果玩家从底部跳到 1. 平台(通过它),它只会在他通过它后发生碰撞。 @Albert 这里不是已经解决了吗:***.com/a/31454044/3402095 玩家从第一个平台跳下后,会经过第二个平台,落地后停留在上面... 不,因为这段代码实际上不起作用,在大约 3-4 个平台之后,播放器不再与任何东西发生碰撞,有时从一开始就发生了。

以上是关于Swift多节点访问的主要内容,如果未能解决你的问题,请参考以下文章

如何访问 SpriteKit 场景编辑器参考节点上自定义类中包含的 Swift 中的变量?

分布式存储支持多节点,节点是啥,一个磁盘还是一个主控?

Swift 树结构、编码和访问节点

RabbitMQ上手记录–part 4-节点集群(单机多节点)

java中如何读取xml中数据。多节点的。给我一个例子,谢谢。

Java多线程有序性-动力节点