Lummox Labs

Mobile app maker since 2015

Action Animation in Forbidden Desert

Haven't played Forbidden Desert yet? Grab it here!

In the mood for a puzzle game instead? Try out Noodles!


In the last few posts I've discussed how Forbidden Desert uses the Action pattern, with GameAction objects, to organize game changes in the app.

Here I'm going to look at another huge part of the app, and a part that Actions drive: Animation.

The vast majority of the visual changes during a game of FD come from changes in the game itself: A player moves to a new tile, sand piles on a tile, the storm rages across the screen, etc. All those animations are directly tied to changes in the game's state. And all game state changes are directly tied to GameAction objects, so it's natural to use those Actions to organize all the animations (and there are a lot of them).

Here's the basic idea in code:

class GameViewController: UIViewController {
...
  func doActionAndUpdate(action: GameAction, completion: (() -> ())? = nil) {
    // Change the game state
    action.doAction(self.game) 
    
    // Animate!
    self.animationManager.animateAction(action,
      controller: self,
      game: self.game,
      isUndo: isUndo,
      completion: completion)
  }
}

class AnimationManager {
...
  func animateAction(action: GameAction, controller: GameViewController, game: Game, isUndo: Bool, completion: (() -> ())?) {
    
    let completionOperation = NSBlockOperation(block: { () -> Void in
      if let completionUnwrap = completion {
        dispatch_async(dispatch_get_main_queue()) { completionUnwrap(areThereMoreActions: false)}
      }
    })
    
    if let animateOperation = action.animationOperation(controller, game: game, isUndo: isUndo) {
      completionOperation.addDependency(animateOperation)
      self.animationQueue.addOperation(animateOperation)
    }
    
    self.animationQueue.addOperation(completionOperation)
  }
}

So! Animations all happen with NSOperations, which provide a very flexible way to organize them. Sometimes we'll need to show 2 animations simultaneously, and sometimes we'll need to show 2 animations serially, and that logic is all wrapped up in an NSOperation, based on the specific needs of that GameAction.

The most important part of the code is this:

let animateOperation = action.animationOperation(controller, game: game, isUndo: isUndo)

You can see that each action is responsible for creating an NSOperation that fully contains all the related animations. Let's check out what that looks like:

extension GameAction {
...
  func animationOperation(controller: GameViewController, game: Game, isUndo:Bool) -> NSOperation? {
    
    // Get the animation for the main part of the GameAction.
    let operationOpt: NSOperation? = (self as? FDAnimatable)?.animationOperationInternal(controller, game: game, isUndo: isUndo)
    
    // Recursively get all animations for SubActions.
    let subactionOpt: self.subactionOperation(controller, game: game, isUndo: isUndo)
    
    // Combine them all into one!
    let operations = [operationOpt, subactionOpt].flatMap{ $0 }
    return MultiOperationOperation(operations: operations)
  }
    
  func subactionOperation(controller: GameViewController, game: Game, isUndo:Bool, serialized: Bool = false) -> NSOperation? {
    let subOperations = subactions.flatMap {
      $0.animationOperation(controller, game: game, isUndo: isUndo)
    }
    
    let subactionOperation = MultiOperationOperation(operations: subOperations, serialized: serialized)
    return subactionOperation
  }
}

Each GameAction specifies its own animations, and is given complete flexibility to do so. In the simple case, an action can ignore animating subactions, since those GameAction classes will define their own animation NSOperations.

A couple of notes about the code:

FDAnimatable is a protocol that's used here to allow GameAction subclasses to optionally provide an operation. When this was written, protocols were much less powerful, so there may be a more elegant way to accomplish this in Swift 2.

MultiOperationOperation is a brilliantly-named custom class that just groups other operations together, and finishes when all the suboperations have finished.

So what does this look like for actual actions?

extension JetpackAction: FDAnimatable {

  func animationOperationInternal(controller: GameViewController, game: Game, isUndo: Bool) -> NSOperation? {
    
    let animateOperation = MainThreadAsyncOperation { (operation) -> Void in
      controller.playerViewWithId(self.playerId).putJetpackAway() {
        operation.finish()
      }
    }
    
    return animateOperation
  }
}

