将第二个精灵与 Spritekit/Swift 中第一个精灵的物理 body 对齐

Aligning second sprite to physics body of first sprite in Spritekit/Swift

我有一个物理精灵 body。 为了移动这个精灵,在 update() 函数中,我不断地将精灵的速度设置为 150 单位向右移动,-150 向左移动。 (见附件代码。)

我有第二个物理 body,我想跟随第一个 sprite。第二个物理的坐标body在第一个物理的底部,向右20点。

我希望第二个物理 body 始终跟随第一个,但有偏移。

我的代码大部分 有效,但我注意到第一个和第二个主体之间的距离略有不同,我希望没有变化。向右移动时,它们之间的距离被压缩了一点。向左移动时,它们之间的距离会增加一点。在此处观看视频:https://www.youtube.com/watch?v=K9FhIdMwp7k

这是我使用的代码:

override func update(_ currentTime: TimeInterval) {

    switch playerDirection {
    case "stopped":
        playerSpeed = 0.0
    case "right":
        playerSpeed = 150.0
    case "left":
        playerSpeed = -150.0
    default:
        print("default")
    }

    // ball is the first sprite and footBall is the second sprite:

    ball.physicsBody?.velocity = CGVector(dx: playerSpeed, dy: ball.physicsBody!.velocity.dy)

    footBall.position = CGPoint(x: (ball.position.x + 20), y: ball.position.y - (ball.size.height / 2) + 4)

    myCam.position = CGPoint(x: round(ball.position.x), y: self.size.height / 2)

...

我一直在尝试使用 override func didSimulatePhysics() 也没有成功。

我做了一个不同的测试,只是取消了使用速度来移动玩家,而是直接增加 ball.position.x(球 = 玩家)和 footBall.position.x,当我这样做时,一切都是完美对齐。但是,如果我采用这条路线,我将不得不改变我的游戏物理在游戏其他地方的工作方式,我宁愿忽略它。

感谢观看。

如果将第二个节点添加为第一个节点的子节点,是否满足您的要求?也就是说,而不是让两者处于同一级别:

scene.addChild(ball)
scene.addChild(footBall)

替换为:

scene.addChild(ball)
ball.addChild(footBall)

然后将 footBall 位置设置为您需要的偏移量:

footBall.position = CGPoint(x: 20, y: - (ball.size.height / 2) + 4)

然后任何时候球移动 footBall 也会移动,因为它是一个子节点,因此您可以删除 footBall 的手动位置更新代码。

我使用 SKPhysicsJoint 解决了这个问题。这是我的工作代码(此时正在测试,所以仍然有点草率,但原则上是可行的):

    //add a nice player
    ball = SKSpriteNode(texture:spriteArray2[0])
    ball.size = CGSize(width: 150, height: 48)
    //ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height / 2)
    ball.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 16, height: 48))
    ball.zPosition = 1
    ball.physicsBody?.affectedByGravity = true
    ball.position = CGPoint(x: 80.0, y: 200.0)
    ball.physicsBody?.categoryBitMask = 1
    ball.physicsBody?.collisionBitMask = UInt32(2 | 32 | 256) //2 = floors, 32 and 256= doors.
    ball.physicsBody?.contactTestBitMask = 0
    ball.physicsBody?.isDynamic = true
    ball.physicsBody?.restitution = 0.0
    ball.physicsBody?.allowsRotation = false
    ball.physicsBody?.mass = 60.0
    ball.physicsBody?.friction = 0.00
    addChild(ball)

    //add a nice ball for when jumping
    footBall = SKSpriteNode(color: SKColor.blue, size: CGSize(width: 24, height: 16))
    footBall.position = ball.position
    footBall.name = "footBall"
    footBall.zPosition = 1
    footBall.physicsBody = SKPhysicsBody(circleOfRadius: 4)
    footBall.physicsBody?.affectedByGravity = false
    footBall.physicsBody?.categoryBitMask = 16
    footBall.physicsBody?.collisionBitMask = 2 // floors
    footBall.physicsBody?.contactTestBitMask = UInt32(32 | 64 | 128 | 256) // the doors bear snake
    footBall.physicsBody?.isDynamic = true
    footBall.physicsBody?.restitution = 0.0
    //footBall.physicsBody?.allowsRotation = false
    //footBall.physicsBody?.mass = 60.0
    //footBall.physicsBody?.friction = 0.00
    addChild(footBall)

    let myCGPoint = ball.position // sets joint position

    let myJoint = SKPhysicsJointFixed.joint(withBodyA: ball.physicsBody!, bodyB: footBall.physicsBody!, anchor: myCGPoint)

    scene?.physicsWorld.add(myJoint)

...

然后在更新循环中我为玩家设置速度:

    ball.physicsBody?.velocity = CGVector(dx: playerSpeed, dy: ball.physicsBody!.velocity.dy)

在我的原始代码中,在我的更新循环中,我还根据需要调整了 footBall 的位置以匹配球(球员)的位置,但在修改后的代码中,由于使用了关节,通过移动球footBall 随之移动,无需另外施加任何力或速度或改变 footBall 的 x 位置。 footBall 随行随行,效果很好。

起初,这个新方法并没有正常工作,我通过反复试验发现原因是"footBall.physicsBody?.allowsRotation = false"不能在footBall上指定为属性。但是,通过取消注释这一行它可以正常工作。

本练习的重点是使用 footBall 作为跳跃测试点,用于测试球员在跳跃过程中双脚何时伸展。所以 footBall 因此略微领先于主要球员的 body。然后我会根据跳跃的需要动态打开或关闭这个 footBall。

"foot sensor" 上的以下页面有些相关: http://gamedevwithoutacause.com/?p=1076 http://www.iforce2d.net/b2dtut/jumpability