简体   繁体   中英

Move SKSpriteNode with UIPanGestureRecognizer continuously

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 ?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM