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