Thursday, December 03, 2015

Antarctica Weather: extremely difficult

One hundred years ago Ernest Shackleton and his team attempted to cross Antarctica. They didn't make it to the South Pole but their expedition became one of the greatest adventure stories ever written.

Two expeditions are commemorating Shackleton's expedition.Shackleton Solo has been going for 20 days. Henry is battling fierce winds and demoralizing whiteous. Meanwhile Shackleton 2015 is waiting at Union glacier for a freak in the weather so they can fly to their starting point.

A lot of things have changed over the last 100 years, but the unrepentant weather in Antarctica remains just as challenging as ever.

I wish the best for the two expeditions trying to make a trans Antarctic crossing. 

Friday, November 06, 2015

I got lazy

The shuffle mode on the iPhone doesn't do a good job of randomizing. It likes to play the same songs over and over and then some songs never get played. This morning on the way to work the phone started playing an audio recording from the day I was at the South Pole, something the phone hasn't selected to play for nearly two years.

It was interesting to hear what I had to say that day. A few weeks ago I was looking at my journal and noticed that it stopped the day before I got to the South Pole. I had gotten lazy and did the final journaling using audio recordings instead of writing.

I think it is interesting that the story I tell has not changed from what I said in that audio recording. We all know of stories that grow in the retelling. My story however seems to be staying true to the actual events.

Anyway, hearing this has made me want to get the movie made. Now that I have a job I can actually put some money towards getting the movie made and so I can feel good about starting up a Kickstarter to get the movie done.

One of the first things I need to do with a new job, and thus a new computer is to set the desktop picture. So I took this picture from a bike ride a couple of months ago and divided it into thirds so it could span all three monitors.

 




Tuesday, November 03, 2015

I'm Committed

Or maybe the title should be "I should be committed!" 

I just started a new job as a software developer for Xactware. It is about 25 miles round trip from my home. I committed to myself that I would bike every day to work. Yesterday was getting set up. Getting access to the showers etc. So today is the first day of the biking to work commitment.

From the vantage point of Xactware looking across Utah Valley it looks nice. A mix of clouds and blue sky. Looks like the prefect day to bike to work. But that is not what it was like while I was biking.

I decided to use my aero road bike (Giant Propel) today. Bad choice. It was windy all night, and this morning there was a bit of rain mixed into the high winds. Oh well, I'm committed. 

As I started the rain started to pick up, by the time I was headed down the highway towards Saratoga Springs the road was a flow of water and the winds were threatening to push the little bike right out from under me, or worse toss me into the rush hour traffic. 

I try to obey the laws, like stop signs and stop lights. I failed this morning. First in the driving rain the light turned red right before I got there the icy rain pelting the side of my face was bad enough that I slipped through the light. Then when stopped at the next light I tried to time it so I would start across the intersection the moment it turned green. Sitting still in that rain was no fun. However there was a turn signal at that light so my timing was off and I went through the intersection before the light turned green. 

So I guess I gave the bike haters out there more things to complain about. I'm sorry, but man that was bad weather!


Monday, August 31, 2015

Why Do I Like My Miata So Much?

I think I'm slowly figuring things out.

A few months ago I rode my bike from Utah to the Oregon coast to go buy back my old Miata. But my old Miata came with a bonus, a not quite as old Miata to use as parts. So for that last few months I have needed to make a second trip to Oregon to get the parts is parts car. Last week I finally got in my old truck and headed out to get the car.

Not long after getting into the truck I am reminded that driving is a boring activity. I'm not sure what all is involved, a creative mind that likes to be active, and a body that likes to be active, or what but I can't drive for long before I get bored and have troubles staying awake. So a little Red Bull, a little more Red Bull, and even more Red Bull and I am able to endure the 14+ hours it takes to get from my home to Astoria Oregon. First thing I notice when I get out of the truck is how jittery I am.

Then a couple of nice days riding my bike and it is back to the truck. Even the couple of hours of driving down to Newport is way to long to be sitting in a truck. Then comes the true test, driving back home. With the car on a trailer behind the truck I have to drive slower, and with the nap somewhere in the middle of Oregon it ends up taking about 24 hours to get back home.

Shortly after getting my Miata back the convertible top broke, making it hard to put the top up or down. Now with the spare parts car I got to work and swapped doors, fixed seatbelts, and fixed my convertible top.