That's ... quite short. But other stuff happens when a player uses the jetpack. Most importantly, the player moves to a new tile. But remember that JetpackAction has subactions, one of which is a MoveAction. So MoveAction will define its own animation, and it gets rolled up automatically into the animation NSOperation for JetpackAction. The great thing about this is MoveAction can be a subaction of different GameActions, and this behavior means in all those cases, we'll see the player move between tiles.

If you're interested, here's MoveAction:

extension MoveAction: FDAnimatable {
  func animationOperationInternal(controller: GameViewController, game: Game, isUndo:Bool) -> NSOperation? {
    
    let animateOperation = MainThreadAsyncOperation(mainThreadBlock: { (operation: MainThreadAsyncOperation) -> Void in
    
      let playerView = controller.playerViewWithId(self.playerId)
    
      UIView.animateWithDuration(0.3,
        animations: { () -> Void in
          playerView.center = // Position on the new tile.
        },
        completion: { _ -> Void in
          operation.finish()
      })
    })
    
    return animateOperation
  }
  
}

Once that architecture is in place, you have total flexibility on how to make actions look in the UI. They compose together nicely, and it's easy enough to add code to do the same thing with sounds in the game, achievements, etc. 

And that's how Forbidden Desert does animations!

Game History with Actions in Forbidden Desert

Haven't played Forbidden Desert yet? Grab it here!

In the mood for a puzzle game instead? Try out Noodles!


This post is one in a series about the Action pattern used in Forbidden Desert on iPad.

So in the previous post we looked at what an Action is, and what it looks like in Swift. Now let's talk about one of the great benefits the game gets from the Action pattern.

The actions have these two methods:

final func doAction(game:Game) -> ()
final func undoAction(game:Game) -> ()

Which are super-easy to use for any Action.

let action = ExcavateAction(tileId: "equip0")
action.doAction(game)
...
action.undoAction(game)

So how can we use this to make an easy game history? Well, let's add a list of everything that's changed the game.

class Game {
  var actionHistory: [GameAction] = [] 
  ...
}

And now every time you perform an action, add it to the history.

let action = ExcavateAction(tileId: "equip0")
action.doAction(game)
game.actionHistory.append(action)

Now you've got enough information to rewind the entire game right to the beginning, action by action. Just keep pulling the last action in the list, and calling undoAction(game). 

You could add a slider to your game that lets a user slide back and forth in history, or easily get a count of how many moves there ever were. There's lots of power hidden in that list of actions.

But the biggest win is just giving the user the ability to Undo to the beginning of their turn, with confidence that the game state won't get messed up with so much change flying around. As long as each action is internally consistent (that undoActionInternal perfectly reverses doActionInternal) then the game will stay consistent too.

We'll take a look in future blog posts at some of the other benefits to the Action pattern.

Action Oriented Gaming in Forbidden Desert

Haven't played Forbidden Desert yet? Grab it here!

In the mood for a puzzle game instead? Try out Noodles!


There are so many posts on the web talking about how to accomplish small tasks in a language, like "How to mask an image in Swift". And lots more that talk about abstract architecture patterns, like Model-View-Controller. This is somewhere in-between. I'm going to describe the super-powerful code pattern that powers Forbidden Desert, and what benefits we get from using it. 

Preamble

Forbidden Desert is a user-driven game, owing to it being a physical board game first. When playing the physical version, humans are literally powering the game, and so in the port it's no surprise that everything that happens is triggered by the user. Many other games, particularly action games are time-based, and more tightly tied to an event loop.

When building FD, there were a bunch of features we knew we needed.

  • Undo - players need to be able to rewind their turn
  • Animations for pretty much everything that happens
  • Online Multiplayer 

And there are so many rules in a board game. There are tons of possible things a player can do on their turn, and lots of different combinations based on a player's Role, so our model needs to be really scalable.

The Action Pattern.

