SpriteKit中拖拽SKShapeNode如何避免穿越其他节点边界?
拖拽SKShapeNode小球时禁止穿越边界的解决方案
我需要实现拖拽代表玩家的圆形SKShapeNode小球时,不能穿越由复杂UIBezierPath创建的天花板、地板SKShapeNode边界,比如小球拖到天花板时不会穿墙。
游戏场景里,天花板和地板在update(_ currentTime: TimeInterval)中修改x坐标实现动画,已配置好碰撞检测与接触测试,整体运行正常,但两种拖拽方法都有问题:
方法一:直接修改position属性
在touchesMoved中直接更新小球position:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { let translation = CGVector(dx: location.x - previousLocation.x, dy: location.y - previousLocation.y) var newPosition = ball.position newPosition.x += translation.dx newPosition.y += translation.dy ball.position = newPosition }
- 优点:拖拽流畅,和手指移动同步,慢速拖动时能遵守边界
- 缺点:快速拖动时小球会直接穿过天花板或地板
方法二:使用applyImpulse施加冲量
通过给小球physicsBody施加冲量实现拖拽:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first, let location = touchLocation else { return } let newLocation = touch.location(in: self) let scalingFactor: CGFloat = 0.1 let touchMovement = CGVector(dx: newLocation.x - location.x, dy: newLocation.y - location.y) touchForce = CGVector(dx: touchMovement.dx * scalingFactor, dy: touchMovement.dy * scalingFactor) touchLocation = newLocation ball.physicsBody?.applyImpulse(touchForce!) }
- 优点:能遵守边界
- 缺点:有缓动效果,不符合预期的拖拽体验,也无法准确反映拖拽幅度
我需要兼顾两者优点的解决方案,以下是墙壁和小球的参考代码:
天花板/地板节点代码
class Wall: SKShapeNode { init(size: CGSize) { super.init() let bottomPath = UIBezierPath() bottomPath.move(to: CGPoint(x: 0, y: -19.99)) bottomPath.addLine(to: CGPoint(x: 5723.5, y: -19.99)) bottomPath.addLine(to: CGPoint(x: 5723.5, y: 35.51)) bottomPath.addLine(to: CGPoint(x: 4915.5, y: 35.51)) bottomPath.addCurve(to: CGPoint(x: 4892.87, y: 44.88), controlPoint1: CGPoint(x: 4907.01, y: 35.51), controlPoint2: CGPoint(x: 4898.87, y: 38.88)) /// 更多路径节点 bottomPath.close() self.path = bottomPath.cgPath strokeColor = UIColor.green fillColor = UIColor.clear lineWidth = 5 lineCap = .round lineJoin = .round zPosition = 0 name = "bottom" physicsBody = SKPhysicsBody(edgeLoopFrom: self.path!) physicsBody?.isDynamic = false physicsBody?.affectedByGravity = false physicsBody?.categoryBitMask = 1 physicsBody?.contactTestBitMask = 2 physicsBody?.collisionBitMask = 1 physicsBody?.restitution = 0 physicsBody?.usesPreciseCollisionDetection = true physicsBody?.density = 100 physicsBody?.mass = 100 } }
小球节点代码
class Ball: SKShapeNode { convenience init(radius: CGFloat) { self.init(circleOfRadius: radius) fillColor = .red zPosition = 0 physicsBody = SKPhysicsBody(circleOfRadius: radius) physicsBody?.affectedByGravity = false physicsBody?.categoryBitMask = 2 physicsBody?.contactTestBitMask = 1 physicsBody?.collisionBitMask = 1 physicsBody?.restitution = 1 physicsBody?.usesPreciseCollisionDetection = true } }
游戏核心玩法是拖拽小球沿路径移动,统计耗时和碰壁次数,求合适的拖拽方案兼顾流畅性与边界约束。
内容的提问来源于stack exchange,提问作者user499846
相关产品推荐
相关产品推荐

