1

So I have made 2 games so far and I always used the touchesBegan function and SpriteNodes to create a Menu, like that:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)

        if (atPoint(location).name == "playButton"){
           startGame()
        }
    }
}

But this way is pretty ugly because as soon as you touch the button it will call the according action to it and you can't cancel it. But with a normal UIButton it will only call the action after you take the finger off the button, and you can even cancle a button click by just moving your finger away from the button. And the problem is, I don't know how I can add a UIButton to my MenuScene.swift file and I also don't use the Storyboard because it's just confusing to me and I don't understand how the .sks, .swift and .Storyboard files are linked together, it just makes no sense to me. I mean the .sks and .storyboard files are both for buildung a GUI but in .sks you cant add a UIButton... but why??? Is there any convenient way to add a button?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Lukas
  • 451
  • 2
  • 13
  • You have to implement your own button class using SKSpriteNode's. e.g. look here: https://stackoverflow.com/questions/38192205/create-button-in-spritekit-swift – Ramy Al Zuhouri Feb 04 '18 at 16:08
  • Can you add a sample code how to do that? and how is the file called where i add it? – Lukas Feb 04 '18 at 16:27
  • Use `touchesEnded()` - that's the equivalent of 'touchUpInside' whereas `touchesBegan()` is 'touchdownInside' – Steve Ives Feb 05 '18 at 12:31
  • @SteveIves gee Steve I heard that somewhere... ;) – Ron Myschuk Feb 05 '18 at 15:35
  • @RonMyschuk You did indeed! :-) I can see the benefit of creating a class button, but for 'simple' use, can you get away with *only* checking `touchesEnded`? – Steve Ives Feb 05 '18 at 15:37

1 Answers1

2

I wouldn't use UIButton in my Spritekit code, you are better off to create your own Button class in Spritekit and use it. The sks file is not linked to a storyboard it is linked to any class that you designate (GameScene, MenuScene) it can even be linked to smaller objects that have their own class (ScoreHUD, Castle, etc).

Honestly you are just over thinking the button thing. Think about the touch events. touchesBegan fires when the object is clicked if you want it to fire on finger up call touchesEnded

Here is a very simple button class I wrote for this example, there are a lot of things more you could do with this, but this covers the basics. It decides if the button will click on down or up and will not click if you move your finger off the button. It uses protocols to pass the click event back to the parent (probably you scene)

you can also add this to an sks file by dragging a colorSprite/ or image onto the scene editor and making it a custom class of "Button" in the Custom Class Inspector. the Button Class...

protocol ButtonDelegate: class {
    func buttonClicked(button: Button)
}

class Button: SKSpriteNode {

    enum TouchType: Int {
        class down, up
    }

    weak var buttonDelegate: ButtonDelegate!
    private var type: TouchType = .down 

    init(texture: SKTexture, type: TouchType) {

        var size = texture.size()

        super.init(texture: texture ,color: .clear, size: size)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        isPressed = true

        if type == .down {
            self.buttonDelegate.buttonClicked(button: self)
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

       if let touch = touches.first as UITouch! {

            let touchLocation = touch.location(in: parent!)

            if !frame.contains(touchLocation) {
                isPressed = false
            }
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard isPressed else { return }

        if type == .up {
            self.buttonDelegate.buttonClicked(button: self)
        }

        isPressed = false
    }
}

In your GameScene file

class GameScene: SKScene, Button {

    private var someButton: Button!
    private var anotherButton: Button!

    func createButtons() {

        someButton = Button(texture: SKTexture(imageNamed: "blueButton"), type: .down)
        someButton.position = CGPoint(x: 100, y: 100)
        someButton.Position = 1
        someButton.name = "blueButton"
        addChild(someButton)

        anotherButton = Button(texture: SKTexture(imageNamed: "redButton"), type: .up)
        anotherButton = CGPoint(x: 300, y: 100)
        anotherButton = 1
        anotherButton = "redButton"
        addChild(anotherButton)
    }

    func buttonClicked(button: Button) {
        print("button clicked named \(button.name!)")
    }
}
Ron Myschuk
  • 6,011
  • 2
  • 20
  • 32
  • Good advise - but doesn't this question apply to any 'storyboard' type UI element? Maybe a mini table present in the game? – Joe Apr 06 '19 at 01:59
  • 1
    yes, if you wanted to have touch interactivity with it, because the main point of this answer is to tell OP how to get the touch event from the object back to the scene. – Ron Myschuk Apr 06 '19 at 14:20