Also known as the Command Pattern, it's a simple idea. The game state is an object, and everything that's part of the game is in that object. The players, their roles, where the tiles are on the board, where the sand is on the tiles, what parts have been already retrived, how much water each player has, and on and on. Everything that together makes up the game at any particular moment is in a Game object (and sub-objects).

class Game {
  var players: [Player]
  var board: Board
  var currentPlayerIndex: Int
  ...
}

Any time the game needs to change it's state - say, when a player moves to a new tile, or a new Storm Card flips over - you don't change the Game object directly. Instead, you create an Action object, and perform it on the Game. The Action is the only entity allowed to change the Game object. Let's look at it in code:

class GameAction {
  var subactions: [GameAction] = []
 
  final func doAction(game:Game) {
    // First perform this action, then all subactions in order.
    self.doActionInternal(game)
    
    for subaction in self.subactions {
      subaction.doAction(game)
    }   
  }
  
  final func undoAction(game:Game) {
    for subaction in self.subactions.reverse() {
      subaction.undoAction(game)
    }
    
    self.undoActionInternal(game)
  }
}

Simple! To change the game you just call doAction(game). To undo it, call undoAction(game). The action changes the game object, and every action knows enough to undo itself.

So now you can split every change to the game into small, focused actions. And for anything complex, notice that the GameAction has a subactions array, so you can group multiple actions together easily.

Let's check out an example of an Action ... in action. Here's how players move around the board, with a MoveAction:

class MoveAction: GameAction {
  var playerId = "player1"
  var fromTileId = "mirage"
  var toTileId = "launchPad"
  
  init(playerId: String, fromTileId: String, toTileId: String) {
    ...
  }
  
  override func doActionInternal(game: Game) {
    // Get the player, move them.
    if let player = game.playerWithId(self.playerId) {
      player.tileId = toTileId
    }
  }
  
  override func undoActionInternal(game: Game) {
    if let player = game.playerWithId(self.playerId) {
      player.tileId = fromTileId
    }
  }
}

And what about something with subactions? Well, let's take a look at another action that uses MoveAction: JetpackAction:

class JetpackAction: GameAction {
  var playerId: String = "player1"
  var alongForTheRidePlayerId: String? = nil
  
  var fromTileId: String = "mirage"
  var toTileId: String = "launchPad"
    
  init(playerId: String, fromTileId: String, toTileId: String, withPlayerId: String? = nil) {
    self.playerId = playerId
    self.fromTileId = fromTileId
    self.toTileId = toTileId
    self.alongForTheRide = withPlayerId
    
    super.init()
  }
  
  override func doActionInternal(game: Game) {
    let allIds = [self.playerId, self.alongForTheRidePlayerId].flatMap{ $0 }
    
    let moveActions = allIds.map{ (moverId) -> GameAction in
      let moveAction = MoveAction(playerId: moverId, fromTileId: self.fromTileId, toTileId: self.toTileId)
      return moveAction
      }
    self.addSubactions(moveActions)
    
    self.addSubaction(RemoveEquipmentAction(playerId: self.playerId, equipment: .Jetpack))
  }
  
  override func undoActionInternal(game: Game) {
    // Nothing for undo, since it's all wrapped in subactions. :)
    // The base GameAction class will handle undoing the subactions.
  }

}
  

Seems like a bit of overhead just to change a few variables in the game, right? Well, yeah. But keep all game changes in these actions, and you get a lot of power out of it. I'll talk about these benefits in more detail in upcoming blog posts.

Solving noodles puzzles

Haven't noodled yet? Download noodles here!


Shortly after building the prototype I realized that testing would not be fun if there's a 2-5 minute gap before testing some level-complete code. I needed the phone to solve the puzzles for me.

Before I start, I will say this: There may be a specific algorithm to solve this, something elegant from graph theory. I don't know it. Drop me a line if you do.

ATTEMPT 1: Brute Force!

  • Result: Ha! 10 minutes per solve, slower than I am.