So today I had to go for a short drive. Putting the top down it starts out as a fun ride, but then I realized why I like don't really like driving and why the Miata is so much better.

I like to be creative, I don't like to be caged in, I like freedom, freedom of expression, freedom of movement, just basically the feeling that I can do what I need to do. But in a car (or truck) your freedom is severely limited. First of all you are boxed into a little cage. Then you must stay between the lines. There are speed limits that if you get caught breaking then you have to sit around while some cop that has been trapped in his own cage takes his time to give you a fine for your attempt to enjoy the ride. But then even without the speed limits there are stop lights, stop signs, and all kinds of rules that you have to conform to. And if that was not limiting enough you are always surrounded by other cars that limit you freedom of motion.

So I think the reason I like the Miata so much is that when I put the top down, to some degree I escape the cage of being in a car. It gives me a sense of freedom. I find myself swerving back and forth in-between the lines of my lane. My little bit of freedom makes me want more. And so I like the Miata.

But mountain biking is even better. I am not in any kind of cage. I feel free to roam and explore. I love mountain biking. But maybe all of this factors into why I hate the rule that mountain bikes are not allowed in the Wilderness areas. Wilderness areas are set apart so that we can escape the confines of our modern world. What I love about mountain biking is also what I love about being in the Wilderness. Too bad I am not allowed to combine the two.

I just love to ride my bike.

Thursday, August 27, 2015

Fat bike Oregon coast day 2

Today I retraced back form Nehalem back to Astoria. Only this time I knew not to do the trail through Ecola. 

I knew high tide would be in the morning and I might end up waiting at Arch point. I took my time riding up the beach taking pictures and getting some video. Still when I got near arch point the tide was too high. So I hung around eating and enjoying the view. Then I decided to make my attempt. Timing in between the surges I worked my bike through the rocks. When a surge would come in I climbed up rocks to keep my feet dry. It worked well until I was about 10 feet from clearing the rocks when a big surge got me. Wet feet for the rest of the day. 

When I got to Hug point the waves had just gotten low enough to make it passable, but the wet rocks made it evident that not long before it would have not been passable. Other than the people not paying any attention getting through was not a problem. 


The return trip was easier and faster since I knew the problem areas. It was a great day that ended with a dense fog coming in off the ocean. 

Wednesday, August 26, 2015

Even wool socks get wet. Oregon coast fat bike


I had an incredible day of biking. I talked to a state park beach patrol guy before I headed out. After I left he figured out who I was. He then tracked me down on the beach. Kind of cool, a guy from New York, working on the Oregon coast and had heard about my South Pole expedition so we took some pictures at the north end of the park which my starting point for riding south. 

The beach riding was incredible. The beach is littered with dead jelly fish, crab legs and shells and sand dollars. The winds come off the ocean from the north west. So traveling south is generally fast and relatively easy. 

First obstacle? A military range. They were going to be firing something so they had check points at the north and south ends of the firing range. I was told I could go through, but no stopping and get through fast so you don't get shot. I guess I'm still alive so it must have worked.

After about 17 miles, at Seaside, there is a river that enters the ocean. The Oregon coast trail map says to get off the beach and explains how to get around the river. I missed the exit. 

When I got to the river there was a nice sand bar with seagulls wandering around. The water between didn't look too deep. Can I get to the island and then to the other side? The beach patrol guy thought it might be possible. I headed out into the river. A nice splash splash rhythm followed. Fun, but now my feet are wet and I probably got salty water into the bottom bracket. Arriving on the island and assessing the situation. Yeah, I probably could wade across, but I would be very wet and I would have to float the bike. Finally my senses kick in and I retrace the route back towards the exit I was suppose to take. But wait, a path goes through the weeds up there. It turned out to be a great fun shortcut. 

Back to the beach for a few miles. Again the map says to leave the beach, but this time it goes on a trail over the point. Cool! I climb the hill to the Ecola? state park and find the trailhead. There is a sign there that has a hiker, a horse rider, and a bike. A faint line goes through the horse and bike. I think two options, bikes are not allowed or it looks like it could be the work of a vandal I pick the second interpretation. The trail is steep, has a lot of root step ups and is nasty for a bike. I meat people that say, all the other bikers give up and turn around. I'm not that smart and keep going. It is a hard climb to work a bike up. A lot of dead fall on the trail makes it even worse. Finally I get to the top. Yes it levels out for a couple of miles, and a mountain bike that is not loaded with gear could ride it, that is assuming the rider isn't hammered from getting up the trail. So after 4 miles of nasty hike a bike I finally get to the hikers camp, and a narrow service road that goes to the trailhead at the south end. I jump on the road. Fast fun downhill in a rainforest. Awesome. Looking back there is a third possibility for the sign. Some biker made the line to warn other bikers that it isn't worth it. 

