使用Swift + SpriteKit将节点移动到手指

时间:2014-08-13 04:17:12

标签: ios swift sprite-kit

更新:我已经解决了问题,并找到了更简单的方法,然后提供答案。我的解决方案是使SPACESHIP的速度等于我手指触摸的距离。为了更快地移动,您可以将此速度乘以常数。在这种情况下,我使用了16.我还摆脱了在touchesEnd事件中将lastTouch设置为nil。这样,即使我松开手指,船仍会停下来。

override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
    if let touch = lastTouch {
        myShip.physicsBody.velocity = CGVector(dx: (lastTouch!.x - myShip.position.x) * 16, dy: 0)
    }

}

===============================

我有一个SPACESHIP节点,其移动仅限于X轴。当用户在屏幕上某处按下并且HOLDS时,我希望SPACESHIP能够移动到手指的x坐标,并且在手指释放之前不会停止向手指移动。如果SPACESHIP靠近用户手指并且仍然按下用户手指,我希望它逐渐减速并停止。我还希望在SPACESHIP改变方向,开始和停止时应用这种平滑运动。

我正在努力找出最佳方法。

到目前为止,我已经创建了节点并且它正确移动,但是存在一个问题:如果我按下屏幕并按住,船最终会越过我的手指并继续移动。这是因为只有在我移动手指时才会触发改变船舶方向的逻辑。所以基本上,我的手指在船上移动以改变船只的方向,但如果船越过我的静止手指,它就不会改变方向

我需要SPACESHIP节点识别它何时越过我的静止手指,并根据它与我手指的距离来改变其方向或停止。

以下是相关代码:

第1部分当用户按下时,找出触摸的来源并使用力度相应地移动myShip(SPACESHIP)

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    /* Called when a touch begins */
    let touch = touches.anyObject() as UITouch
    let touchLocation = touch.locationInNode(self)

    if (touchLocation.x < myShip.position.x) {
        myShip.xVelocity = -200
    } else {
        myShip.xVelocity = 200
    }
}

第2部分当用户移动手指时,触发一个事件,检查手指是否已移动到船的另一侧。如果是这样,改变船的方向。

override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
    let touch = touches.anyObject() as UITouch
    let touchLocation = touch.locationInNode(self)

    //distanceToShip value will eventually be used to figure out when to stop the ship
    let xDist: CGFloat = (touchLocation.x - myShip.position.x)
    let yDist: CGFloat = (touchLocation.y - myShip.position.y)
    let distanceToShip: CGFloat = sqrt((xDist * xDist) + (yDist * yDist))

    if (myShip.position.x < touchLocation.x) && (shipLeft == false) {
        shipLeft = true
        myShip.xVelocity = 200
    }

    if (myShip.position.x > touchLocation.x) && (shipLeft == true) {
        shipLeft = false
        myShip.xVelocity = -200
    }

}

第3部分当用户从屏幕上松开手指时,我希望船只停止移动。

override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
    myShip.xVelocity = 0
}

第4部分更新船舶位置的更新事件

    override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
    let rate: CGFloat = 0.5; //Controls rate of motion. 1.0 instantaneous, 0.0 none.
    let relativeVelocity: CGVector = CGVector(dx:myShip.xVelocity - myShip.physicsBody.velocity.dx, dy:0);
    myShip.physicsBody.velocity = CGVector(dx:myShip.physicsBody.velocity.dx + relativeVelocity.dx*rate, dy:0);

感谢阅读,期待回复!

3 个答案:

答案 0 :(得分:3)

使用:myShip.physicsBody.applyImpluse(vector)可以省去很多麻烦。它的工作原理就像你向myShip方向推动vector一样。如果您将vector计算为距离上次触摸位置到myShip的x距离,那么它会加速,减速,改变方向等,非常接近您描述的方式,因为它会在每个update上向正确的方向推动它。

基本上,您存储了最后一个触摸位置,然后在update函数中计算从CGVector指向myShip的{​​{1}}并将其作为您的推动应用物理机构。

类似的东西:

lastTouch

您可能还想在var lastTouch: CGPoint? = nil override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { let touch = touches.anyObject() as UITouch let touchLocation = touch.locationInNode(self) lastTouch = touchLocation } override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) { let touch = touches.anyObject() as UITouch let touchLocation = touch.locationInNode(self) lastTouch = touchLocation } // Be sure to clear lastTouch when touches end so that the impulses stop being applies override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) { lastTouch = nil } override func update(currentTime: CFTimeInterval) { // Only add an impulse if there's a lastTouch stored if let touch = lastTouch { let impulseVector = CGVector(touch.x - myShip.position.x, 0) // If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range myShip.physicsBody.applyImpluse(impulseVector) } } 上使用linearDampingangularDamping值。它们将帮助确定myShip.physicsBody加速和减速的速度。

我在我的应用中myShip的最大值:

1.0

如果myShip.physicsBody.linearDamping = 1.0 myShip.physicsBody.angularDamping = 1.0 没有足够快地停止,您还可以尝试在myShip函数中应用一些中断:

update

答案 1 :(得分:2)

对于2017年,这里可以轻松地执行正确答案中解释的内容。

没有必要存储以前的位置,它是给你的 ......

  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    let t: UITouch = touches.first! as UITouch

    let l =      t.location(in: parent!)
    let prev =   t.previousLocation(in: parent!)

    let delta = (l - prev).vector

    physicsBody!.applyImpulse(delta)
 }

就是这样。

两个音符。(A)你应该正确地将delta距离除以deltaTime以获得正确的脉冲。如果你是一个业余爱好者真的只是乘以“约100”,你会没事的。 (B)请注意,当然你需要一个扩展或功能来将CGPoint转换为CGVector,没有它就不可能做任何事情。

答案 2 :(得分:-1)

thuchesBegantouchesMoved存储触摸位置作为&#34;目标&#34;。在update然后检查您的船的位置,如果船已经到达/超过了目标,则将xVelocity重置为0.

由于您只对x坐标感兴趣,因此您也可以只存储touchLocation.x。你也可以扭转速度,但我觉得这看起来很奇怪。请注意,如果用户再次移动手指,您的船只将再次开始移动,因为touchMoved将再次触发。

在旁注上,touchesMoved内您还设置了shipLeft属性,但未在touchesBegan中设置。如果在其他地方使用此属性,则应同步其使用。