SpriteKit中如何基于触摸实现精灵相对原始位置的跟随移动
嘿,我完全懂你想要的效果——让精灵跟着手指的滑动轨迹同步移动,而不是用SKAction.moveTo那种预先设定路径的方式对吧?这种实时跟随的交互其实比动作类更直接,核心就是监听触摸事件,实时计算位移并更新精灵位置。我给你拆解一下具体的实现步骤,用SpriteKit的常规Swift写法:
我们需要记录两个关键状态:触摸开始时的手指位置,以及此时精灵的初始位置。之后在手指滑动过程中,计算手指的移动偏移量,再把这个偏移量叠加到精灵的初始位置上,就能实现精灵跟着手指的滑动轨迹同步移动的效果——就像你说的,精灵从屏幕中心出发,跟着向上滑动的手指一起移动。
假设你已经在场景里创建了名为playerSprite的精灵节点,接下来在你的SKScene子类里添加以下代码:
1. 定义变量记录初始状态
先声明两个私有变量,用来存储触摸开始时的手指位置和精灵位置:
private var initialTouchPosition: CGPoint? private var initialSpritePosition: CGPoint?
2. 监听触摸开始事件
当用户按下屏幕时,记录当前的触摸点(转换为SpriteKit场景坐标系)和精灵的初始位置:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } // 将UI坐标系的触摸点转换为SpriteKit场景坐标系 initialTouchPosition = touch.location(in: self) // 记录精灵当前的初始位置 initialSpritePosition = playerSprite.position }
3. 实时更新精灵位置
在手指滑动过程中,计算手指的位移偏移量,然后同步更新精灵的位置:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first, let initialTouchPos = initialTouchPosition, let initialSpritePos = initialSpritePosition else { return } let currentTouchPos = touch.location(in: self) // 计算手指从初始位置到当前位置的偏移量 let offset = CGPoint(x: currentTouchPos.x - initialTouchPos.x, y: currentTouchPos.y - initialTouchPos.y) // 更新精灵位置:初始位置 + 手指偏移量 playerSprite.position = CGPoint(x: initialSpritePos.x + offset.x, y: initialSpritePos.y + offset.y) }
4. 触摸结束后重置状态
当用户松开手指或者触摸被取消时,清空记录的初始状态,避免影响下一次触摸操作:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { initialTouchPosition = nil initialSpritePosition = nil } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { touchesEnded(touches, with: event) }
平滑移动效果:如果你想要更丝滑的跟随感,可以给精灵的位置更新加上一点缓动,比如用短时长的
SKAction:let targetPosition = CGPoint(x: initialSpritePos.x + offset.x, y: initialSpritePos.y + offset.y) playerSprite.run(SKAction.move(to: targetPosition, duration: 0.05))注意这种方式会有轻微的延迟,适合追求流畅感而非绝对同步的场景。
边界限制:如果不想让精灵移出屏幕,可以在更新位置时加上边界检测:
let spriteHalfWidth = playerSprite.size.width / 2 let spriteHalfHeight = playerSprite.size.height / 2 let minX = spriteHalfWidth let maxX = size.width - spriteHalfWidth let minY = spriteHalfHeight let maxY = size.height - spriteHalfHeight let targetX = max(minX, min(maxX, initialSpritePos.x + offset.x)) let targetY = max(minY, min(maxY, initialSpritePos.y + offset.y)) playerSprite.position = CGPoint(x: targetX, y: targetY)直接跟随手指位置:如果你想要精灵直接跟着手指的当前位置走(而非相对初始位置偏移),那更简单,直接在
touchesMoved里把精灵位置设为currentTouchPos即可。
内容的提问来源于stack exchange,提问作者Cryohazards