At the bottom the trail continues on. This trail does not say anything about bikes and it looks decent. I start on it. It may have been rideable but I'm beat up from the last trail and running low on water so I turn around and use the road to get back to the beach. A lot of climbing on that road for a beat up cyclist. 

Some more great beach riding. The map says that you need a low tide to get around the next point. It is about mid tide and rising, but a hiker says that it is doable, and it was.  At one point Oregon cut through some of the rocks to make it possible to travel down the beach. I guess this was before highway 101. It is kind of a cool little passage followed by some caves and se areas where the water was surging into the rocks. If I times it well I could go between waves and work my way through the rocks and sand. Next is arch way point. The map says to leave the beach here. I go through the arch, and down the beach until I get to falcon point area. Here there is no way to continue on the beach and I have to climb up a steep trail to get to the road. Then the road goes very steep up to 101.

The climb up to the top of falcon point was hard and near the top I drank a Coke. It don't even freeze while I was opening it. 

The road down to Nahem? Beach, sorry no internet connection here to get the right spelling, is steep and fast. I passed the of road trails for the Oregon coast route. Again not designed for biking. Going down the road I hit the highest speeds I think I have ever done in a fat bike. This flatish tires don't handle well at those speeds.  

I got to the hiker biker camp just as it was getting dark. It was a great day. However it is a lot different than I hoped. I have come to the conclusion that you need to think of this as a beach and road ride, not the beach and mountain biking trip I was thinking of. So I think I should get back to the truck so I can get the trailer sold as soon as possible. The experiment is done time to be a little responsible. 

Monday, August 24, 2015

Heaven on Earth-- Oregon coast fat bike day 0


I woke up early this morning so that I could drive from Eagle Mountain Utah to Astoria Oregon where I will begin the my ride. There are so many fires in the western states that it was very smoky all the way until Portland. The final fire was in the wilamina area just outside of Portland. Finally after over 800 miles and 13 hours I was out of the smoke. 

I don't know what it is about the Oregon coast range mountains. When I reached the Coast Range a smile so large, as Carissa would say, it was so large it would make me have to close my eyes. I think I Oregon just runs in my blood. I was born in Corvallis on the east side of the mountains, but it is more than that. George Luther Boone and Alphonzo (sp?) Boone, my great great something grand parent and father, were some of the original Trailblazers in Oregon and settled in Toledo. George's place is still known as Boone island to this day. They say you can't shake a tree without Boone relatives falling out. I know I have a lot of Boone relatives in this area. 

I also have some Czech relatives in the area. In particular, Oswego Oregon. I don't know many of my relatives that live here in Oregon. However when my grandma Helen and grandpa Daniel Boone's ashes were sent out to sea I met my Czech relatives. They look just like my Grandma. 

As I drove through the "rain forest" tears flowed as I remembered sending my grandparents off to their final resting place. But not just for them, but for my mother too. I remember her telling me how much she loved the Oregon rain forest. And when she needed peace she left Utah and moved to the Oregon coast. She was so anxious to move out here that she bought a house that seemed to be falling off the hill and into the ocean. The floor sloped more than any camping spot I have ever placed a tent. I am sure that some day that house will fall off the hill if it isn't torn down first. But my mom loved the house. She loved the forest and the beaches. She would often talk of Cannon Beach, and she loved to go down to Agate Beach to collect agates. I could rarely find an agate but she was a master of finding the agates and other rocks that would be great for polishing. 

It is hard to imagine that heaven could be as lovely as the Oregon coast. But I am imagine that my mom's heaven is a lot like Oregon, and maybe her home in heaven seems as if it is about to fall into the ocean.   

Sunday, August 23, 2015

The gear for the coast

