Unable to add swipe recognizer to SKScene in Swift playground? - swift

Ok, Im still a little new to how swift playgrounds work but I am trying to add a swipe gesture recognizer in Swift 3 to my swift playground. Following this http://www.spritekitlessons.com/gesture-recognizer-with-sprite-kit-and-swift/ I now have:
func swipedRight(sender:UISwipeGestureRecognizer){
print("swiped right")
}
func swipedLeft(sender:UISwipeGestureRecognizer){
print("swiped left")
}
func swipedUp(sender:UISwipeGestureRecognizer){
print("swiped up")
}
func swipedDown(sender:UISwipeGestureRecognizer){
print("swiped down")
}
let degree = CGFloat(M_PI_2) / 90
class GameScene: SKScene {
var selectedNode: SKNode?
var shakeAction: SKAction?
override func didMove(to view: SKView) {
/* Setup your scene here */
let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector(("swipedRight:")))
swipeRight.direction = .right
view.addGestureRecognizer(swipeRight)
let swipeLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector(("swipedLeft:")))
swipeLeft.direction = .left
view.addGestureRecognizer(swipeLeft)
let swipeUp:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector(("swipedUp:")))
swipeUp.direction = .up
view.addGestureRecognizer(swipeUp)
let swipeDown:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector(("swipedDown:")))
swipeDown.direction = .down
view.addGestureRecognizer(swipeDown)
}
let frame = CGRect(x: 0, y: 0, width: 1000, height: 600) //view size
let view = SKView(frame: frame)
let scene = GameScene(size: frame.size)
view.presentScene(scene)
PlaygroundPage.current.liveView = view
This compiles, however when I swipe I get an unrecognized selector error even though I did include the functions with the selector:
I have tried placing the functions within the class as well. How can I add a swipe recognizer to a Swift playground SKScene?

You have selectors passed as strings, something is definitely wrong with them as said in error log
Try to use new selector syntax - #selector(methodName).
Example:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
/* Swift 3 */
let swipe = UISwipeGestureRecognizer(target: self, action:#selector(handleSwipe))
view.addGestureRecognizer(swipe)
}
func handleSwipe() {
print("Swiped!")
}
}
Using strings for selectors has been deprecated.
Using new selector syntax if the methodName() method doesn't exist, you'll get a compile error – your app won't crash because of "unrecognized selector".

Related

why is bringSubviewToFront() only working for panning, not tapping?

