如何通过接触从 SKNodes 获取一个实体 SKPhysicsBody 或 SKNode 对象?

How to obtain one solid SKPhysicsBody or SKNode object from SKNodes with contact?

我正在尝试创建类似 House Stack 的游戏 (https://apps.apple.com/gb/app/house-stack/id1458713825?l),但在分配物理机制时遇到问题。

我的主要问题是当节点掉落并与其他对象接触并在它们达到特定高度时以实体形式向下移动时创建单个对象。

我尝试创建节点之间有接触的固定关节,并在最后一个节点位置 y = 0 时移动它们,但固定关节没有像我想的那样工作。节点像蛇一样晃动,移动时崩溃。

还尝试创建一个新的具有接触的单个对象并计算其高度,但无法弄清楚我应该如何使用 init(bodies: [SKPhysicsBody])。即使我将 physicsbody 属性分配给新对象,我也无法测量或调用其高度并使用另一个节点接触更新主体。

任何想法或例子都很好。这是我的代码,提前致谢。

SKNode(在touchesBegan中多次创建同一个节点):

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let Node1 = SKSpriteNode(imageNamed: "Object1")
        Node1.position = MovingObject.position
        Node1.zPosition = 2
        Node1.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: Node1.size.width, height: Node1.size.height))
        Node1.physicsBody?.friction = 0.9
        Node1.physicsBody?.restitution = 0.1
        Node1.physicsBody?.allowsRotation = true
        Node1.physicsBody!.contactTestBitMask = Node1.physicsBody!.collisionBitMask
        Node1.physicsBody!.categoryBitMask = Node1Category
        addChild(Node1)
    }

移动物体:

Inside GameScene;
var MovingObject = SKSpriteNode(imageNamed: "Object1")
let ObjectMove = SKAction.sequence([(SKAction.moveBy(x: 200, y: 0, duration: 0.5)),(SKAction.moveBy(x: -400, y: 0, duration: 1)),(SKAction.moveBy(x: 200, y: 0,  duration: 0.5))])

Inside override func didMove(to view: SKView);
        MovingObject.position = CGPoint(x: 0, y: frame.maxY * 0.55)
        MovingObject.zPosition = 1
        MovingObject.run(SKAction.repeatForever(ObjectMove))
        addChild(MovingObject)

关节和动作:

func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.node?.name == "Node1" && contact.bodyB.node?.name == "Node1"
        {
            let joint2 = SKPhysicsJointFixed.joint(withBodyA: contact.bodyA , bodyB: contact.bodyB, anchor: CGPoint(x: contact.contactPoint.x, y:contact.contactPoint.y))
            
            let pos2 = (contact.bodyA.node?.position.x)!-(contact.bodyB.node?.position.x)!

            if pos2 <= Node1.size.width * 0.5 && pos2 >= -Node1.size.width * 0.5{
                physicsWorld.add(joint2)
            }

            if (contact.bodyB.node?.position.y)! >= 0 {
                let movenodedown = SKAction.moveBy(x: 0, y: -Node1.size.height, duration: 0.5)
                contact.bodyB.node?.run(movenodedown)
                ground.run(movenodedown)     
            }   
        }

对于类似问题需要启发的人;

我通过同时使用 enumerateChildNodes(withName:using:)physicsBody.isDynamic = false 而不是固定关节找到了解决方案。代码如下。

func didBegin(_ contact: SKPhysicsContact)
    {
if contact.bodyA.node?.name == "Node1" && contact.bodyB.node?.name == "Node1"
        {
let pos2 = (contact.bodyA.node?.position.x)!-(contact.bodyB.node?.position.x)!

            if pos2 <= Node1.size.width * 0.5 && pos2 >= -Node1.size.width * 0.5.
            {
                contact.bodyB.node?.physicsBody?.isDynamic = false
                contact.bodyA.node?.physicsBody?.collisionBitMask = 0
                contact.bodyA.node?.physicsBody?.contactTestBitMask = 0
                
                if (contact.bodyB.node?.position.y)! >= 0
                {
                    let movenodesdown = SKAction.moveBy(x: 0, y: Node1.size.height , duration: 0.5)

                    enumerateChildNodes(withName: "Node1") { (nodes, stop) in
                        let Node1 = nodes as! SKSpriteNode
                        Node1.run(movenodesdown)
                    }
                }
            }
        }
    }