ATTEMPT 2: Brute force with backtracking & smart pruning

  1. Start at (0,0). Set the piece to point North.
  2. Check if the orientation is valid. If the current piece now points off an edge of the puzzle, no good. If the piece points at an earlier piece (earlier row or same row, earlier column), and only one of the pieces points at the other, no good.
  3. If the orientation is invalid, rotate the piece once clockwise and try again.
  4. If the orientation is possible, move on to the next piece in the puzzle and try to set that.
  5. If none of the orientations is possible, back up a step to the piece before. 
  6. On the last piece of the puzzle, check if every piece is connected (using our BFS).
  7. Connected? Done. Not connected? Back up a step.
  • Result: This really depended on the specific puzzle, but it wasn't fast. Anywhere from about 10 seconds to 2 minutes per solve.

ATTEMPT 3: Possibility sets

  1. For each piece, mark the possible orientations (every direction, to start).
  2. GOTCHA: Some pieces have multiple orientations that are the same. For example, a straight line can point north or south and both would be a valid solution. This confuses the possibility sets, so you have to eliminate duplicates in step 1. 
  3. Piece by piece, remove impossible orientations from the possibility set for that piece, using the same rules as above.
  4. Once a piece has only one possibility, it's "locked" and we know the final orientation. Then the piece can be used to eliminate possibilities from its neighbours. 
  5. Cycle through the pieces until you have a solution, or until you're stuck. It will take many passes.
  6. If you're stuck (you've gone a full pass without making any changes to sets) then use brute force on the remaining unlocked pieces.
  • Result: Much better. Most puzzles, and all smaller puzzles, take < 1s. Sometimes larger puzzles can take 10s or so, but it's less common.

ATTEMPT 4: Possibility sets with smarter ordering.

  1. Do attempt 3, but instead of going through in piece order, start at the edges of the puzzle where you are most likely to lock pieces immediately.
  • Result: This saves a little bit of time, but nothing to write home about.

So after 4 attempts, we've got a reasonable solve that worked for testing. Since it was debug-only I didn't worry too much about it. But there are certain features we're thinking of adding that would require knowing the solution, and I can't have a 10 or 20 second delay to find it.

And as sometimes happens, I bailed on an algorithmic solve, and did what I should have done in the first place:

ATTEMPT 5: Just store the solutions with the damn puzzles.

When I generate the puzzles they are all connected anyways, so it's just a matter of recording the orientations and putting them in the json. 

  • Result: Instantaneous solve, and a bit of shame for previous wasted time.

One small catch: I already generated the puzzles, and already submitted a build to Apple, so I really didn't want to re-generate puzzles. For anyone who had played the game already, their best scores would be all messed up.

So for all the game packs, I wrote a small bit of code to load the pack's puzzles in json, called solve() for each game, and wrote the solution back to the puzzle json. Levels stay the same, and I just add solutions to each of them. So my little solve() method got production use after all...


Generating noodles puzzles

Haven't noodled yet? Download noodles here!


So it must take a long time to think up so many connected noodles puzzles, right?

Wrong! Even though the levels look and feel amazing, each one more impressive than the last, they are actually generated using what the cool kids call "algorithms". And here's how:

In the last post I mentioned that Noodles puzzles are graphs. But we can go further. Fully-connected puzzles have no cycles, so it's a fully-connected acyclic graph. In fact, if you want to consider the source node as a root, the whole thing is an n-ary tree, though that doesn't impact puzzle generation. 

So who cares? Well, to generate puzzles we fall back on some nice graph algorithms. To generate puzzles, here's what we do:

  1. Start with a bunch of nodes with no edges.
  2. Choose a node randomly. That's your graph so far.
  3. Pick a random node in the graph, connect it to a random adjacent node not in the graph.
  4. Repeat 3 until all nodes are in the graph.
  5. Pick a piece to be your Source. (whispers) which piece doesn't actually affect the puzzle at all... 

