Home > Software design >  Create a moving Button for a Game in Swift
Create a moving Button for a Game in Swift

Time:05-04

I have an assignment where I need to create a game with SpriteKit. It should have a button moving randomly within a view and if I click on it I get points. The issue is that I have no idea how to create a button in SpriteKit.

Do I need to do a workaround by using a SKSpriteNode? But how would I make it look like a standard button? Or can I actually create a button somehow for that?

CodePudding user response:

SpriteKit has no built-in SKButton class. but we can build some basic functionality. as sangony said you need three parts: draw the graphics (I'm using SKShapeNode for simplicity but you could use SKSpriteNode); move the node; add picking functionality. here is some code to illustrate.

Draw

add a SKShapeNode or SKSpriteNode to your SKNode class

shape = SKShapeNode(circleOfRadius: 40)
shape.fillColor = .green
addChild(shape)

Move

SKAction is very useful. here is an example that moves to a random position, then recursively calls itself. stop/go is regulated by a boolean flag.

func movement() {
    print("movement")
    let DURATION:CGFloat = 2.0
    let random_x = CGFloat.random(in: -200...200)
    let random_y = CGFloat.random(in: -200...200)
    let random_point = CGPoint(x: random_x, y: random_y)
    let move = SKAction.move(to: random_point, duration: DURATION)
    move.timingMode = .easeInEaseOut
    let wait = SKAction.wait(forDuration: DURATION)
    let parallel = SKAction.group([move,wait])
    
    let recursion = SKAction.run {
        if self.isInMotion { self.movement() }
    }
    let serial = SKAction.sequence([parallel, recursion])
    self.run(serial)
}

Pick

Testing for user clicks in a scene is called picking. I use a PickableNode protocol which helps filter out which SKNodes you want to be clickable.

extension GameScene {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches{
            //call `pick` on any `PickableNode` that exists at touch location
            let location = touch.location(in: self)
            let _ = self.nodes(at: location).map { ($0 as? PickableNode)?.pick() }
        }
    }
}

Here is the whole completed class

protocol PickableNode {
    func pick()
}

class Button: SKNode, PickableNode {
    let shape:SKShapeNode
    var isInMotion:Bool = true
    override init() {
        shape = SKShapeNode(circleOfRadius: 40)
        shape.fillColor = .green
        super.init()
        addChild(shape)
        movement()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func movement() {
        print("movement")
        let DURATION:CGFloat = 2.0
        let random_x = CGFloat.random(in: -200...200)
        let random_y = CGFloat.random(in: -200...200)
        let random_point = CGPoint(x: random_x, y: random_y)
        let move = SKAction.move(to: random_point, duration: DURATION)
        move.timingMode = .easeInEaseOut
        let wait = SKAction.wait(forDuration: DURATION)
        let parallel = SKAction.group([move,wait])
        
        let recursion = SKAction.run {
            if self.isInMotion { self.movement() }
        }
        let serial = SKAction.sequence([parallel, recursion])
        self.run(serial)
    }
    
    func pick() {
        print("i got picked")
        if !isInMotion {
            isInMotion = true
            shape.fillColor = .green
            movement()
        } else {
            isInMotion = false
            shape.fillColor = .red
            self.removeAllActions()
        }
    }
}
  • Related