Reputation: 175
I am trying to move an SKSpriteNode
continuously in a simple 2-dimensional SKScene
. This involves both moving an array containing all background-nodes in the opposite direction of a UIGestureRecognizer
's pan and animating the node at the same time.
I have already realized the movement by implementing the nodes and recognizer and calling its method when panning:
@objc func didPan(gesture: UIPanGestureRecognizer) {
let pan = gesture.velocity(in: self.view)
if gesture.state == .changed {
for sprites in levelSprites {
if pan.x > 0 && pan.x > pan.y {
sprites.run(SKAction.moveTo(x: sprites.position.x - 40, duration: 0.5))
self.player.run(SKAction(named: "WalkRight")!)
} else if pan.x < 0 && pan.x < pan.y {
sprites.run(SKAction.moveTo(x: sprites.position.x + 40, duration: 0.5))
self.player.run(SKAction(named: "WalkLeft")!)
} else if pan.y < 0 && pan.x > pan.y {
sprites.run(SKAction.moveTo(y: sprites.position.y - 30, duration: 0.5))
self.player.run(SKAction(named: "WalkUp")!)
} else if pan.y > 0 && pan.x < pan.y {
sprites.run(SKAction.moveTo(y: sprites.position.y + 30, duration: 0.5))
self.player.run(SKAction(named: "WalkDown")!)
}
}
}
}
The problem I'm facing is that this method only moves and animates the sprites for the value I set and the limited time that I have to maintain to accurately match the animations length, when I actually want to move them for the duration of the pan.
I deliberately implemented a recognizer for pan indstead of swipes, scince the scene will also contain a joystick for controlling the movement later on.
Is there maybe an easier solution to what I'm trying to accomplish not using a UIGestureRecognizer
?
Upvotes: 0
Views: 331
Reputation: 4809
didPan()
is called multiple times with state .changed
during a single pan from the user, but not at a regular frequency.
Instead, you should declare two global state variables that save the current horizontal and vertical directions (left to right, or right to left, for the first one, for instance) and update these variables each time didPan()
is called.
You should run an SKAction
instance only when a direction changes and those SKAction
instances should loop indefinitely, not have a one-time only specific duration of 0.5 sec (see SKAction.repeatForever()
in the SceneKit API manual).
Also, you need to be sure to remove the already running moving action before running the next movement action.
Finally, call removeAllActions()
when didPan()
is called with state .ended
.
enum VerticalState{
case .none
case .topToBottom
case .bottomToTop
}
enum HorizontalState{
case .none
case .leftToRight
case .rightToLeft
}
var verticalState = VerticalState.none
var horizontalState = HorizontalState.none
@objc func didPan(gesture: UIPanGestureRecognizer) {
let pan = gesture.velocity(in: self.view)
if gesture.state == .changed {
for sprites in levelSprites {
if pan.x > 0 && pan.x > pan.y && horizontalState <> .leftToRight{
horizontalState = .none
verticalState = .none
} else if pan.x < 0 && pan.x < pan.y && horizontalState <> .rightToLeft{
horizontalState = .rightToLeft
verticalState = .none
} else if pan.y < 0 && pan.x > pan.y && verticalState <> .bottomToTop{
horizontalState = .none
verticalState = .bottomToTop
} else if pan.y > 0 && pan.x < pan.y && verticalState <> topToBottom{
horizontalState = .none
verticalState = .topToBottom
}
switch horizontalState
{
case .leftToRight:
sprites.removeActionForKey("movement")
self.player.removeActionForKey("movement")
sprites.run(SKAction.repeatForever(SKAction.moveBy(x: -40, y:0, duration: 0.5), forKey:"movement"))
self.player.run(SKAction(named: "WalkRight")!, forKey:"movement")
case .rightToLeft:
sprites.removeActionForKey("movement")
self.player.removeActionForKey("movement")
sprites.run(SKAction.repeatForever(SKAction.moveBy(x: 40, y:0,, duration: 0.5), forKey:"movement"))
self.player.run(SKAction(named: "WalkLeft")!, forKey:"movement")
case .none:
break
}
switch verticalState
{
case .topToBottom:
sprites.removeActionForKey("movement")
self.player.removeActionForKey("movement")
sprites.run(SKAction.repeatForever(SKAction.moveBy(x: 0, y:-30, duration: 0.5), forKey:"movement"))
self.player.run(SKAction(named: "WalkUp")!, forKey:"movement")
case .bottomToTop:
sprites.removeActionForKey("movement")
self.player.removeActionForKey("movement")
sprites.run(SKAction.repeatForever(SKAction.moveBy(x: 0, y:30,, duration: 0.5), forKey:"movement"))
self.player.run(SKAction(named: "WalkDown")!, forKey:"movement")
case .none:
break
}
}
}else if gesture.state == .ended {
sprites.removeActionForKey("movement")
self.player.removeActionForKey("movement")
}
}
Upvotes: 2