一尘不染

使用Swift + SpriteKit将节点移至手指

swift

更新:
我已经解决了这个问题,并且找到了一个比提供答案更简单的方法。我的解决方案是使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轴。当用户在屏幕上的某个位置按下并按住时,我希望SPACESHIP能够移动到手指的x坐标,而不希望在松开手指之前不停止向手指移动。如果“空格键”靠近用户的手指并且用户的手指仍被按下,则希望它逐渐减速并停止。我还希望当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);

感谢您的阅读,并期待得到答复!


阅读 231

收藏
2020-07-07

共1个答案

一尘不染

使用以下命令可以为您省去很多麻烦myShip.physicsBody.applyImpluse(vector)。它的工作方式就像您myShip在方向vector点上施加了推力一样。如果您计算的vector是从上次触摸位置到的x距离myShip,则它会加速,减速,改变方向等。与您描述的方式非常接近,因为它只会在正确的方向上进行少量推动每个update

基本上,您存储了最后一次触摸的位置,然后在update函数中计算了CGVectormyShip到的指向,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)
    }
}

您可能还想使用linearDamping和的angularDampingmyShip.physicsBody。它们将帮助确定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)
    }
}
2020-07-07