0

My game has a character which whenever I touch the screen, goes to that location.

However I would like that character to keep following the touch until I let go.

I have tried to do this in the update method, but to no avail.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Amir A.
  • 35
  • 1
  • 8

3 Answers3

2

You can use GameplayKit on iOS 9.

Demo movie https://www.youtube.com/watch?v=9S9SEp6eIZw&feature=youtu.be

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    let trackingAgent = GKAgent2D()

    var player = AgentNode()

    var seekGoal : GKGoal = GKGoal()

    let stopGoal = GKGoal(toReachTargetSpeed: 0)

    var seeking : Bool = false {
        willSet {
            if newValue {
                self.player.agent.behavior?.setWeight(1, forGoal: seekGoal)
                self.player.agent.behavior?.setWeight(0, forGoal: stopGoal)
            }else{
                self.player.agent.behavior?.setWeight(0, forGoal: seekGoal)
                self.player.agent.behavior?.setWeight(1, forGoal: stopGoal)
            }
        }
    }

    var agentSystem = GKComponentSystem()

    var lastUpdateTime : NSTimeInterval = 0

    override func didMoveToView(view: SKView) {
        super.didMoveToView(view)

        self.trackingAgent.position = vector_float2(Float(self.frame.midX), Float(self.frame.midY))

        self.agentSystem = GKComponentSystem(componentClass: GKAgent2D.self)

        self.player = AgentNode(scene: self, radius: Float(40.0), position: CGPoint(x: self.frame.midX, y: self.frame.midY))

        self.player.agent.behavior = GKBehavior()
        self.agentSystem.addComponent(self.player.agent)

        self.seekGoal = GKGoal(toSeekAgent: self.trackingAgent)
    }

    override func update(currentTime: CFTimeInterval) {

        if lastUpdateTime == 0 {
            lastUpdateTime = currentTime
        }

        let delta = currentTime - lastUpdateTime
        lastUpdateTime = currentTime
        self.agentSystem.updateWithDeltaTime(delta)
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.seeking = true
        handleTouch(touches)
    }

    override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
        self.seeking = false
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.seeking = false
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        handleTouch(touches)
    }

    func handleTouch(touches:Set<UITouch>) {
        guard let touch = touches.first else {
            return
        }

        let location = touch.locationInNode(self)

        self.trackingAgent.position = vector_float2(Float(location.x), Float(location.y))
    }
}

>

import Foundation
import GameplayKit
import SpriteKit

class AgentNode : SKNode, GKAgentDelegate {
    var agent = GKAgent2D()

    var triangleShape = SKShapeNode()

    override init(){
        super.init()
    }

    init(scene:SKScene, radius:Float, position:CGPoint) {
        super.init()

        self.position = position
        self.zPosition = 10;
        scene.addChild(self)

        agent.radius = radius
        agent.position = vector_float2(Float(position.x), Float(position.y))
        agent.delegate = self
        agent.maxSpeed = 100 * 4
        agent.maxAcceleration = 50 * 4

        let ship = SKSpriteNode(imageNamed:"Spaceship")
        ship.setScale(1.0 / 8.0)
        ship.zRotation = CGFloat(-M_PI / 2.0)
        self.addChild(ship)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func agentWillUpdate(agent: GKAgent) {

    }

    func agentDidUpdate(agent: GKAgent) {
        guard let agent2D = agent as? GKAgent2D else {
            return
        }

        self.position = CGPoint(x: CGFloat(agent2D.position.x), y: CGFloat(agent2D.position.y))
        self.zRotation = CGFloat(agent2D.rotation)
    }
}
akio0911
  • 21
  • 4
0

Use removeActionForKey method.

let sprite = SKSpriteNode(imageNamed:"Spaceship")

let key = "move1"

override func didMoveToView(view: SKView) {
    sprite.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
    sprite.setScale(0.25)
    self.addChild(self.sprite)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        let move = SKAction.moveTo(location, duration: 4)
        self.sprite.runAction(move, withKey: self.key)
    }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.sprite.removeActionForKey(self.key)
}
akio0911
  • 21
  • 4
0

I have done it like this. I do not know if it is the best way to do, but it is the best way i found :)

nodeToMove - your node which you want to move nodeToMove.movingSpeed - your node speed

func movingWithLocation(location: CGPoint) {

    isMoving = true
    microbe.removeActionForKey("move")
    var distanceX: Float = (location.x - nodeToMove.position.x)
    var distanceY: Float = (location.y - nodeToMove.position.y)
    var distance: Float = sqrtf(fabsf(distanceX * distanceX) + fabsf(distanceY * distanceY))
    nodeToMove.runAction(SKAction.moveByX(distanceX, y: distanceY, duration: distance / (self.frame.size.width / 300 * nodeToMove.movingSpeed)), withKey: "move")
    self.runAction(SKAction.sequence([
            SKAction.waitForDuration(0.05),
            SKAction.performSelector("changeMovament", onTarget: self)]))
}

>

func changeMovament() {
    isMoving = false
}

And call like this

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    var touch: UITouch = touches.anyObject()
    var location: CGPoint = touch.locationInNode(self)

    if isMoving == false {

        self.movingWithLocation(locationWorld)
    }
}

>

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    var touch: UITouch = touches.anyObject()
    var location: CGPoint = touch.locationInNode(self)

    if isMoving == false {

        self.movingWithLocation(locationWorld)
    }
}

Dont forget!

var isMoving: Bool = false
Darvas
  • 974
  • 3
  • 14
  • 27
  • 1
    The problem with this is you are running many actions over such a short period of time, in which case you should just use the update method for better performance. What the OP is looking for is going to require real-time motion because the node will need to change velocity/position at each frame in the simulation, making it impossible to use SKActions efficiently. – Epic Byte Oct 02 '15 at 17:30