Ios 使用Swift+将节点移动到手指上;斯皮特基特

Ios 使用Swift+将节点移动到手指上;斯皮特基特,ios,swift,sprite-kit,Ios,Swift,Sprite Kit,更新:我已经解决了这个问题,并找到了一种比答案更简单的方法。我的解决办法是使宇宙飞船的速度等于我用手指触摸的距离。为了更快的移动,你可以将这个速度乘以一个常数。在本例中,我使用了16。在TouchSend事件中,我还将lastTouch设置为零。这样,即使我松开手指,船也会停下来 override func update(currentTime: CFTimeInterval) { /* Called before each frame is rendered */ if let tou

更新:我已经解决了这个问题,并找到了一种比答案更简单的方法。我的解决办法是使宇宙飞船的速度等于我用手指触摸的距离。为了更快的移动,你可以将这个速度乘以一个常数。在本例中,我使用了16。在TouchSend事件中,我还将lastTouch设置为零。这样,即使我松开手指,船也会停下来

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)
    }

}
===============================

我有一个太空船节点,它的运动限制在X轴上。当用户按住屏幕上的某个位置时,我希望飞船能够移动到手指的x坐标,并且在手指松开之前不会停止向手指移动。如果飞船靠近用户的手指,但用户的手指仍被按下,我希望它逐渐减速并停止。我还希望在宇宙飞船改变方向、启动和停止时应用这种平滑的运动

我正试图找出最好的方法来做到这一点

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

我需要太空船节点识别它何时越过我静止的手指,并根据它离我手指的距离改变方向或停止

以下是相关代码:

第1部分:当用户按下时,找出触摸的来源,并使用速度相应地移动我的飞船(太空船)

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
    }
}
第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);

感谢阅读,期待回复

在您的
thuchesBegan
touchsmoved
中,将触摸位置存储为“目标”。在
更新
中,然后检查您的船舶的位置,如果船舶已达到/通过目标,则将
xVelocity
重置为0

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


另一方面,在
touchsmoved
中,您还设置了
shipleet
属性,但这不是在
touchsbegind
中设置的。如果此属性在其他地方使用,您应该同步它的使用。

通过使用:
myShip.physicsBody.applyImpluse(vector)
,您可以省去很多麻烦。它的工作原理是,好像你给了
myShip
一个方向
vector
点的推力。如果你计算
向量
作为你最后一次触摸位置到
myShip
的x距离,那么它会加速、减速、改变方向等。非常接近你描述的方式,因为它会在每次
更新
时向正确的方向轻轻推动

基本上,您存储最后一次触摸的位置,然后在
update
函数中,计算
CGVector
myShip
指向
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)
    }
}
您可能还需要在
myShip.physicsBody
上使用
linearDamping
angularsdamping
值。它们将帮助确定myShip的加速和减速速度

我在我的应用程序中最大化了
1.0
处的值:

myShip.physicsBody.linearDamping = 1.0
myShip.physicsBody.angularDamping = 1.0
如果
myShip
的停止速度不够快,您也可以尝试在
update
功能中应用一些中断:

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)
    } else if !myShip.physicsBody.resting {
        // Adjust the -0.5 constant accordingly
        let impulseVector = CGVector(myShip.physicsBody.velocity.dx * -0.5, 0)
        myShip.physicsBody.applyImpulse(impulseVector)
    }
}

对于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)
 }
override func touchesMoved(touch:Set,带有事件:UIEvent?){
让t:UITouch=touch.first!作为UITouch
设l=t.location(in:parent!)
让prev=t.previousLocation(在:父对象中!)
设delta=(l-prev).vector
physicsBody!.applyImpulse(增量)
}
就这样



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

哇,首先,非常感谢您花时间给出如此详细的回答!你太棒了!在触摸结束时将lastTouch更改为nil是一种天才之举——这也是这种新语言力量的一个很好的例子。我被什么东西卡住了。出于某种原因,我在更新函数中遇到一个错误:“让pulseVector:CGVector=CGVector(lastTouch.x-myShip.position.x,0)”它说CGPoint没有名为x的成员。发生了什么事?不客气!设置
pulsevector
时遇到的问题是我的输入错误,对此表示抱歉。它应该是
touch
,而不是
lastTouch
。我编辑了我的答案并修正了。迈克,非常感谢!我用触摸代替了上次触摸,程序运行了。这给了我一个很好的起点来进一步调整它。最后的几个问题/想法。在第三个示例部分中,您是指“myShip.physicsBody.applyImpulse(pulseVector)”而不是pulseDirection吗?此外,我对“if let touch=lastTouch”sta感到困惑
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)
    } else if !myShip.physicsBody.resting {
        // Adjust the -0.5 constant accordingly
        let impulseVector = CGVector(myShip.physicsBody.velocity.dx * -0.5, 0)
        myShip.physicsBody.applyImpulse(impulseVector)
    }
}
  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)
 }