如何检测 Spritekit 节点上的滑动?
How can I detect swipes on Spritekit Nodes?
所以我目前正在研究用 Swift3 编写的 2D 无尽奔跑者,并将 Spritekit 用于我的节点和场景。我最近实现了一些代码来检测一般的滑动,它们将在下面。所以我的问题是:如何检测滑动动作并检查 Spritekit 节点上滑动的方向?我意识到之前有人问过这个问题,但我找不到可行的解决方案,因为我遇到的一切似乎都是针对 Swift 和 Swift2,而不是 Swift3.
这是我的滑动检测代码:
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeLeft.direction = UISwipeGestureRecognizerDirection.left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeRight.direction = UISwipeGestureRecognizerDirection.right
self.view.addGestureRecognizer(swipeRight)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeUp.direction = UISwipeGestureRecognizerDirection.up
self.view.addGestureRecognizer(swipeUp)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeDown.direction = UISwipeGestureRecognizerDirection.down
self.view.addGestureRecognizer(swipeDown)
}
我用函数测试了这些:
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right:
print("Swiped right")
case UISwipeGestureRecognizerDirection.down:
print("Swiped down")
case UISwipeGestureRecognizerDirection.left:
print("Swiped left")
case UISwipeGestureRecognizerDirection.up:
print("Swiped up")
default:
break
}
}
}
滑动似乎工作正常,因为打印语句一直显示正确的输出以响应我的滑动。
我还添加了一个委托来避免可能的 SIGABRT 错误:
class GameViewController: UIViewController, UIGestureRecognizerDelegate
如果您想了解更多信息,请告诉我!
Edit:
Added code where I initialized my puzzle pieces
//The class
class ChoosePiecesClass: SKSpriteNode{
func moveWithCamera() {
self.position.x += 5;
}
//initialize a piece
private var RandomPiece1: ChoosePiecesClass?;
override func didMove(to view: SKView) {
RandomPiece1 = childNode(withName: "RandomPiece1") as? ChoosePiecesClass;
RandomPiece1?.position.x = 195;
RandomPiece1?.position.y = -251;
}
override func update(_ currentTime: TimeInterval) {
RandomPiece1?.moveWithCamera();
}
Edited to provide the error statement from console, upon clicking Start Game and triggering the fatalError code, causing the game to crash.
fatal error: init(coder:) has not been implemented: file /Users/ardemis/Documents/PuzzleRunner/PuzzleRunner 3 V3/PuzzleRunner/ChoosePieces.swift, line 33
它还显示以下内容
EXEC_BAT_INSTRUCTION(code = EXEC_1386_INVOP, subcode = 0x0)
与 fatalError 声明在同一行。
如果我试图跟踪特定的 SpriteNode,我不会使用 UIGestures。您可以轻松地在 TouchesBegan 中跟踪您的节点,并找出滑动方向发生的方式。此示例在屏幕上显示三个子画面 print/log 无论朝哪个方向滑动其中一个,都会忽略所有其他滑动。
EDIT > I just created a subclass for my Box object (sorry I didn't use your naming, but it has the same functions). There are probably many ways of doing this, I chose to use create a protocol on the subclass and make the scene conform to the protocol. I moved all of the touch/swipe functionality into the sub class, and when it is done detecting the swipe it just calls the delegate and says which object has been swiped.
protocol BoxDelegate: NSObjectProtocol {
func boxSwiped(box: Box)
}
class Box: SKSpriteNode {
weak var boxDelegate: BoxDelegate!
private var moveAmtX: CGFloat = 0
private var moveAmtY: CGFloat = 0
private let minimum_detect_distance: CGFloat = 100
private var initialPosition: CGPoint = CGPoint.zero
private var initialTouch: CGPoint = CGPoint.zero
private var resettingSlider = false
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
self.isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func moveWithCamera() {
self.position.x += 5
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
initialTouch = touch.location(in: self.scene!.view)
moveAmtY = 0
moveAmtX = 0
initialPosition = self.position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let movingPoint: CGPoint = touch.location(in: self.scene!.view)
moveAmtX = movingPoint.x - initialTouch.x
moveAmtY = movingPoint.y - initialTouch.y
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
var direction = ""
if fabs(moveAmtX) > minimum_detect_distance {
//must be moving side to side
if moveAmtX < 0 {
direction = "left"
}
else {
direction = "right"
}
}
else if fabs(moveAmtY) > minimum_detect_distance {
//must be moving up and down
if moveAmtY < 0 {
direction = "up"
}
else {
direction = "down"
}
}
print("object \(self.name!) swiped " + direction)
self.boxDelegate.boxSwiped(box: self)
}
}
在GameScene.sks
Make sure to make GameScene conform to BoxDelegate by adding the protocol after the declaration
class GameScene: SKScene, BoxDelegate {
var box = Box()
var box2 = Box()
var box3 = Box()
override func didMove(to view: SKView) {
box = Box(color: .white, size: CGSize(width: 200, height: 200))
box.zPosition = 1
box.position = CGPoint(x: 0 - 900, y: 0)
box.name = "white box"
box.boxDelegate = self
addChild(box)
box2 = Box(color: .blue, size: CGSize(width: 200, height: 200))
box2.zPosition = 1
box2.name = "blue box"
box2.position = CGPoint(x: 0 - 600, y: 0)
box2.boxDelegate = self
addChild(box2)
box3 = Box(color: .red, size: CGSize(width: 200, height: 200))
box3.zPosition = 1
box3.name = "red box"
box3.position = CGPoint(x: -300, y: 0)
box3.boxDelegate = self
addChild(box3)
}
func boxSwiped(box: Box) {
currentObject = box
print("currentObject \(currentObject)")
}
override func update(_ currentTime: TimeInterval) {
box.moveWithCamera()
box2.moveWithCamera()
box3.moveWithCamera()
}
}
所以我目前正在研究用 Swift3 编写的 2D 无尽奔跑者,并将 Spritekit 用于我的节点和场景。我最近实现了一些代码来检测一般的滑动,它们将在下面。所以我的问题是:如何检测滑动动作并检查 Spritekit 节点上滑动的方向?我意识到之前有人问过这个问题,但我找不到可行的解决方案,因为我遇到的一切似乎都是针对 Swift 和 Swift2,而不是 Swift3.
这是我的滑动检测代码:
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeLeft.direction = UISwipeGestureRecognizerDirection.left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeRight.direction = UISwipeGestureRecognizerDirection.right
self.view.addGestureRecognizer(swipeRight)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeUp.direction = UISwipeGestureRecognizerDirection.up
self.view.addGestureRecognizer(swipeUp)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeDown.direction = UISwipeGestureRecognizerDirection.down
self.view.addGestureRecognizer(swipeDown)
}
我用函数测试了这些:
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right:
print("Swiped right")
case UISwipeGestureRecognizerDirection.down:
print("Swiped down")
case UISwipeGestureRecognizerDirection.left:
print("Swiped left")
case UISwipeGestureRecognizerDirection.up:
print("Swiped up")
default:
break
}
}
}
滑动似乎工作正常,因为打印语句一直显示正确的输出以响应我的滑动。
我还添加了一个委托来避免可能的 SIGABRT 错误:
class GameViewController: UIViewController, UIGestureRecognizerDelegate
如果您想了解更多信息,请告诉我!
Edit: Added code where I initialized my puzzle pieces
//The class
class ChoosePiecesClass: SKSpriteNode{
func moveWithCamera() {
self.position.x += 5;
}
//initialize a piece
private var RandomPiece1: ChoosePiecesClass?;
override func didMove(to view: SKView) {
RandomPiece1 = childNode(withName: "RandomPiece1") as? ChoosePiecesClass;
RandomPiece1?.position.x = 195;
RandomPiece1?.position.y = -251;
}
override func update(_ currentTime: TimeInterval) {
RandomPiece1?.moveWithCamera();
}
Edited to provide the error statement from console, upon clicking Start Game and triggering the fatalError code, causing the game to crash.
fatal error: init(coder:) has not been implemented: file /Users/ardemis/Documents/PuzzleRunner/PuzzleRunner 3 V3/PuzzleRunner/ChoosePieces.swift, line 33
它还显示以下内容
EXEC_BAT_INSTRUCTION(code = EXEC_1386_INVOP, subcode = 0x0)
与 fatalError 声明在同一行。
如果我试图跟踪特定的 SpriteNode,我不会使用 UIGestures。您可以轻松地在 TouchesBegan 中跟踪您的节点,并找出滑动方向发生的方式。此示例在屏幕上显示三个子画面 print/log 无论朝哪个方向滑动其中一个,都会忽略所有其他滑动。
EDIT > I just created a subclass for my Box object (sorry I didn't use your naming, but it has the same functions). There are probably many ways of doing this, I chose to use create a protocol on the subclass and make the scene conform to the protocol. I moved all of the touch/swipe functionality into the sub class, and when it is done detecting the swipe it just calls the delegate and says which object has been swiped.
protocol BoxDelegate: NSObjectProtocol {
func boxSwiped(box: Box)
}
class Box: SKSpriteNode {
weak var boxDelegate: BoxDelegate!
private var moveAmtX: CGFloat = 0
private var moveAmtY: CGFloat = 0
private let minimum_detect_distance: CGFloat = 100
private var initialPosition: CGPoint = CGPoint.zero
private var initialTouch: CGPoint = CGPoint.zero
private var resettingSlider = false
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
self.isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func moveWithCamera() {
self.position.x += 5
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
initialTouch = touch.location(in: self.scene!.view)
moveAmtY = 0
moveAmtX = 0
initialPosition = self.position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let movingPoint: CGPoint = touch.location(in: self.scene!.view)
moveAmtX = movingPoint.x - initialTouch.x
moveAmtY = movingPoint.y - initialTouch.y
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
var direction = ""
if fabs(moveAmtX) > minimum_detect_distance {
//must be moving side to side
if moveAmtX < 0 {
direction = "left"
}
else {
direction = "right"
}
}
else if fabs(moveAmtY) > minimum_detect_distance {
//must be moving up and down
if moveAmtY < 0 {
direction = "up"
}
else {
direction = "down"
}
}
print("object \(self.name!) swiped " + direction)
self.boxDelegate.boxSwiped(box: self)
}
}
在GameScene.sks
Make sure to make GameScene conform to BoxDelegate by adding the protocol after the declaration
class GameScene: SKScene, BoxDelegate {
var box = Box()
var box2 = Box()
var box3 = Box()
override func didMove(to view: SKView) {
box = Box(color: .white, size: CGSize(width: 200, height: 200))
box.zPosition = 1
box.position = CGPoint(x: 0 - 900, y: 0)
box.name = "white box"
box.boxDelegate = self
addChild(box)
box2 = Box(color: .blue, size: CGSize(width: 200, height: 200))
box2.zPosition = 1
box2.name = "blue box"
box2.position = CGPoint(x: 0 - 600, y: 0)
box2.boxDelegate = self
addChild(box2)
box3 = Box(color: .red, size: CGSize(width: 200, height: 200))
box3.zPosition = 1
box3.name = "red box"
box3.position = CGPoint(x: -300, y: 0)
box3.boxDelegate = self
addChild(box3)
}
func boxSwiped(box: Box) {
currentObject = box
print("currentObject \(currentObject)")
}
override func update(_ currentTime: TimeInterval) {
box.moveWithCamera()
box2.moveWithCamera()
box3.moveWithCamera()
}
}