Creating D-Pad Controls for an iOS Game in Swift & SpriteKit

This is part of a free course that teaches game design and the Swift programming language. It contains examples from a real game I created called ForeverMaze. The full course includes the source code for the whole game.

Learn how to control a character for your game with “D-Pad.” This tutorial will show you how to use Swift to create a simple but powerful control structure.

Download Direction.swift

What Is a D-Pad?

D-PadA “D-Pad” is short for “directional pad,” one of the most common game controller input styles.

Of course, modern mobile devices do not have physical buttons. So we need to create our own D-Pad implementation. In ForeverMaze, the player simply presses somewhere on screen and then drags his finger around. The original press acts as the center point of the D-Pad, and the distance he moves from that center point indicates the direction to move in.

I found that this was a very simple and intuitive way to control characters in ForeverMaze. In my testing, every single user was able to figure it out within seconds. The only trick with implementation was the fact that the game is 2.5D, meaning everything is rotated by 45 degrees. Let’s see how that works…

Detecting User Input in SpriteKit

Your SKScene subclass will need to detect the user input. This means simply overriding methods like touchesBegan . From there,  we simply keep track of the touches. If at any time we want to know what direction the user is facing, we can access the variable self.dPadDirection  … which will return nil  if the user is not currently trying to move.

  var touches = Set<UITouch>()

  var dPadDirection:Direction? {
    if self.touches.count != 1 {
      return nil
    }
    let touch = self.touches.first!
    let loc = touch.locationInView(self.view)
    if distance(loc, p2: firstTouchLocation) < 3 { // minimum distance to be considered movement
      return nil
    }
    let coords = loc - firstTouchLocation
    let degrees = 180 + Int(Float(M_PI_2) - Float(180 / M_PI) * atan2f(Float(coords.x), Float(coords.y)))
    return Direction(degrees: degrees)
  }

  func updateTouches(touches: Set<UITouch>) {
    if self.touches.count <= 0 && touches.count > 0 {
      firstTouchLocation = touches.first!.locationInView(self.view)
    }
    self.touches.unionInPlace(touches)
  }

  func endTouches(touches: Set<UITouch>) {
    self.touches.subtractInPlace(touches)
    firstTouchLocation = CGPointZero
  }

  override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.updateTouches(touches)
  }

  override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.endTouches(touches)
  }

  override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
    self.endTouches(touches!)
  }

  override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.updateTouches(touches)
  }

That’s it! Quite simple, really.

If you enjoyed this post, why not enroll in the free course? It contains hours of video content, source code downloads, examples and more. I cover many different intermediate and advanced topics for creating a real-time game in Swift with SpriteKit and Firebase. You can check out the complete game at ForeverMaze.com.

[author]

Leave A Comment

You must be logged in to post a comment.

Back to Top