Hours Remaining: 31
Days 9 & 10
Days 9 & 10 were mostly spent fixing the giant horrible mess that I’d created getting things to work.
Once I had a better understanding of how it all fit together, it was time to make the code more manageable. I also realised I’d made a pretty significant error in how I was handling attaching Actors to Zones.
This issue (the Reattachment Problem) was that Actors would quickly re-attach themselves to a Zone they were previously attached to when touches began. It was all to easy for the SKPhysicsContactDelegate
to be called after the player accidentally brushed the Actor they had started touching against the Zone it was just attached to. Incredibly frustrating if you’re playing against a clock.
My first pass involved trying to keep track of which Actors were attached to which Zones, then once touches began, that Actor could not reattach itself to that Zone unless it had moved at least 100 pixels away.
The flaw—obvious in retrospect—was the complex hoops required to remove the Actor’s reference from the Zone after the Actor started moving. At one point, I ended up with the Zone holding on to a reference to the Actor and the Actor holding on to a reference to the last Zone so I could do ugly little things like this:
actor.currentZone?.currentActor = nil
Nope. Nuh-uh. No, thank you.
As always, stepping away from it for a day helped and I quickly realised that I was using space to manage the Reattachment Problem, when I should have been using time. All I needed was a simple timer that began on touchesBegan(withEvent:)
and refused to lock anything to any Zone for either half a second or until touchesEnded(withEvent:)
was called, whichever came first.
Simple and easy to understand. A satisfying solution.
The other major thing was tackling that really ugly code for adding ingredients. After trying a dozen different ways, I settled on using a Protocol called Containable
that defined the behaviour for adding and dispensing ingredients. It ended up simplifying that horrible mess into this:
func addIngredientFromNode(node : SKNode) {
// Button nodes should always have a parent Zone
if let zone = node.parent as? Zone {
// Figure out where the ingredient is coming from.
// If it's from a non-interactive object, then it'll be the Linked Container
// Otherwise, it'll come from the current Actor attached to the Zone
let fromNode : Containable?
if let container = zone.linkedContainer {
fromNode = container
} else {
fromNode = zone.currentActor
}
// Attempt to dispense the ingredient
// The callback means that, if the toNode disappears (e.g. a cup is moved the coffee
// finishes pouring), then the ingredient transfer will fail
fromNode?.dispense({ (ingredient: Ingredient?, quantity: Int) -> () in
// Get the target Actor (e.g. a Cup)
let targetActor : Actor?
if let linkedZone = zone.linkedZone {
targetActor = linkedZone.currentActor
} else {
targetActor = zone.currentActor
}
// If there's still an Actor, attempt to add the ingredient
if let hasActor = targetActor as? Containable {
if let hasIngredient = ingredient {
hasActor.addIngredient(hasIngredient, quantity: quantity)
BaristaLog("Added ingredient \(hasIngredient) with quantity \(quantity)", level: 1)
}
}
})
}
}
Not only is it simpler to understand, it takes advantage of callbacks. This means that I can have ingredients take an arbitrary amount of time to transfer. For example, pouring an espresso into a cup now takes half a second per shot. If the cup is moved before the espresso finishes pouring, it counts as a miss.
Day 11
After a little bit more cleanup, I am now at the stage where I can start making it look better. Steam and coffee particle effects were added first to give some visual feedback on how long the player has to wait before they can move things around.
Scoring is also working—you can see that when the Espresso is delivered to the serving tray, the Single Espresso
label disappears, and the score goes up.
In terms of coding, all of the game logic is there, and now it’s just about tweaking various parameters to make it as fun as possible.
The rest of the remaining 31 hours will be spent on design, effects, beta testing, and preparing it for the App Store.