在Spritekit / Swift中将第二个精灵对齐到第一个精灵的物理主体

时间:2017-02-07 03:59:22

标签: swift physics

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

我有第二个物理机构,我想跟随第一个精灵。第二个物理体的坐标位于第一个物体的底部,右侧是20个点。

我希望第二个物理体始终跟随第一个物理体,带有偏移量。

我的代码主要是有效,但我注意到第一个和第二个主体之间的距离略有不同,我希望没有变化。向右移动时,它们之间的距离会被压缩一点。向左移动时,它们之间的距离会略微增加。观看视频: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(ball = player)和footBall.position.x,当我这样做时,一切都完全对齐。但是,如果我采取这条路线,我将不得不改变游戏物理在游戏中其他地方的工作方式,我宁愿忽略它。

感谢您一看。

2 个答案:

答案 0 :(得分:0)

如果将第二个节点添加为第一个节点的子节点,它是否符合您的要求?也就是说,而不是两者都处于同一水平:

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的手动位置更新代码。

答案 1 :(得分:0)

我使用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的位置以匹配球(球员)位置,但是在修改后的代码中,由于使用了关节,通过移动球足球与它一起移动而不需要施加任何力或速度或改变脚球的x位置。脚踏车只是为了骑行而标记起来,这是有效的。

起初,这种新方法无法正常工作,我通过反复试验发现原因是“footBall.physicsBody?.allowsRotation = false”无法在footBall上指定为属性。通过取消注释这一行,它可以正常工作。

本练习的目的是使用足球作为跳跃测试点,以便在跳跃时玩家的脚伸展。所以足球因此略微超出了主要球员的身体。然后我会根据需要动态打开或关闭这个footBall。

“足部传感器”的以下页面有些相关: http://gamedevwithoutacause.com/?p=1076 http://www.iforce2d.net/b2dtut/jumpability