There are a few complications in those directions. One is that sometimes a node in the graph can't connect to anything around it, because it's reached the max connections (in square games, I set that max to 3. In hex games, 4) or because everything around it is in the graph. When this happens, you can just try another node, or keep track of the nodes that can be used, and take the problem node out of that list.

Another is that there's a small chance that this process will connect your graph in such a way that makes it impossible to have a fully-connected graph. So you have to have a way to error out and try again. Luckily, the error rate isn't very high.

So why does this work? Well, the short answer is this: Any acyclic, connected graph is a valid puzzle. At each step of the algo you're making a new edge, and one of the nodes is not in the graph. You're never connecting two already-connected nodes, so you can't create any cycles that way.

Best part? The algorithm works great for any puzzle type. The rules just change in step 3, for which nodes are candidates to connect with which other ones.

Michael, does this mean I could have a game with heptagons? FOOL. THAT'S JUST WHAT HEPTAGONS WOULD HAVE YOU THINK. 

Updating noodles puzzles

Haven't noodled yet? Download noodles here!


This is the first of (what will likely be) three posts on some algorithms used in building Noodles.

I'll start off with this link. That is pretty much amazing, and I wish I had known about it when I started building the hex games. The trickiest things with hexagons (ignoring design challenges) is the math in placing them because columns are offset, and the hexes don't have equal height and width. Read up there on how to do that math. Or do high school trig again.

Okay, so what is a Noodles puzzle, as a data structure? Well, if you think of the pieces as nodes and the connections between them as edges, it's a graph. Let's say an edge exists between two nodes (x, y) and (a, b) only if they both connect to each other. Like this:

Connected

Connected

Pieces that are connected to the Source, the dark ones in the game, I refer to as "powered" in code. So to find out which pieces are powered, you just go through the edges of the graph, starting at the source, and any node you reach has power. A simple breadth-first search will do the trick. I use a BFS for a bunch of stuff in the game, so I created a BFS function. 

The thing is, the two types of puzzles, squares and hexes, have very different rules: Different piece types, and even different pairs of indices that could be connected. So the BFS function allows the caller to pass in these "rules". That way you can use it for any game type, any graph. The rules are: 

  1. What node(s) to start with
  2. Which nodes are adjacent
  3. What makes two nodes equal?
/**
Perform a Breadth-first-search on ... well, anything!
:param: startNodes A list of nodes that comprise level 0.
:param: levels How deep to search the tree. Will stop after levels has been reached. Pass 0 for no limit.
:param: equalNodes A closure to determine when two nodes are equal.
:param: adjacentTo A closure to determine what nodes are adjacent to a given node.
:param: visited A closure called once for each visited node.
*/
func breadthFirstSearch<T: Hashable>(startNodes: [T],
  levels: Int = 0,
  equalNodes: (lhs: T, rhs: T) -> Bool,
  adjacentTo: (node: T) -> [T],
  visited: (node: T, level: Int) -> Void) {
    
    // Hashcodes
    var seenNodes = [T: Bool]()
    var nextNodes = [T](startNodes)
    
    for startNode in startNodes {
      seenNodes[startNode] = true
    }
    
    var actualLevels = (levels > 0) ? levels : 1000
    for level in 0 ..< actualLevels {
      var tempNextNodes = [T]()
      
      for nextNode in nextNodes {
        
        visited(node: nextNode, level: level)
        
        let adjacentNodes = adjacentTo(node: nextNode)
        for adjacentNode in adjacentNodes {
          if (seenNodes[adjacentNode] == nil) {
            tempNextNodes.append(adjacentNode)
            seenNodes[adjacentNode] = true
          }
        }
      }
      
      nextNodes = tempNextNodes
      
      if (nextNodes.count == 0) {
        // We're done! We've been through the whole thing.
        break
      }
    }
}