I'll take my normal biking gear including some long water proof pants and jacket. For camping I have a 15F sleeping bag and an Easton tent suffers into a compression bag. The tent was given to me by a good friend I first met at the bike store. I have a Nemo pillow, and Exped mattress that I used in Antarctica, also my MSR stove and a Coleman pot, the stove is inside the pot. An emergency poncho for rain, some Backpacker's Pantry food, some oatmeal and a Cabela's multi tool. The pliers worked great for handling the hot pot and for wiring gears to spokes in the middle of Antarctica. 
I have the fuel bottle in the bottle cage on my bike, and the rest of the gear will go in a bag on top of the rear rack and on a bag attached to the handlebars. Then my water and clothes and camera will go in my camelbak. I think I'll use my winter Shimano biking shoes. They should help with the wet conditions. 

Next Adventure: Oregon Coast Trail

I was planning on being headed to Oregon by now. Originally Jake and I were planning on leaving right after church and driving to Astoria. The problem is it is a 13+ hour drive, and so I would arrive sometime after 3 in the morning. With two drivers this would be possible, but Jake ended up not being able to go this week, and by myself I can't do that drive. So I will get rest tonight and start first thing in the morning.

I plan on driving to Astoria Oregon and biking along the Oregon Coast Trail until I run out of time. The "trail" consists of riding on the beach as much as possible. Should be fun with my fat bike. The trail also includes some nice trails over areas where there isn't a sandy beach, and to get around rivers I have two options, find a boat that will ferry me to the other side, or jump on the road and go to the nearest bridge.

Mostly this is an experimental trip. Assuming it works out decently then we will have to return some day and do the full 400 mile trip from the north end of Oregon to the south.

Sunday, August 16, 2015

New church building

The Bishop must not think I am getting enough exercise on Sundays. 

We use to go to the building that is a mile from my home. It just seemed that being so close it was not right to drive to church so I would walk. 

Then a few years ago they moved us across the highway to a church building that is about two miles from home. The neighborhood has a designated horse trail system. I say designated because mostly the trails don't really exist. Such was the case for the trail between my house and the church.

The first few weeks I would scamper up and over hills, through brush, and around the empty wash. It was quite an adventure each week, and I would get to church looking like I had been on safari. Eventually I figured out the best route through the gully and built the trail. It is now a pretty nice trail, yet often I still get to church all dusty and dirty. The horse riders enjoy the trail I built and it gets pretty dusty. 

So today is our first day at a new church building. Actually the building isn't new, President Hinkley dedicated it years ago. However it is the new location for our ward. My route this morning ended up being 5.3 miles. 
I thought about following the old railroad bed that goes through the valley. While it was still visible, and with the fat bike I could go through the fields, it wasn't really a nice route. Looking to the south east I could see a nice dirt road climbing up a hill. 

OK, a long sleeve shirt and tie are not the best for mountain biking, and wanting not to be too drenched in sweat I had to go easy, but it was a fun little climb with a great view of the valley. 
After dropping down the other side of the hills I hit the old Pony Express trail and pretty much followed it the rest of the way to the church. 
Ironically, in spite of google's efforts to get more sites to be mobile friendly, Blogger does not work well for creating post from a mobile device.  So I'll have to fix up the positions of these images when I get home. 
I just love to ride my bike. 



Tuesday, July 28, 2015

Combining Balls Animation -- Epic Color Crash Step 4

OK it has been a couple of days since the last step was posted. I am splitting my time between a couple of web service applications, a new game, this tutorial, selling stuff on eBay, and sometime I should work on getting a job. Anyway it is time for the next step.

Preview: Here is what the game will be like at the end of this step:
video


Now that we have the images for the animations created we can start the game logic. The first thing I am going to add is the ability to swipe between two primary colored balls to produce a secondary colored ball.

I don't really need to do a swipe detection, all I really need to do is on a touchesBegan check and see what ball, if any, the user touched. Then on the touchesMoved check and see if the touch has moved to a different ball. Then if the balls are allowed to combine we can combine the balls.

The touchesBegan function in GameScene.swift currently looks like this:
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        /* Called when a touch begins */
        
        for touch in (touches as! Set<UITouch>) {
        }

    }

First we want to get the location of the touch in the local coordinates. Inside the for loop add:
let location = touch.locationInNode(self)

