使用 UIPanGestureRecognizer 连续移动 SKSpriteNode
Posted
技术标签:
【中文标题】使用 UIPanGestureRecognizer 连续移动 SKSpriteNode【英文标题】:Move SKSpriteNode with UIPanGestureRecognizer continuously 【发布时间】:2018-05-30 17:07:24 【问题描述】:我试图在一个简单的二维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
来完成的工作,是否有更简单的解决方案?
【问题讨论】:
【参考方案1】:didPan()
在用户单次平移期间被多次调用,状态为.changed
,但不是定期调用。
相反,您应该声明两个全局状态变量来保存当前的水平和垂直方向(例如,第一个方向是从左到右或从右到左)并在每次调用 didPan()
时更新这些变量。
您应该仅在方向发生变化时运行 SKAction
实例,并且这些 SKAction
实例应该无限循环,而不是仅具有 0.5 秒的一次性特定持续时间(请参阅 SceneKit API 手册中的 SKAction.repeatForever()
)。
另外,您需要确保在运行下一个移动动作之前删除已经运行的移动动作。
最后,当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")
【讨论】:
注意,您还需要使用moveBy
而不是moveTo
moveTo
的连续循环将带您到达第一个moveTo
位置
我尽我所能根据您的回答提供了编辑和示例。请随时更新示例以说明您的具体意思。以上是关于使用 UIPanGestureRecognizer 连续移动 SKSpriteNode的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 UIPanGestureRecognizer 移动对象时会有延迟?
UIPanGestureRecognizer ***视图未获取事件,子视图使用它们
在 UITableView 上滑动删除以使用 UIPanGestureRecognizer
在 UIPanGestureRecognizer 中使用velocityInView