And with that, finding the powered nodes is straightforward:

  func updatePowered() {
    // Flag everything as unpowered to start
    for piece in self.pieces {
      piece.powered = false
    }
    
    // Set up the BFS
    let equalBlock: (GamePiece, GamePiece) -> Bool = { lhs, rhs in
      return lhs.index == rhs.index
    }
    
    let adjacentBlock: (GamePiece) -> [GamePiece] = { node in
      return self.connectingPiecesToPoint(node.index)
    }
    
    let visitedBlock: (GamePiece, Int) -> () = { node, level in
      node.powered = true
    }
    
    let sourceNodes = self.pieces.filter{ $0.source }
    
    breadthFirstSearch(sourceNodes,
      levels: 0,
      equalBlock,
      adjacentBlock,
      visitedBlock)
  }

And that's it! every time the user rotates a piece I run updatePowered() and update the visual state of the game. Easy peasy.

And bonus: I use the same BFS function to generate the "disappear" animation when you finish a puzzle.

Footnote for the interested: The adjacentBlock in the code above is a simplified version of the one I actually use. It was getting slow to recalculate which pieces are connected so many times, and they don't change for the duration of the method, so I cache the list of adjacent nodes for every piece. 

Import fun

For those of us working in Objective C... 

At my day job with FreshBooks in Toronto we came across a strange issue last week. After making some changes, Xcode started giving my colleague Jameson an error that it couldn't find an #imported header from a Cocoapod. The import was in a file in the test project that he hadn't touched. Nobody else's machine exhibited the problem.

#import <KeyChainAccess/KeyChainAccess.h>

// Can't find header <KeyChainAccess/KeyChainAccess.h> ...

So we tried a bunch of stuff: Try with a fresh repo (fine), look for changes in the pod (none), check the xcode version (same on his machine as on mine). No luck.

The next thing to look at was the Search Paths. There are a number of build settings that dictate where Xcode looks for headers where building. For headers imported with <>, the Framework Search Path is where you want to look. For anything coming from a cocoapod, it's the .xcconfig file that cocoapods generates that will add the right paths to the Search Path build setting. So 

  1. Make sure the .xcconfig file from cocoapods is being used. Check this in the build settings for the project (not the targets). There you can set a per-configuration .xcconfig file which should show the pod xcconfig.
  2. In Build Settings for the target, filter for "Search Path", and press the "Levels" button to see where all the various paths are coming from, and how they are inherited.
Search Paths from a different project

Search Paths from a different project

All of that looked fine on both our machines. And besides, that wouldn't explain why it was failing for him but working for me.

If the Search Paths are set correctly, then Xcode's autocomplete should be able to help out with the #import. So we tried it out on his machine, and sure enough autocomplete worked. That's so odd: Xcode can find the header for autocomplete but not compiling??

Just because, Jameson compiled at this point and it all worked. All we had changed is to re-write the same #import using autocomplete. So we looked at the diff to see what (if anything changed) the diff marked the #import as changed, but it looked the same. ALMOST the same! Notice the difference?

// Bad
#import <KeyChainAccess/KeyChainAccess.h>

// Good
#import <KeychainAccess/KeychainAccess.h>

Okay, yeah. It's easy to see when I lay them out like that. The bad one has a "C" instead of "c". Success! Well, sort of. So Xcode was complaining that it couldn't find that file because we were asking for a file that doesn't exist. That makes sense, but why was the same, misspelled line working on my machine that was failing on his?

We talked about what the changes he had made. And in cleaning up a bunch of #imports, he removed a bunch from other header files (awesome). So in my version of the codebase, the misspelled #import was preceded (through a chain of imports) by another, correctly spelled import, like this:

#import <KeychainAccess/KeychainAccess.h>
...
// A bunch of code imported from a bunch of headers
...
#import <KeyChainAccess/KeyChainAccess.h>

So as long as the misspelled #import follows a correctly-spelled one, it's fine?? Why would that be the case? (See what I did there?)

#import is a bit of helping syntax on #include. In my C++ days, you had to watch out for #including headers twice, because it could cause duplicate symbols. So you surrounded pretty much every header with preprocessor commands to ignore the content if it's already been #included. Like this:

// In MyHeader.h

#ifndef __MY_HEADER_H__
#define __MY_HEADER_H__

... all the codes ...

#endif

