簡體   English   中英

使用Swift + SpriteKit將節點移至手指

[英]Move a node to finger using Swift + SpriteKit

更新:我已經解決了這個問題,並且找到了一個更簡單的方法來做到這一點,然后提供了答案。 我的解決方案是使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改變方向,開始和停止時應用這種平滑運動。

我正在嘗試找出最佳方法。

到目前為止,我已經創建了節點並且它可以正確移動,但是存在一個問題:如果我按下屏幕並按住不放,船最終將越過我的手指並繼續移動。 這是因為僅當我移動手指時才會觸發更改船方向的邏輯。 因此,基本上,將我的手指移到船上以改變船的方向是可行的,但是如果船越過我的靜止指頭,則不會改變方向

我需要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);

感謝您的閱讀,並期待得到答復!

您可以使用myShip.physicsBody.applyImpluse(vector)myShip.physicsBody.applyImpluse(vector)麻煩。 它的工作方式就像您向myShip推動方向vector點一樣。 如果您將vector計算為從上次觸摸位置到myShip的x距離,則它將加速,減速,改變方向等。與您描述的方式非常接近,因為它將在右側進行小的推動每次update方向。

基本上你存儲的最后觸摸位置,然后,在update功能時,您計算CGVector從指着myShiplastTouch和應用,作為一種沖動,你的物理身體。

就像是:

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功能中應用一些中斷:

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

而已。


兩個筆記。 (A)正確地,應將增量距離除以deltaTime,以獲得正確的脈沖。 如果您是一個業余愛好者,只需乘以“大約100”就可以了。 (B)請注意,您當然需要擴展程序或函數才能將CGPoint轉換為CGVector,否則就無法做任何事情。

在您的thuchesBegantouchesMoved將觸摸位置存儲為“目標”。 update然后檢查您的船的位置,如果船已達到/超過目標,則將xVelocity重置為0。

由於您只對x坐標感興趣,因此也可以只存儲touchLocation.x 您也可以反轉速度,但我認為這看起來很奇怪。 請注意,如果用戶再次移動手指,您的飛船將再次開始移動,因為touchMoved將再次被觸發。

附帶說明一下,在touchesMoved內,您還設置了shipLeft屬性,但未在touchesBegan設置。 如果在其他地方使用了此屬性,則應同步其使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM