当两个 SK 节点相交时标记

flag when two sk nodes intersect

提问人:Bike Smith 提问时间:10/30/2023 最后编辑:Bike Smith 更新时间:11/6/2023 访问量:74

问:

在我的 swift 代码中,在一个名为 stick 的节点周围移动的左右按钮下方。我希望用户点击使摇杆与边界相交的按钮。debug 部分将打印 “flag”。我知道在 uikit 中有一个相交命令,但我不知道 sprite kit。蓝绿色是界限

在此处输入图像描述


import SpriteKit
import GameplayKit


class GameScene: SKScene , SKPhysicsContactDelegate {
    
    var stick: SKSpriteNode!
    var leftButton: SKSpriteNode!
    var rightButton: SKSpriteNode!
    var bounds: SKSpriteNode!
    
    
    var objectThatHandlesContactLogic: ContactDetectionLogic!

   
    
    override func didMove(to view: SKView) {
        physicsWorld.contactDelegate = self  // << from the previous step

          backgroundColor = SKColor.white
              
        objectThatHandlesContactLogic = ContactDetectionLogic()
           
        physicsWorld.contactDelegate = objectThatHandlesContactLogic
        
        // Create left and right buttons
        leftButton = SKSpriteNode(color: .blue, size: CGSize(width: 100, height: 50))
        leftButton.position = CGPoint(x: size.width * 0.2, y: size.height * 0.1)
        addChild(leftButton)
        
        rightButton = SKSpriteNode(color: .red, size: CGSize(width: 100, height: 50))
        rightButton.position = CGPoint(x: size.width * -0.1, y: size.height * 0.1)
        addChild(rightButton)
          // Create and position the stick
        physicsWorld.contactDelegate = self  // << from the previous step

            backgroundColor = SKColor.white
                
            // Create and position the stick
            let stickSize = CGSize(width: 160, height: 20)
            stick = SKSpriteNode(color: .brown, size: stickSize)
            stick.position = CGPoint(x: size.width * -0.2, y: size.height * -0.1)
            addChild(stick)
                
            // Add physics body to stick
            stick.physicsBody = SKPhysicsBody(rectangleOf: stickSize)
            stick.physicsBody!.categoryBitMask = 0b0000  // Means the stick doesn't belong to any category (all zeros)
            stick.physicsBody!.collisionBitMask = 0b0000  // Means the stick collides with no category, i.e., doesn't collide with anything (all zeros)
            stick.physicsBody!.contactTestBitMask = 0b0001  // Means the stick will only collide with nodes belonging to category 0001 (in binary. This also happens to mean category "1" in decimal)
            
            stick.physicsBody!.affectedByGravity = false  // since you dont want it falling off of the screen
            
            // Create and position the bounds box
            let boundsSize = CGSize(width: 150, height: 300)
            bounds = SKSpriteNode(color: .systemTeal, size: boundsSize)
            bounds.position = CGPoint(x: size.width * -0.4, y: size.height * -0.2)
            addChild(bounds)
                
            // add physics body to bounds
            bounds.physicsBody = SKPhysicsBody(rectangleOf: boundsSize)
            bounds.physicsBody!.collisionBitMask = 0b0000  // Means bounds collides with no category (all zeros)
            bounds.physicsBody!.categoryBitMask = 0b0001  // Means the bounds belongs to category 0001 (in binary. Which again, translates to "1" in decimal), which if you remember, is what we set the stick to collide with

            // the default value for bounds.physicsBody!.contactBitMask
            // is already 0b0000 so no need to set it explicitly here.
            // (You could do it for consistency sake if you'd like but it
            // wouldn't matter since you're setting it to the same value it
            // already is)
            
            bounds.physicsBody!.affectedByGravity = false  // since you dont want it falling off of the screen

            // ...blah blah blah all the other code
    }
    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)

            if leftButton.contains(location) {
                // Rotate the stick counterclockwise
                let rotateAction = SKAction.rotate(byAngle: CGFloat(Double.pi / 4), duration: 1.0)
                stick.run(rotateAction)
                print("hit Left")
            }

            if rightButton.contains(location) {
                // Rotate the stick clockwise
                let rotateAction = SKAction.rotate(byAngle: -CGFloat(Double.pi / 4), duration: 1.0)
                stick.run(rotateAction)
            }
        }
    }

}


class ContactDetectionLogic: NSObject, SKPhysicsContactDelegate {  // << Make sure you also add NSObject
    // if you add this function, this function will be called when a contact between two nodes begins
    func didBegin(_ contact: SKPhysicsContact) {
        print("flag")
    }
}


在这种情况下,我不认为相交是一种选择。

swift sprite-kit 重叠 skspritenode 连接

评论


答:

0赞 rayaantaneja 10/30/2023 #1

步骤1:

SpriteKit 有一个检测系统,可以告诉您两个节点何时相互接触。通过将接触检测回调符合类,可以将该类添加到该类。SKPhysicsContactDelegate