You had to do this ALL THE TIME. So in Objective C, #import is like a smart #include, in that it does that for you! But notice what happens when you write the #ifndef: The casing is lost on the header name!

So in our case, the correctly spelled header is #imported. #import creates something like #ifndef for you. Then when you try to #import the misspelled header, it checks #ifndef __MY_HEADER__, finds that it *was* defined before, and doesn't bother trying to find it at all. 

I think, anyways. One of the problems I had while confirming this myself in a test project is that my #imports at home seem to be case-INsensitive. I can happily #import "mYhEaDeR.h" and xcode just figures it out. So there's something at work that I don't know about that makes it matter. 

Regardless, it was an interesting problem to chew on...

Paletteable.

Note: For the remainder of the post we will ignore the fact that throughout the codebase the spelling "palate" was used. Shameful.

Note: Download Noodles here!


Once we settled on an abstract style for Noodles, the colour became really important. Jibran (designer extraordinaire) and I wanted a different colour for each "puzzle pack", or puzzle size. The idea was that when you pick a pack, everything gets tinted to match the colours of that pack. Then the main screen, anything before a pack is loaded, would take the colour of the last pack played. 

Here are a few simple things we did to make this as easy as possible.

Noodles really only uses two colours for each palette - a base colour for the background, and a main colour. Though everything here would work just as well with more complex palettes.

First up, Jibran needed to be able to play with the palettes really easily, to tweak colours. We created an xib file with a bunch of palettes he could play with. In code I just grab the background colour and text colour, which creates each palette. You could easily beef up the xib to include other colours, text strings, or anything else. 

I do what I can

I do what I can

Okay, now we have an easy way to choose and edit palettes, how does the code actually use them? 

First, there's a Palette object, which is a simple container for the different colours/properties.

class Palette: NSObject {
  var baseColor: UIColor = UIColor.whiteColor()
  var textColor: UIColor = UIColor.blackColor()
}

Any keen-eyed observers wondering why the Palette is an NSObject, it's only because it's used in some protocols that require it.

All view controllers have a Palette variable, and an init method that requires a Palette, and a styleWithPalate() method that sets all colours.

  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    ...
    
    self.styleWithPalate()
  }
  
  func styleWithPalate() {
    StyleUtilities.styleNavigationBar(color: self.palate.textColor)

    self.view.backgroundColor = self.palate.baseColor
    
    let labels = [self.playButton, self.nextButton]
    labels.doEach{ $0.textColor = self.palate.textColor }
    
    let buttons: [UIButton] = [self.legalButton, self.resetButton]
    buttons.doEach{ $0.setTitleColor(self.palate.textColor, forState: .Normal) }
  }

Keen-eyed observers, yes! I don't use the tintColor property at all! Mostly because it has limited use: the buttons will use it, but nothing else: borders, labels, images. However, I think you could write some clever code to style labels and borders based on their tint colours, and perhaps cascade the tint a little better. Try it out!  

You could get clever to avoid writing the (fairly repetitive) styleWithPalate method, but the app is small enough that I left it simple.

Mostly, the Palettes are passed around, so the PackViewController passes its Palette to the GameViewController, which passes to the PuzzleCompleteViewController, etc. This way there isn't a lot of singleton access of the manager that loads the colours from the xib. And Palettes aren't strongly tied to packs, which easily allows us to use them in screens (like the about screen) that have nothing to do with packs. 

What else do we do with palettes? One of the biggest things is the noodles themselves: we only have one set of assets for the pieces, and in code we colour them to create the correct UIImages.  

  class func imageFromImage(image: UIImage, cacheKey: String, withColor color: UIColor, overlayImageOpt: UIImage? = nil) -> UIImage {

    if let cachedImage = styleUtilitiesImageCache[cacheKey] {
      return cachedImage
    }
    
    let rect = CGRectMake(0.0, 0.0, image.size.width, image.size.height)
    
    UIGraphicsBeginImageContextWithOptions(rect.size, false, image.scale)
    
    let context = UIGraphicsGetCurrentContext()
    
    image.drawInRect(rect)
    
    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextSetBlendMode(context, kCGBlendModeSourceAtop)
    CGContextFillRect(context, rect)
    
    if let overlayImage = overlayImageOpt {
      overlayImage.drawInRect(rect)
    }
    
    let result: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    styleUtilitiesImageCache[cacheKey] = result
    
    return result
  }

