使用 UIPanGestureRecognizer 连续移动 SKSpriteNode

Move SKSpriteNode with UIPanGestureRecognizer continuously

我正在尝试在简单的二维 SKScene 中连续移动 SKSpriteNode。这涉及在 UIGestureRecognizer 的平移的相反方向上移动包含所有背景节点的数组,并同时为节点设置动画。

我已经通过实现节点和识别器并在平移时调用其方法实现了移动:

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

我面临的问题是,当我真正想要移动它们时,此方法仅根据我设置的值和我必须保持的有限时间来移动和动画化精灵以准确匹配动画长度锅的持续时间。

我特意实现了一个平移识别器而不是滑动识别器,因为场景还将包含一个用于稍后控制移动的操纵杆。

对于我不使用 UIGestureRecognizer 想要完成的事情,是否有更简单的解决方案?

didPan() 在用户的单个平移期间以状态 .changed 被多次调用,但不是以常规频率调用。

相反,您应该声明两个保存当前水平和垂直方向的全局状态变量(例如,从左到右,或从右到左,对于第一个)并每次更新这些变量didPan() 叫做。

你应该 运行 一个 SKAction 仅当方向改变时的实例,并且那些 SKAction 实例应该无限循环,而不是只有一次性的特定持续时间 0.5 秒(见SKAction.repeatForever() 在 SceneKit API 手册中)。

此外,您需要确保在 运行 下一个移动动作之前删除已经 运行 宁的移动动作。

最后,当 didPan() 以状态 .ended 调用时调用 removeAllActions()

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