How to control sprite using swiping gestures so sprite can move along x axis

178 Views Asked by At

At the moment I have a game in which the sprite can be controlled and moved along the x axis (with a fixed y position) using the accelerometer of the device. I wish to change this so the user can control the sprite by dragging on the screen like in popular games such as snake vs.block.

I've already tried using the touches moved method which gives the correct effect, although the sprite first moves to the location of the users touch which I don't want.

Below is the environment I've been using to experiment, the touches moved gives the correct type of control I want although I can't seem to figure out how to stop the sprite first moving to the location of the touch before the swipe/drag

import SpriteKit
import GameplayKit

var player = SKSpriteNode()
var playerColor = UIColor.orange
var background = UIColor.black
var playerSize = CGSize(width: 50, height: 50)
var touchLocation = CGPoint()
var shape = CGPoint()
class GameScene: SKScene {

  override func didMove(to view: SKView) {
    self.backgroundColor = background

    spawnPlayer()    
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
        let touchLocation = touch.location(in: self)
        player.position.x = touchLocation.x
    }
}

func spawnPlayer(){    
    player = SKSpriteNode(color: playerColor, size: playerSize)
    player.position = CGPoint(x:50, y: 500)

    self.addChild(player)
}

override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered
}

In summary, I'm looking for the same method of controlling a sprite as in snakes vs blocks

2

There are 2 best solutions below

0
KissTheCoder On

Hey so you have the right idea, you need to store a previous touchesMovedPoint. Then use it to determine how far your finger has moved each time touchesMoved has been called. Then add to the player's current position by that quantity.

var lastTouchLoc:CGPoint = CGPoint()

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
        let touchLocation = touch.location(in: self)

        let dx = touchLocation.x - lastTouchLoc.x
        player.position.x += dx // Change the players current position by the distance between the previous touchesMovedPoint and the current one.
        lastTouchLoc.x = touchLocation.x // Update last touch location
    }
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
         // When releasing the screen from point "E" we don't want dx being calculated from point "E".
        // We want dx to calculate from the most recent touchDown point
        let initialTouchPoint =  touch.location(in: self)
        lastTouchLoc.x = initialTouchPoint.x
    }
}
4
Knight0fDragon On

You want to use SKAction.move to perform what you want.

func distance(from lhs: CGPoint, to rhs: CGPoint) -> CGFloat {
    return hypot(lhs.x.distance(to: rhs.x), lhs.y.distance(to: rhs.y))
}


override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
        let touchLocation = touch.location(in: self)
        let speed = 100/1  //This means 100 points per second
        let duration = distance(player.position,touchLocation) / speed //Currently travels 100 points per second, adjust if needed
        player.run(SKAction.move(to:touchLocation, duration:duration),forKey:"move")
    }
}

What this does is it will move your "snake" to the new location at a certain duration. To determine duration, you need to figure out how fast you want your "snake" to travel. I currently have it set up to where it should take 1 second to move 100 points, but you may want to adjust that as needed.