Note the use of a cache in there: One of the downsides to this code is that you lose the built-in caching of UIImage(named: ), so we cache the coloured images ourselves.

This code replaces the colour of the source image with the new colour, respecting the alpha channel. So semi-transparent parts of the source image still are semi-transparent in the final image. 

Our use of palettes is super simple, but I like the patterns because they scale nicely to have easily-swappable, complex palettes in the future. Enjoy!

Login with Facebook. If you're lucky.

I'm working on a project where we've decided to support log in with Facebook. To start, I grabbed the docs from facebook's developer page. Registered a facebook app and matched the id with my app's bundle id. Put all the facebook plist nuggets in place in my app, fixed a transcription error (why no error messages, FB?) fixed a FB app setting error ("the app is not set up correctly". thanks.) and got login working after a couple hours.

At this point I should point out that despite a little pain, FB has made it remarkably easy. Just add a custom UIView as the login button and magically everything else works. Mostly.

The current problem is that the token isn't persisting between app launches, when it really should. So here's how I debugged it. This is for interest's sake; I'm writing this before I have the answer, so it's not a tutorial on how to fix bugs like a boss.

Step 1: Google. Nobody seems to be having this problem, so it's likely a config issue.

Step 2: Log everything I can about the token when FB gives it to me. Log the token on app start (nothing) and at login (something!). Verify that I can retrieve the token from the FB SDK after login is done. Check.

Step 3: Scour the FB documentation to find a step I missed, maybe a missed framework or something? Everything looks good, and I made sure the the Security framework was in the app, in order to use the secure keychain.

Step 4:  Download the FB SDK source (thanks, FB!). How is the token stored? The code was fairly easy to read, but there is lots going on, lots of little macros and helper function, and the keychain isn't easy to deal with to start. Looks like they store a UUID in NSUserDefaults, and the token in the keychain, associated with the UUID as a sanity check.

Step 5: Print out the contents of NSUserDefaults and Keychain at app launch. Time to get my hands dirty. NSUserDefaults has a UUID but no token, as expected. Keychain seems to have ... something but it takes a little finagling to print out whatever the data represents. The data in the keychain is NSData that's an NSArchive of an NSDictionary. I copy-pasted the code they use to unarchive it, and I've got a (surprisingly large) string of data called "tokenEncoded". I didn't bother to decode it because I've verified the most important thing: The token is there! 

So why the crap can't FB uncache and return it for me on a fresh launch? That's where I'm at now.

Update: More steps!

Step 6: Okay, so the token is in place in the keychain, maybe the Facebook SDK isn't trying to load it from cache? So check FBSDKTokenAccess to see where the cached token is actually set. Look for "g_currentAccessToken =". It's only set in +setCurrentAccessToken. So search for that. Among other places, it's called in FBSDKApplicationDelegate.application:didFinishLaunchingWithOptions:

Wait a tick. I'm definitely not calling that method. So these lines aren't being executed:

  FBSDKAccessToken *cachedToken = [[FBSDKSettings accessTokenCache] fetchAccessToken];
  [FBSDKAccessToken setCurrentAccessToken:cachedToken];

Which is a pretty good candidate for why the token isn't loading: Nobody asked to retrieve it from the keychain!

Lest you wonder, Facebook's guide doesn't mention that little part, though it is clear from the code comments that it's necessary:

/*!
 @abstract
 Call this method from the [UIApplicationDelegate application:didFinishLaunchingWithOptions:] method
 of the AppDelegate for your app. It should be invoked for the proper use of the Facebook SDK.

...

And sure enough, from my own didFinishLaunching, I call FBSDK didFinishLaunching, and everything is happy again. Another half-day wasted...