Now we want to see if there are any balls at this location. self.nodesAtPoint(location) will give us a list of all of the scenes child nodes that are at the location. These nodes may or may not be a colored ball. So I will create an optional called startBall. Add startBall right after the declaration for newBallDelay in the Game scene class.
class GameScene: SKScene {
    var lastBallDropped: CFTimeInterval = 0
    var newBallDelay: CFTimeInterval = 1.5
    var startBall: ColoredBall?

We will then get the list of nodes at the touch location, assuming there is at least one node we will try and set the startBall to the touched node as a ColoredBall. If the node is not an object with the class of ColoredBall then startBall will be set to no value. However if it is a ColoredBall object then the optional will be set. When this happens we don't need to look at anymore nodes or anymore touches and we can just return. So after let location = touch.locationInNode(selfadd:

            let balls = self.nodesAtPoint(location)
            if balls.count >= 1 {
                for aBall in balls {
                    startBall = aBall as? ColoredBall;
                    if startBall != nil {
                        return
                    }
                }
            }

Now we want to get touchesMoved events and see if the user swipes into a different ball. We add the touchesMoved function and like the touchesBegan convert the touch location to our local coordinates, and check to see if there is a ColoredBall at that location. If there is a ColoredBall at that location than we make sure we have a starting ball, and the starting ball is not the same as the ball being touched. If that is the case than we can try and combine the balls.
 
    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
        for touch in (touches as! Set<UITouch>) {
            let location = touch.locationInNode(self)
            let aBall:ColoredBall? = self.nodeAtPoint(location) as? ColoredBall
            if startBall != nil && aBall != nil && aBall != startBall {
                primaryContact(startBall!, spriteB: aBall!)
                startBall = nil
                return
            }
            
        }
    }

The way this is written the first touch has to be in a ball, however we could change it so that if the startBall is not set then we would set the startBall to the current ball being touched which would allow a swipes that pass through two balls but didn't start in a ball. I could change this in my current game, but the method above works well.

I have added a call to a new function primaryContact let's write that function. The function will take two colored balls and check to see if they are colors that can be combined, if so combine to make a new colored ball. This is a big nested set of if else code. Given that in sprite you can have switch statements with strings this could be rewritten with switch statements. However eventually I will convert this code to Objective-C and to C++ which would require it to be if else statements. Since either works just fine I will stick to the classic if else method.

We create a the function:
    func primaryContact(spriteA: ColoredBall, spriteB: ColoredBall) {

If the first ball is red then check and see if the second ball is yellow or blue, if so create an orange or purple ball.
        if spriteA.name == "red" {
            if spriteB.name == "yellow" {
                // make an orange ball
                ebcc_combineSprites(spriteA, spriteB: spriteB, color: "orange")
                orangeBalls.insert(spriteB)
            } else if spriteB.name == "blue" {
                // make a purple ball
                ebcc_combineSprites(spriteA, spriteB: spriteB, color: "purple")
                purpleBalls.insert(spriteB)
                
            }
OK, same thing if the first ball is yellow but test for red and blue to get orange and green. 
        } else if spriteA.name == "yellow" {
            if spriteB.name == "red" {
                // make an orange ball
                combineSprites(spriteA, spriteB:spriteB, color: "orange")
            } else if spriteB.name == "blue" {
                // make a green ball
                combineSprites(spriteA, spriteB: spriteB, color: "green")
            }

And finally if the first is blue then red to purple and yellow to green.
        } else if spriteA.name == "blue" {
            if spriteB.name == "red" {
                // make a purple ball
                combineSprites(spriteA, spriteB: spriteB, color: "purple")
                purpleBalls.insert(spriteB)
            } else if spriteB.name == "yellow" {
                // make a green ball
                combineSprites(spriteA, spriteB: spriteB, color: "green")
            }
        }
        
    }
But I still have not written the code to combine the sprites. Let's do that now. The combineSprites function will take two colored balls and string designating the new color. 
    func combineSprites(spriteA: ColoredBall, spriteB: ColoredBall, color: String) {
First I will move the second ball to be halfway between the two balls.
        spriteB.position.x = (spriteA.position.x + spriteB.position.x) / 2
        spriteB.position.y = (spriteA.position.y + spriteB.position.y) / 2
Then we will run a little animation that will turn the second ball into one with the new color.
        switch color {
        case "orange":
            spriteB.runAction(orangeAction!)
        case "green":
            spriteB.runAction(greenAction!)
        case "purple":
            spriteB.runAction(purpleAction!)
        default:
            spriteB.texture = SKTexture(imageNamed: color)
        }

Here I did use the switch statement instead of a bunch of if else statements. When we create the Objective-C and C++ code this will have to change. The switch statement in Swift requires a default case. This should never happen because we always send orange, green, or purple. However if for some strange reason we added some other color then we will just change the texture to an image with that color as the name. Again this never happens.

Now I want to remove the first ball from the scene. And since it will no longer have anything referencing it, it will be freed.
        spriteA.removeFromParent()

And finally I will change the name of the second sprite to the new color. This is critical so that we can test if it is touching other secondary colored balls and also so our touchesBegan and touchesMoved functions don't think it is a primary colored ball.
        spriteB.name = color
    }

