Как управлять спрайтом с помощью жестов смахивания, чтобы спрайт мог двигаться вдоль оси X

На данный момент у меня есть игра, в которой спрайтом можно управлять и перемещать по оси x (с фиксированным положением y) с помощью акселерометра устройства. Я хочу изменить это, чтобы пользователь мог управлять спрайтом, перетаскивая его по экрану, как в популярных играх, таких как змея против блока.

Я уже пробовал использовать метод перемещения касаний, который дает правильный эффект, хотя спрайт сначала перемещается в место касания пользователя, чего я не хочу.

Ниже приведена среда, которую я использовал для экспериментов, перемещенные касания дают правильный тип управления, который я хочу, хотя я не могу понять, как остановить спрайт, сначала перемещающийся к месту касания перед пролистыванием/перетаскиванием

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
}

В общем, я ищу тот же метод управления спрайтом, что и в змеях против блоков.


person Tobias    schedule 26.01.2019    source источник


Ответы (2)


Эй, у вас есть правильная идея, вам нужно сохранить предыдущий touchesMovedPoint. Затем используйте его, чтобы определить, как далеко перемещается ваш палец каждый раз, когда вызывается touchesMoved. Затем добавьте это количество к текущей позиции игрока.

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
    }
}
person KissTheCoder    schedule 27.01.2019

Вы хотите использовать SKAction.move для выполнения того, что хотите.

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

Что это делает, так это перемещает вашу «змейку» в новое место на определенное время. Чтобы определить продолжительность, вам нужно выяснить, как быстро вы хотите, чтобы ваша «змея» двигалась. В настоящее время я настроил его таким образом, что для перемещения на 100 точек требуется 1 секунда, но вы можете настроить это по мере необходимости.

person Knight0fDragon    schedule 28.01.2019
comment
Я попробовал ваше решение и получил следующую ошибку: «Использование расстояния» почти соответствует глобальной функции «расстояние» в модуле «simd», а не методу экземпляра «расстояние (от: до:)». Я попытался изменить имя функции, но это приводит к большему количеству ошибок. - person Tobias; 29.01.2019
comment
Если он уже существует, возможно, вам не нужна моя функция расстояния. - person Knight0fDragon; 29.01.2019
comment
Я удалил вашу функцию расстояния, и единственная ошибка, которую я получаю сейчас, это «Невозможно вызвать« расстояние »со списком аргументов типа «(CGPoint, CGPoint)» в течение времени let - person Tobias; 29.01.2019
comment
Я проверю это, когда вернусь домой, понятия не имею, в чем проблема, вам просто нужно рассчитать расстояние между двумя точками и разделить на скорость. - person Knight0fDragon; 29.01.2019