Posts

The Hidden Garageband Sampler (and other features)

Image
Garageband has some interesting features, made more interesting by the fact that some are quietly hidden away in the program. Here are some hidden and/or notable Garageband features: AUSampler & Effects Yep, Garageband 10 has a sampler that can play an entire keyboard range given a single audio file, but it's not nearly as easy to find as the iOS version's less powerful sampler. Here's how to get to it: 1. Create a new instrument and double click its icon to go to Smart Controls. 2. Hit the "(i)" button in the top right hand corner of the Smart Controls window. 3. Click "plug-ins" to expand it 4. Click instruments → AU Instruments → AUSampler → Stereo 5. Click the keyboard icon in the bottom right of the popup window. 6. Click "Sine 440 built in" 7. Click "choose file" (it's hard to see, but it's right under "Key mappings") 8. Choose file 9. Set the pitch of the file (called "root" in

Magic enums

Image
There's a talk (click here to go to it)  from WWDC 2015 which discusses uses of Swift enumerations in its second half. When I first watched it, I was somewhat suspicious that it was overhyping enums as "magical unicorn solutions" to all problems. However, as I've worked on my game, I've found a great deal of use cases for enums. Here are some examples of how I've used enums and what I've learned about them: Raw values limited, computed vars unlimited I made function that checks if two rectangles intersect in any of the four cardinal directions by using subrectangles (see the diagram below).  I use the function to allow the player to jump only when standing on top of the ground. (I actually use a spiffy PhysicsSensor class more often than this function, but more on that later). ... and therefore it is legal for the player to jump. Note: I actually run this check by enumerating over all of the obstacles in the scene, as the player could be standing

Memoization in Swift 2

The WWDC 2014 talk "Advanced Swift" (https://developer.apple.com/videos/wwdc/2014/#404 ) included a sample 'memoization function' which could speed up performance of certain functions by storing function results in a dictionary. Here's my implementation of it: func memoize<Input: Hashable, Output>(function: Input  -> Output ) -> ( Input  -> Output ) {     var lookupTable = [ Input : Output ]()     return {input in         if lookupTable[input] == nil {lookupTable[input] = function(input)}         return lookupTable[input]!     } } This implementation is very similar to the first implementation of memoization presented in the Advanced Swift talk. However, that first implementation had an issue with creating recursive functions: let factorialMemoized = memoize {n in return n < 2 ? 1 : factorialMemoized(n- 1 )*n} //Error: Variable used within its own initial value when using 'Take One' implementation of m

How to add a folder to Launchpad

Image
I'm not sure if I'll actually use this, but I think it's pretty neat. I use Launchpad a lot to open applications because it works well with trackpad gestures. One way to add folders to Launchpad is by creating applications within Automator that open folders. 1. Open Automator and create a new Application 2. Click the Variables tab and the Locations submenu (the one with the Finder icon), and drag the Path variable to the 'Drag actions or files here.' 3. Double-click 'Path' in the Variable menu (beneath the workflow) and set the path to the folder you want to add to Launchpad. 4. Go back to Actions, choose Files and Folders, and drag 'Open Finder Items' to below the 'Get Specified Variable' action. 5. Save the application in the Applications folder in your user folder, with the same name as the folder it opens. 6. At this point, the app shows up, but it has an automator robot as its icon. Since it opens a folder, it ought

Operator precedence in Swift

The SKActions to move all take a duration argument. To ensure that the rate of the move remains the same even if the distance is different, the duration must be computed: SKAction . moveBy (myVector, duration: NSTimeInterval ( sqrt (myVector. dx *myVector. dx + myVector. dy *myVector. dy )/ 1_000 )) That's an awful lot of code to write for such a simple operation! To alleviate this, I extended CGVector to include a 'magnitude' variable: extension CGVector {     static func from(start: CGPoint , to end: CGPoint ) -> CGVector {         return CGVector (dx: end. x -start. x , dy: end. y -start. y )     }     var magnitude: CGFloat {         return sqrt ( dx ^ 2 + dy ^ 2 )     } } The constant-rate move action could then be created much more simply: SKAction . moveBy (myVector, duration:  NSTimeInterval ( myVector.magnitude / 1_000 )) All seemed to be going well, but I soon noticed a bug in the magnitude: CGVector (dx: 0 , dy: 200

Finding bottlenecks with Time Profiler

After watching a WWDC talk on using time profiler, and noticing low framerate in my game, I decided to try using it to find out what I could optimize. To my surprise, I had a bottleneck that the profiler found very quickly. The culprit was this computed variable: var playerSprite: PlayerSprite ? {         return self [ "PlayerSprite" ][ 0 ] as ? PlayerSprite     } It was called twice every frame in the update method: override   func  update(currentTime:  NSTimeInterval ) {                   guard   didInitialize   else  { return }                   camera !. position  =  playerSprite !. position                   for  child  in   self . children  {             (child  as ?  OverworldSpriteNode )?. updateWithDeltaTime ( 1 / 60 )         }                   k  = ( k  +  1 ) %  7_200                   if   playerSprite ?. position . isInRect ( bounds ) ==  false  {             playerSprite?.gameOver() //not counting this one because the