view.bringSubviewToFront(tappedView)
is working when I drag (pan) views but not when I tap them. My issue is that when I have one view layered over the other, I want the bottom view to come to the front when tapped. Currently it will only come to the front when dragged. Do I need some additional code to do this? Thanks.
Here's an excerpt from my code for more context:
#objc func didPan(_ recognizer: UIPanGestureRecognizer) {
let location = recognizer.location(in: self.view)
switch recognizer.state {
case .began:
currentTappedView = moviePieceView.filter { pieceView -> Bool in
let convertedLocation = view.convert(location, to: pieceView)
return pieceView.point(inside: convertedLocation, with: nil)
}.first
currentTargetView = movieTargetView.filter { $0.pieceView == currentTappedView }.first
case .changed:
guard let tappedView = currentTappedView else { return }
let translation = recognizer.translation(in: self.view)
tappedView.center = CGPoint(x: tappedView.center.x + translation.x, y: tappedView.center.y + translation.y)
recognizer.setTranslation(.zero, in: view)
view.bringSubviewToFront(tappedView)
```
I had this same problem, I managed to solve it this way:
Add a gestureRecognizer to your view and put this in your code. Don't forget to set the delegate as well when attaching this to the code!
#IBAction func tappedView1(recognizer: UITapGestureRecognizer) {
view.bringSubviewToFront(myView)
}
Put this in your viewDidLoad:
let tap = UITapGestureRecognizer(target: self, action: #selector(tappedView1))
tap.cancelsTouchesInView = false
self.view.addGestureRecognizer(tap)
If you want to do that from your panGesture check my question.
Thank you all. It worked when I wrote a second function in addition to didPan().
This is the additional code:
override func viewDidLoad() {
super.viewDidLoad()
configureLabel()
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPan(_:)))
view.addGestureRecognizer(panGestureRecognizer)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
view.addGestureRecognizer(tapGestureRecognizer)
}
#objc func didTap(_ recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: self.view)
currentTappedView = moviePieceView.filter { pieceView -> Bool in
let convertedLocation = view.convert(location, to: pieceView)
return pieceView.point(inside: convertedLocation, with: nil)
}.first
guard let tappedView = currentTappedView else { return }
view.bringSubviewToFront(tappedView)
}
HOWEVER, I found out you can also just tick the "User Interaction Enabled" box in the Image View if you don't want to do it programmatically.

How to make a gestureRecogniser selector work in swift 3?

Below is the code I have been using to try and add a gesture recogniser to something. I am getting the yellow error: "No method declared with objective C selector dragging" and then the program is crashing when I go to pan on it. The code and way of using a selector seems to work in all tutorials but it's the problem here.
class GameViewController: UIViewController, UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let p = UIPanGestureRecognizer(target: self, action: #selector("dragging"))
p.delegate = self
characterGridView!.addGestureRecognizer(p)
}
func dragging(p: UIPanGestureRecognizer) {
print("works")
}
Your selector is incorrect.
Change
let p = UIPanGestureRecognizer(target: self, action: #selector("dragging"))
to
let p = UIPanGestureRecognizer(target: self, action: #selector(dragging(p:)))

TVOS : detecting touches with press began and functions (Swift Spritekit)

im trying to define touches in TVOS with press began but its not working.
i want to connect 3 functions
Start Game
Play Pause Music
Restart Game
Game scene TVOS:
func StartGameRecognizer(gesture: UITapGestureRecognizer) {
if isGameOver {
} else if !isStarted {
start()
} else {
hero.flip()
}
}
func playPauseMusicRecognizer(gesture: UITapGestureRecognizer) {
let onoroff = UserDefaults.standard.bool(forKey: "onoroff")
if !onoroff { //playing is false
Singleton.sharedInstance().pauseBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-off.png")
UserDefaults.standard.set(true, forKey: "onoroff")
}
else {
Singleton.sharedInstance().resumeBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-on.png")
UserDefaults.standard.set(false, forKey: "onoroff")
}
}
func RestartGameRecognizer(gesture: UISwipeGestureRecognizer){
print("RestartGame")
//Re-open GameScene
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
GameViewController().scoreTextLabel.isHidden = true
GameViewController().highscoreTextLabel.isHidden = true
GameViewController().ScoreBoardTV.isHidden = true
GameViewController().Score.isHidden = true
GameViewController().HighScore.isHidden = true
GameViewController().NewhighscoreTextLabel.isHidden = true
GameViewController().HomeButton.isHidden = true
// Singleton.sharedInstance().resumeSoundEffectClickedButton()
GameViewController().gameDidStart()
}
GameViewControllerTVOS:
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .upArrow:
print("Up Arrow")
case .downArrow:
print("Down arrow")
case .leftArrow:
print("Left arrow")
case .rightArrow:
print("Right arrow")
case .select:
print("Select")
case .menu:
print("Menu")
case .playPause:
print("Play/Pause")
default:
print("")
}
}
}
How i can use it right?
How can i transfer functions between scene to view controller?
I need example or hint to write the code right.
Update:
GameSceneTvOS:
override func didMove(to view: SKView) {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameSceneTVOS.StartGameRecognizer(gesture:)))
tapGesture.allowedPressTypes = [NSNumber(value: UIPressType.Select.rawValue)]
view.addGestureRecognizer(tapGesture)
let tapGesture1 = UITapGestureRecognizer(target: self, action: #selector(GameSceneTVOS.PlaypauseMusicRecognizer(gesture:)))
tapGesture1.allowedPressTypes = [NSNumber(value: UIPressType.PlayPause.rawValue)]
view.addGestureRecognizer(tapGesture1)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(GameSceneTVOS.RestartGameRecognizer(gesture:)))
swipeUp.direction = UISwipeGestureRecognizerDirection.up
self.view?.addGestureRecognizer(swipeUp)
}
**Functions :**
func StartGameRecognizer(gesture: UITapGestureRecognizer) {
print("StartGame")
if isGameOver {
} else if !isStarted {
start()
} else {
hero.flip()
}
}
func PlaypauseMusicRecognizer(gesture: UITapGestureRecognizer) {
print("PlaypauseMusic")
let onoroff = UserDefaults.standard.bool(forKey: "onoroff")
if !onoroff { //playing is false
Singleton.sharedInstance().pauseBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-off.png")
UserDefaults.standard.set(true, forKey: "onoroff")
}
else {
Singleton.sharedInstance().resumeBackgroundMusic()
SoundOnOff.texture = SKTexture(imageNamed:"Sound-on.png")
UserDefaults.standard.set(false, forKey: "onoroff")
}
}
func RestartGameRecognizer(gesture: UISwipeGestureRecognizer){
print("RestartGame")
//Re-open GameScene
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
GameViewController().scoreTextLabel.isHidden = true
GameViewController().highscoreTextLabel.isHidden = true
GameViewController().ScoreBoardTV.isHidden = true
GameViewController().Score.isHidden = true
GameViewController().HighScore.isHidden = true
GameViewController().NewhighscoreTextLabel.isHidden = true
GameViewController().HomeButton.isHidden = true
// Singleton.sharedInstance().resumeSoundEffectClickedButton()
GameViewController().gameDidStart()
}
You code has some problems.
1) This code is wrong in the restartGame method.
GameViewController().TitleGameOver.isHidden = true
GameViewController().RestartButton.isHidden = true
...
You are creating a new instance of GameViewController on every line, you are not referencing the current game view controller.
2) You should not be using your GameViewController to create your UI, you should be doing it directly in the relevant SKScenes using only SpriteKit APIs (SKLabelNodes, SKSpriteNodes, SKNodes etc). Using UIKit in SpriteKit, except in some occasions, is bad practice.
3) You should be using TouchesBegan, TouchesMoved etc directly in the SKScenes to get touch input, dont use the GameViewController method.
They fill fire just like they do when you are on iOS.
You can also create gesture recognizers in your SKScene to get button presses from the SiriRemote.
/// Pressed, not tapped, main touch pad
let pressedMain = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedMain.allowedPressTypes = [NSNumber(value: UIPressType.select.rawValue)]
view?.addGestureRecognizer(pressedMain)
/// Pressed play pause button
let pressedPlayPause = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedPlayPause.allowedPressTypes = [NSNumber(value: UIPressType.playPause.rawValue)]
view?.addGestureRecognizer(pressedPlayPause)
/// Pressed menu button
let pressedMenu = UITapGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
pressedMenu.allowedPressTypes = [NSNumber(value: UIPressType.menu.rawValue)]
view?.addGestureRecognizer(pressedMenu)
You can also use swipe gesture recognizers if you want
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
rightSwipe.direction = .right
view?.addGestureRecognizer(rightSwipe)
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
leftSwipe.direction = .left
view?.addGestureRecognizer(leftSwipe)
let upSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
upSwipe.direction = .up
view?.addGestureRecognizer(upSwipe)
let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SOMEMETHOD))
downSwipe.direction = .down
view?.addGestureRecognizer(downSwipe)
If you are using gesture recognisers, remember they are added to the GameViewController (view?.addGesture...) so its good practice to remove them when you add either new ones, or if you change to a new scene where you might need different ones.
Call this code when you exit a scene or add new gesture recognizers.
for gestureRecognizer in view?.gestureRecognizers ?? [] {
view?.removeGestureRecognizer(gestureRecognizer)
}
If you are looking for fully fledged micro gamepad support than you will need to watch some tutorials about the gameController framework.
4) Try putting your string keys like the ones for UserDefaults in some property.
enum Key: String {
case onoroff
}
and than use it like so
UserDefaults.standard.set(true, forKey: Key.onoroff.rawValue)
to avoid making typos.
5) You should be following the Swift conventions consistently, some of your methods and properties start with capital letters but they shouldn't.
I would advise that you restructure your code and not continue with this approach of trying to use the GameViewController for all this. It should be all done directly in the relevant SKScene.
EDIT. I think you are calling the selector wrong, try this. When your function has a parameter you would use this (_:), you are trying to use (gesture:). Try this instead.
... action: #selector(startGameRecognizer(_:))
Hope this helps

Function not called with selector action

I'm trying to handle tap gesture in an external UIViewController's class but my function was never called. Here is my
code:
import SceneKit
import UIKit
class SceneManager
{
private let assetFolder: String
private let mainCamera: SCNNode
private let view: SCNView
private let scene: SCNScene
init(view: SCNView, assetFolder: String, sceneFile: String, mainCameraName: String, backgroundColor: UIColor) {
self.assetFolder = assetFolder
self.scene = SCNScene(named: (self.assetFolder + "/scene/" + sceneFile))!
self.mainCamera = self.scene.rootNode.childNodeWithName(mainCameraName, recursively: true)!
self.view = view
self.view.backgroundColor = backgroundColor
self.view.allowsCameraControl = false
self.view.pointOfView = self.mainCamera
self.view.scene = self.scene
//PROBLEM BELOW
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.addGestureRecognizer(gesture)
}
#objc func handleTap(sender: UITapGestureRecognizer) {
print("hello")
}
}
Here is my ViewController Class :
import UIKit
import QuartzCore
import SceneKit
class ViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
let view = self.view as! SCNView
view.showsStatistics = true
_ = SceneManager(view: view, assetFolder: "art.scnassets", sceneFile: "EURO_COPTER.dae", mainCameraName: "camera", backgroundColor: UIColor.blackColor())
}
}
If someone has an idea. Thanks in advance.
Try following code it may help
let gesture = UITapGestureRecognizer(target: self, action: #selector(SceneManager.handleTap(_:)))
Try to this way:-
When you declare your class, add UIGestureRecognizerDelegate after the class it subclasses. Here's what that looks like in my case:
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.userInteractionEnabled = true;
gesture.delegate = self
self.view.addGestureRecognizer(gesture)

Swipe gesture action is not called

I am trying to do basic 2D snake game for tv.
I have problem with gestures. I add gestures to view in didMoveToView(view: SKView) method inside GameScene class. This class also extends SKScene class. This is my didMoveToView method and handleSwipe method.
override func didMoveToView(view: SKView) {
let swipeUp = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeUp.direction = .Up
view.addGestureRecognizer(swipeUp)
let swipeDown = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeDown.direction = .Down
view.addGestureRecognizer(swipeDown)
let swipeLeft = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeLeft.direction = .Left
view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeRight.direction = .Right
view.addGestureRecognizer(swipeRight)
backgroundColor = SKColor.blackColor()
}
func handleSwipe(sender: UIGestureRecognizer) {
if let gesture = sender as? UISwipeGestureRecognizer {
switch(gesture.direction) {
case UISwipeGestureRecognizerDirection.Right: m_snake.moveRight()
case UISwipeGestureRecognizerDirection.Left: m_snake.moveLeft()
case UISwipeGestureRecognizerDirection.Up: m_snake.moveUp()
case UISwipeGestureRecognizerDirection.Down: m_snake.moveDown()
default:
break
}
}
}
It seems like my program does not enter handleSwipe method when I swipe on remote. I am testing this on simulator. Any idea why this doesn't work?
func handleSwipes(sender:UISwipeGestureRecognizer) {
if let gesture = sender as? UISwipeGestureRecognizer {
switch(gesture.direction) {
case UISwipeGestureRecognizerDirection.Right: m_snake.moveRight()
case UISwipeGestureRecognizerDirection.Left: m_snake.moveLeft()
case UISwipeGestureRecognizerDirection.Up: m_snake.moveUp()
case UISwipeGestureRecognizerDirection.Down: m_snake.moveDown()
default:
break
}
}
}
I just tested your code in my current project and it worked perfectly fine
To get the swipe working, configure the simulator like this;
Show the remote by going to Hardware > Show Apple TV Remote
Hold down option while your mouse is over the trackpad.
Move the mouse sideways in a swipe movement