例如。

class ContactDetectionLogic: NSObject, SKPhysicsContactDelegate {  // << Make sure you also add NSObject
    // if you add this function, this function will be called when a contact between two nodes begins
    func didBegin(_ contact: SKPhysicsContact) {
        print("flag")
    } 
}

您甚至可以使自己的协议符合此协议!(我通常这样做,我认为这是非常典型的做法)GameScene

class GameScene: SKScene, SKPhysicsContactDelegate {  // << Here we add the conformance
    // ...blah blah blah all the other code

    func didBegin(_ contact: SKPhysicsContact) {
        print("flag")
    }
}

步骤2:

确定哪个对象将接收回调后,请确保将此对象分配给 .delegatephysicsWorld

例如:

var objectThatHandlesContactLogic: ContactDetectionLogic!

override func didMove(to view: SKView) {
    objectThatHandlesContactLogic = ContactDetectionLogic()
    physicsWorld.delegate = objectThatHandlesContactLogic

    backgroundColor = SKColor.white
    // ...blah blah blah all the other code
}

或者,如果你使场景本身符合协议(这同样是更典型的做法),你会这样做:

override func didMove(to view: SKView) {
    physicsWorld.delegate = self  // This is also much cleaner imo

    backgroundColor = SKColor.white
    // ...blah blah blah all the other code
}

步骤3:

添加委托后,您必须配置哪些接触的节点将触发它们。在你的例子中,它是棍子和边界,所以你这样做,我们为每个它们添加物理体:

override func didMove(to view: SKView) {
    physicsWorld.contactDelegate = self  // << from the previous step

    backgroundColor = SKColor.white
        
    // Create and position the stick
    let stickSize = CGSize(width: 160, height: 20)
    stick = SKSpriteNode(color: .brown, size: stickSize)               
    stick.position = CGPoint(x: size.width * -0.2, y: size.height * -0.1)
    addChild(stick)
        
    // Add physics body to stick
    stick.physicsBody = SKPhysicsBody(rectangleOf: stickSize)
    stick.physicsBody!.categoryBitMask = 0b0000  // Means the stick doesn't belong to any category (all zeros)
    stick.physicsBody!.collisionBitMask = 0b0000  // Means the stick collides with no category, i.e., doesn't collide with anything (all zeros)
    stick.physicsBody!.contactTestBitMask = 0b0001  // Means the stick will only collide with nodes belonging to category 0001 (in binary. This also happens to mean category "1" in decimal)
    
    stick.physicsBody!.affectedByGravity = false  // since you dont want it falling off of the screen 
    
    // Create and position the bounds box
    let boundsSize = CGSize(width: 150, height: 300)
    bounds = SKSpriteNode(color: .systemTeal, size: boundsSize)
    bounds.position = CGPoint(x: size.width * -0.4, y: size.height * -0.2)
    addChild(bounds)
        
    // add physics body to bounds
    bounds.physicsBody = SKPhysicsBody(rectangleOf: boundsSize)
    bounds.physicsBody!.collisionBitMask = 0b0000  // Means bounds collides with no category (all zeros)
    bounds.physicsBody!.categoryBitMask = 0b0001  // Means the bounds belongs to category 0001 (in binary. Which again, translates to "1" in decimal), which if you remember, is what we set the stick to collide with

    // the default value for bounds.physicsBody!.contactBitMask 
    // is already 0b0000 so no need to set it explicitly here.
    // (You could do it for consistency sake if you'd like but it 
    // wouldn't matter since you're setting it to the same value it
    // already is)
    
    bounds.physicsBody!.affectedByGravity = false  // since you dont want it falling off of the screen

    // ...blah blah blah all the other code
}

现在,每当联系开始时,您都应该得到一个打印件,上面写着“标志”。

希望这有帮助!如果您对联系系统的工作原理有疑问,请发表评论,我会回答他们

评论

0赞 Bike Smith 10/31/2023
在课堂上 contactDectectionLogic 它希望我添加 10 个资金,比如 func 执行。我该怎么办?
0赞 rayaantaneja 10/31/2023
哦,对不起,我打错了字。加。您的自定义类应该是 basic 的子类。很抱歉,我现在正在更新我的答案。让它知道你是否让它工作ContactDetectionLogic: NSObject, SKPhysicsContactDelegateNSObject
0赞 Bike Smith 11/2/2023
当代码在第一秒内编译完成时,stick 和 bounds 都会直接在屏幕外动画,有什么方法可以阻止这种情况?
0赞 rayaantaneja 11/2/2023
我刚刚意识到你可能没有禁用它们的重力。因此,将每个物理体中的属性设置为affectedByGravityfalse
0赞 rayaantaneja 11/2/2023
我再次更新了我的答案。非常抱歉给您带来麻烦,但它现在可以 100% 工作