OK they are combined, but I added the use of some actions that are not defined yet. Finally we get to use the animation images we created in the last step.

First I'll add optionals for each color action, and then a sound action to play when the balls are combined. I found a public domain sound that I downloaded. I'll let you go find your own. On the sound action I use waitForCompletion to tell it to start the drip sound and then continue with other actions.
    var orangeAction: SKAction?
    var greenAction: SKAction?
    var purpleAction: SKAction?
    var dripSound = SKAction.playSoundFileNamed("drip.wav", waitForCompletion: false)

We need to actually assemble the actions. I'll do that in the scene's didMoveToView function right after the self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
First I'll check to see if the action already was created in a previous didMoveToView call
        if orangeAction == nil {

Then I'll get an atlas with the animation images. The problem is we are not guaranteed what order they will be in. So I sort them and then I can create an animation with 0.075 seconds between images for just a little less than half a second total. Then I can create an sequence that plays the sound and then runs the image animation.
            let orangeAtlas = SKTextureAtlas(named: "orange")
            let orangeTextures = sorted(orangeAtlas.textureNames as! [String]).map { orangeAtlas.textureNamed($0) }
            let orangeAnimation = SKAction.animateWithTextures(orangeTextures, timePerFrame: 0.075)
            orangeAction = SKAction.sequence([dripSound,orangeAnimation])
        }
Repeat for green and purple
        if greenAction == nil {
            let greenAtlas = SKTextureAtlas(named: "green")
            let greenTextures = sorted(greenAtlas.textureNames as! [String]).map { greenAtlas.textureNamed($0) }
            let greenAnimation = SKAction.animateWithTextures(greenTextures, timePerFrame: 0.075)
            greenAction = SKAction.sequence([dripSound,greenAnimation])
        }
        if purpleAction == nil {
            let purpleAtlas = SKTextureAtlas(named: "purple")
            let purpleTextures = sorted(purpleAtlas.textureNames as! [String]).map { purpleAtlas.textureNamed($0) }
            let purpleAnimation = SKAction.animateWithTextures(purpleTextures, timePerFrame: 0.075)
            purpleAction = SKAction.sequence([dripSound,purpleAnimation])
        }

Now we need to add the images and sound to our project. Previously I created a group called images, but I am going to be putting sounds in here too, so I am going to rename it assets, a much better name.

Then File->Add Files to "EpicColorCrash"... and select the atlas directories we created in the last step.
Make sure Copy items if needed is selected and Create groups is selected. And click Add. Then download or create a sound for the drip.wav and add it to the project.


Build and run. Now you should be able to swipe between balls, get a cool little animation and a sound.
Here is the GameScene.swift file at the end of this step:
//
//  GameScene.swift
//  Epic Color Crash
//
//  Created by Daniel Burton on 7/25/15.
//  Copyright (c) 2015 Daniel Burton. All rights reserved.
//

import SpriteKit

class ColoredBall: SKSpriteNode {
}

class GameScene: SKScene {
    var lastBallDropped: CFTimeInterval = 0
    var newBallDelay: CFTimeInterval = 1.5
    var startBall: ColoredBall?
    var orangeAction: SKAction?
    var greenAction: SKAction?
    var purpleAction: SKAction?
    var dripSound = SKAction.playSoundFileNamed("drip.wav", waitForCompletion: false)

    func addColorBall(location: CGPoint, withColor color:String) {
        let sprite = ColoredBall(imageNamed: color)
        
        sprite.position = location
        sprite.name = color
        let body = SKPhysicsBody(circleOfRadius: 25)
        sprite.physicsBody = body
        body.allowsRotation = false
        body.friction = 0.0
        self.addChild(sprite)
    }
    
