[英]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
從指着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)
}
}
你也可能會想用玩linearDamping
和angularDamping
價值觀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,否則就無法做任何事情。
在您的thuchesBegan
和touchesMoved
將觸摸位置存儲為“目標”。 在update
然后檢查您的船的位置,如果船已達到/超過目標,則將xVelocity
重置為0。
由於您只對x坐標感興趣,因此也可以只存儲touchLocation.x
。 您也可以反轉速度,但我認為這看起來很奇怪。 請注意,如果用戶再次移動手指,您的飛船將再次開始移動,因為touchMoved
將再次被觸發。
附帶說明一下,在touchesMoved
內,您還設置了shipLeft
屬性,但未在touchesBegan
設置。 如果在其他地方使用了此屬性,則應同步其使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.