How to recognize continuous touch in Swift?

后端 未结 3 1924
余生分开走
余生分开走 2021-02-03 11:59

How can I recognize continuous user touch in Swift code? By continuous I mean that the user has her finger on the screen. I would like to move a sprite kit node to the direction

相关标签:
3条回答
  • 2021-02-03 12:27

    The most difficult thing about this process is tracking single touches within a multitouch environment. The issue with the "simple" solution to this (i.e., turn "istouched" on in touchesBegan and turn it off in touchesEnded) is that if the user touches another finger on the screen and then lifts it, it will cancel the first touch's actions.

    To make this bulletproof, you need to track individual touches over their lifetime. When the first touch occurs, you save the location of that touch and move the object towards that location. Any further touches should be compared to the first touch, and should be ignored if they aren't the first touch. This approach also allows you to handle multitouch, where the object could be made to move towards any finger currently on the screen, and then move to the next finger if the first one is lifted, and so on.

    It's important to note that UITouch objects are constant across touchesBegan, touchesMoved, and touchesEnded. You can think of a UITouch object as being created in touchesBegan, altered in touchesMoved, and destroyed in touchesEnded. You can track the phase of a touch over the course of its life by saving a reference to the touch object to a dictionary or an array as it is created in touchesBegan, then in touchesMoved you can check the new location of any existing touches and alter the object's course if the user moves their finger (you can apply tolerances to prevent jitter, e.g., if the x/y distance is less than some tolerance, don't alter the course). In touchesEnded you can check if the touch in focus is the one that ended, and cancel the object's movement, or set it to move towards any other touch that is still occurring. This is important, as if you just check for any old touch object ending, this will cancel other touches as well, which can produce unexpected results.

    This article is in Obj-C, but the code is easily ported to Swift and shows you what you need to do, just check out the stuff under "Handling a Complex Multitouch Sequence": https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/multitouch_background/multitouch_background.html

    0 讨论(0)
  • 2021-02-03 12:27

    Below is the code to drag the node around on X position (left and right), it is very easy to add Y position and do the same thing.

    let item = SKSpriteNode(imageNamed: "xx")
    var itemXposition = 50
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    // updates itemXposition variable on every touch
        for touch in touches {
            let location = touch.location(in: self)
            itemXposition = Int(location.x)
        }
    }
    
    // this function is called for each frame render, updates the position on view
    override func update(_ currentTime: TimeInterval) {
        spaceShip.position = CGPoint(x: self.itemXposition , y: 50 )
    }
    
    0 讨论(0)
  • 2021-02-03 12:30

    The basic steps

    1. Store the location of the touch events (touchesBegan/touchesMoved)
    2. Move sprite node toward that location (update)
    3. Stop moving the node when touch is no longer detected (touchesEnded)

    Here's an example of how to do that

    Xcode 8

    let sprite = SKSpriteNode(color: SKColor.white, size: CGSize(width:32, height:32))
    var touched:Bool = false
    var location = CGPoint.zero
    
    override func didMove(to view: SKView) {
        /* Add a sprite to the scene */
        sprite.position = CGPoint(x:0, y:0)
        self.addChild(sprite)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        touched = true
        for touch in touches {
            location = touch.location(in:self)
        }
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            location = touch.location(in: self)
        }
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // Stop node from moving to touch
        touched = false
    }
    
    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        if (touched) {
            moveNodeToLocation()
        }
    }
    
    // Move the node to the location of the touch
    func moveNodeToLocation() {
        // Compute vector components in direction of the touch
        var dx = location.x - sprite.position.x
        var dy = location.y - sprite.position.y
        // How fast to move the node. Adjust this as needed
        let speed:CGFloat = 0.25
        // Scale vector
        dx = dx * speed
        dy = dy * speed
        sprite.position = CGPoint(x:sprite.position.x+dx, y:sprite.position.y+dy)
    }
    

    Xcode 7

    let sprite = SKSpriteNode(color: SKColor.whiteColor(), size: CGSizeMake(32, 32))
    var touched:Bool = false
    var location = CGPointMake(0, 0)
    
    override func didMoveToView(view: SKView) {
        self.scaleMode = .ResizeFill
        /* Add a sprite to the scene */
        sprite.position = CGPointMake(100, 100)
        self.addChild(sprite)
    }
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        /* Start moving node to touch location */
        touched = true
        for touch in touches {
            location = touch.locationInNode(self)
        }
    }
    
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        /* Update to new touch location */
        for touch in touches {
            location = touch.locationInNode(self)
        }
    }
    
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        // Stop node from moving to touch
        touched = false
    }
    
    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
        if (touched) {
            moveNodeToLocation()
        }
    }
    
    // Move the node to the location of the touch
    func moveNodeToLocation() {
        // How fast to move the node
        let speed:CGFloat = 0.25
        // Compute vector components in direction of the touch
        var dx = location.x - sprite.position.x
        var dy = location.y - sprite.position.y
        // Scale vector
        dx = dx * speed
        dy = dy * speed
        sprite.position = CGPointMake(sprite.position.x+dx, sprite.position.y+dy)
    
    }
    
    0 讨论(0)
提交回复
热议问题