    func combineSprites(spriteA: ColoredBall, spriteB: ColoredBall, color: String) {
        spriteB.position.x = (spriteA.position.x + spriteB.position.x) / 2
        spriteB.position.y = (spriteA.position.y + spriteB.position.y) / 2
        switch color {
        case "orange":
            spriteB.runAction(orangeAction!)
        case "green":
            spriteB.runAction(greenAction!)
        case "purple":
            spriteB.runAction(purpleAction!)
        default:
            spriteB.texture = SKTexture(imageNamed: color)
        }
        spriteA.removeFromParent()
        spriteB.name = color
    }

    func primaryContact(spriteA: ColoredBall, spriteB: ColoredBall) {
        if spriteA.name == "red" {
            if spriteB.name == "yellow" {
                // make an orange ball
                combineSprites(spriteA, spriteB: spriteB, color: "orange")
            } else if spriteB.name == "blue" {
                // make a purple ball
                combineSprites(spriteA, spriteB: spriteB, color: "purple")
                
            }
        } else if spriteA.name == "yellow" {
            if spriteB.name == "red" {
                // make an orange ball
                combineSprites(spriteA, spriteB:spriteB, color: "orange")
            } else if spriteB.name == "blue" {
                // make a green ball
                combineSprites(spriteA, spriteB: spriteB, color: "green")
            }
        } else if spriteA.name == "blue" {
            if spriteB.name == "red" {
                // make a purple ball
                combineSprites(spriteA, spriteB: spriteB, color: "purple")
            } else if spriteB.name == "yellow" {
                // make a green ball
                combineSprites(spriteA, spriteB: spriteB, color: "green")
            }
        }
        
    }
    
    override func didMoveToView(view: SKView) {
        
        /* Setup your scene here */
        self.scaleMode = .AspectFit

        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        if orangeAction == nil {
            let orangeAtlas = SKTextureAtlas(named: "orange")
            let orangeTextures = sorted(orangeAtlas.textureNames as! [String]).map { orangeAtlas.textureNamed($0) }
            let orangeAnimation = SKAction.animateWithTextures(orangeTextures, timePerFrame: 0.075)
            orangeAction = SKAction.sequence([dripSound,orangeAnimation])
        }
        if greenAction == nil {
            let greenAtlas = SKTextureAtlas(named: "green")
            let greenTextures = sorted(greenAtlas.textureNames as! [String]).map { greenAtlas.textureNamed($0) }
            let greenAnimation = SKAction.animateWithTextures(greenTextures, timePerFrame: 0.075)
            greenAction = SKAction.sequence([dripSound,greenAnimation])
        }
        if purpleAction == nil {
            let purpleAtlas = SKTextureAtlas(named: "purple")
            let purpleTextures = sorted(purpleAtlas.textureNames as! [String]).map { purpleAtlas.textureNamed($0) }
            let purpleAnimation = SKAction.animateWithTextures(purpleTextures, timePerFrame: 0.075)
            purpleAction = SKAction.sequence([dripSound,purpleAnimation])
        }

    }
    
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        /* Called when a touch begins */
        
        for touch in (touches as! Set<UITouch>) {
            let location = touch.locationInNode(self)
            let balls = self.nodesAtPoint(location)
            if balls.count >= 1 {
                for aBall in balls {
                    startBall = aBall as? ColoredBall;
                    if startBall != nil {
                        return
                    }
                }
            }
        }
    }
    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
        for touch in (touches as! Set<UITouch>) {
            let location = touch.locationInNode(self)
            let aBall:ColoredBall? = self.nodeAtPoint(location) as? ColoredBall
            if startBall != nil && aBall != nil && aBall != startBall {
                primaryContact(startBall!, spriteB: aBall!)
                startBall = nil
                return
            }
            
        }
    }

    override func update(currentTime: CFTimeInterval) {

        // if the time has come to drop a new ball
        if currentTime > (lastBallDropped + newBallDelay) {
                lastBallDropped = currentTime
                let colors = ["red", "yellow", "blue"]
                var xpos = Int(arc4random_uniform(UInt32(self.size.width-100) ))+50
                let ypos = self.size.height - 120
                let location = CGPoint(x: xpos, y: Int(ypos))
                var colorIndex = arc4random_uniform(3)
                addColorBall(location, withColor: colors[Int(colorIndex)])
        }

    }
    

}


My Bicycle Store