Move a node to finger using Swift + SpriteKit

前端 未结 3 699
灰色年华
灰色年华 2020-12-19 13:17

UPDATE: I have solved the problem, and figured out a more simplified way to do this then the answer provided. My solution was to make the velocity of the SP

相关标签:
3条回答
  • 2020-12-19 13:52

    You can save yourself a lot of trouble by using: myShip.physicsBody.applyImpluse(vector). It works by acting as if you gave myShip a push in the direction vector points. If you calculate vector as the x distance from your last touch location to myShip, then it'll accelerate, decelerate, change direction, etc. pretty close to the way you're describing because it'll be giving it little pushes in the right direction on each update.

    Basically you store the last touch location then, in your update function, you calculate the CGVector pointing from myShip to lastTouch and apply that as an impulse to your physics body.

    Something like:

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

    You'll also probably want to play with the linearDamping and angularDamping values on myShip.physicsBody. They'll help determine how fast myShip accelerates and decelerates.

    I maxed out the values at 1.0 in my app:

    myShip.physicsBody.linearDamping = 1.0
    myShip.physicsBody.angularDamping = 1.0
    

    If myShip doesn't stop fast enough for you, you can also try applying some breaking in your update function:

    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)
        }
    }
    
    0 讨论(0)
  • 2020-12-19 13:56

    In your thuchesBegan and touchesMoved store the touch location as the "target". In the update then check the position of your ship and reset the xVelocity to 0 if the ship has reached/passed the target.

    Since you are only interested in the x coordinate you could also store just touchLocation.x. You can also reverse the velocity but I think that would look strange. Note that if the user moves the finger again, your ship will start moving again because the touchMoved will be triggered again.

    On a side note, within touchesMoved you are also setting the shipLeft property but this is not set in your touchesBegan. If this property is used elsewhere you should sync its use.

    0 讨论(0)
  • 2020-12-19 14:00

    For 2017 here's the easy way to do what is explained in the correct answer here.

    There's no need to store the previous position, it is given to you...

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

    That's it.


    Two notes. (A) properly you should divide the delta distance by the deltaTime to get the correct impulse. If you're a hobbyist really just multiply by "about 100" and you'll be fine. (B) note that of course you will need an extension or function to convert CGPoint to CGVector, it's impossible to do anything without that.

    0 讨论(0)
提交回复
热议问题