From cb16c16303a8aa7940380b3d1473a3d88899fbe9 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 16:53:37 -0500 Subject: [PATCH 01/15] initial fork --- README.mkd | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/README.mkd b/README.mkd index 5ee3918..9c10ebc 100644 --- a/README.mkd +++ b/README.mkd @@ -1,18 +1,6 @@ -[![BuddyBuild](https://dashboard.buddybuild.com/api/statusImage?appID=55dd277abbda430100397040&branch=master&build=latest)](https://dashboard.buddybuild.com/apps/55dd277abbda430100397040/build/latest) -# FlappySwift -An implementation of Flappy Bird in Swift for iOS 8. - -![FlappySwift](http://i.imgur.com/1NLoToU.gif) - -# Notes - -We're launching a course [Game Programming with Swift](https://fullstackedu.com) - -If you are interested in early access to the course, head to [fullstackedu.com](https://www.fullstackedu.com) and _enter in your email in the signup box at the bottom of the page_ to be notified of updates on the course itself. - -# Authors +# Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) by - Nate Murray - [@eigenjoy](https://twitter.com/eigenjoy) - Ari Lerner - [@auser](https://twitter.com/auser) From ac920d0f03a156bb65f45bcc030314ffa3ffa49b Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 17:45:37 -0500 Subject: [PATCH 02/15] add configurable game variables and enable realtime spritekit action update with withKey --- FlappyBird/GameScene.swift | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/FlappyBird/GameScene.swift b/FlappyBird/GameScene.swift index af93d4d..518043c 100644 --- a/FlappyBird/GameScene.swift +++ b/FlappyBird/GameScene.swift @@ -9,7 +9,10 @@ import SpriteKit class GameScene: SKScene, SKPhysicsContactDelegate{ - let verticalPipeGap = 150.0 + //remotely configurable variables + var verticalPipeGap = 200.0 + var gravity:Double = 4 + var gameSpeed: CGFloat = 100 var bird:SKSpriteNode! var skyColor:SKColor! @@ -32,7 +35,7 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ canRestart = true // setup physics - self.physicsWorld.gravity = CGVector( dx: 0.0, dy: -5.0 ) + self.physicsWorld.gravity = CGVector( dx: 0.0, dy: -gravity ) self.physicsWorld.contactDelegate = self // setup background color @@ -85,18 +88,8 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ pipeTextureDown = SKTexture(imageNamed: "PipeDown") pipeTextureDown.filteringMode = .nearest - // create the pipes movement actions - let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeTextureUp.size().width) - let movePipes = SKAction.moveBy(x: -distanceToMove, y:0.0, duration:TimeInterval(0.01 * distanceToMove)) - let removePipes = SKAction.removeFromParent() - movePipesAndRemove = SKAction.sequence([movePipes, removePipes]) - - // spawn the pipes - let spawn = SKAction.run(spawnPipes) - let delay = SKAction.wait(forDuration: TimeInterval(2.0)) - let spawnThenDelay = SKAction.sequence([spawn, delay]) - let spawnThenDelayForever = SKAction.repeatForever(spawnThenDelay) - self.run(spawnThenDelayForever) + resetPipes() + startNewPipes() // setup our bird let birdTexture1 = SKTexture(imageNamed: "bird-01") @@ -151,7 +144,7 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ let pipeDown = SKSpriteNode(texture: pipeTextureDown) pipeDown.setScale(2.0) - pipeDown.position = CGPoint(x: 0.0, y: y + Double(pipeDown.size.height) + verticalPipeGap) + pipeDown.position = CGPoint(x: 0.0, y: y + Double(pipeDown.size.height) + self.verticalPipeGap) pipeDown.physicsBody = SKPhysicsBody(rectangleOf: pipeDown.size) @@ -178,9 +171,25 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ contactNode.physicsBody?.contactTestBitMask = birdCategory pipePair.addChild(contactNode) - pipePair.run(movePipesAndRemove) + pipePair.run(movePipesAndRemove, withKey: "movePipesAndRemove") pipes.addChild(pipePair) + } + + func resetPipes() { + // create the pipes movement actions + let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeTextureUp.size().width) + let movePipes = SKAction.moveBy(x: -distanceToMove, y:0.0, duration:TimeInterval((1/self.gameSpeed) * distanceToMove)) + let removePipes = SKAction.removeFromParent() + self.movePipesAndRemove = SKAction.sequence([movePipes, removePipes]) + } + + func startNewPipes() { + let spawn = SKAction.run(spawnPipes) + let delay = SKAction.wait(forDuration: TimeInterval(2.0)) + let spawnThenDelay = SKAction.sequence([spawn, delay]) + let spawnThenDelayForever = SKAction.repeatForever(spawnThenDelay) + self.run(spawnThenDelayForever, withKey: "spawnThenDelayForever") } func resetScene (){ From a52039cb33c36da5f9ffefb4303d2b606f3abf9a Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 17:49:34 -0500 Subject: [PATCH 03/15] advance build target to iOS 10 for SDK compatibility --- FlappyBird.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FlappyBird.xcodeproj/project.pbxproj b/FlappyBird.xcodeproj/project.pbxproj index b0120f5..fc98258 100644 --- a/FlappyBird.xcodeproj/project.pbxproj +++ b/FlappyBird.xcodeproj/project.pbxproj @@ -310,7 +310,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -358,7 +358,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; From 9d384a23a62803dcea81264fd1e8145aada4bd31 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 17:56:13 -0500 Subject: [PATCH 04/15] add Optimizely Swift SDK --- FlappyBird.xcodeproj/project.pbxproj | 54 ++++++++++++++++--- .../contents.xcworkspacedata | 2 +- .../xcshareddata/swiftpm/Package.resolved | 16 ++++++ 3 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 FlappyBird.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/FlappyBird.xcodeproj/project.pbxproj b/FlappyBird.xcodeproj/project.pbxproj index fc98258..cadd2f5 100644 --- a/FlappyBird.xcodeproj/project.pbxproj +++ b/FlappyBird.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -15,6 +15,7 @@ 4374520B193D163800654986 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4374520A193D163800654986 /* Images.xcassets */; }; 43745217193D163800654986 /* FlappyBirdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43745216193D163800654986 /* FlappyBirdTests.swift */; }; 437A3DBA193D326A00909BA0 /* bird.atlas in Resources */ = {isa = PBXBuildFile; fileRef = 437A3DB9193D326A00909BA0 /* bird.atlas */; }; + 5CE2274B24C112310060AE20 /* Optimizely in Frameworks */ = {isa = PBXBuildFile; productRef = 5CE2274A24C112310060AE20 /* Optimizely */; }; 6E1623E01E24FC4E00FB2C72 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E1623DF1E24FC4E00FB2C72 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ @@ -49,6 +50,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5CE2274B24C112310060AE20 /* Optimizely in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -138,6 +140,9 @@ dependencies = ( ); name = FlappyBird; + packageProductDependencies = ( + 5CE2274A24C112310060AE20 /* Optimizely */, + ); productName = FlappyBird; productReference = 437451FA193D163700654986 /* FlappyBird.app */; productType = "com.apple.product-type.application"; @@ -191,6 +196,9 @@ Base, ); mainGroup = 437451F1193D163700654986; + packageReferences = ( + 5CE2274924C112310060AE20 /* XCRemoteSwiftPackageReference "swift-sdk" */, + ); productRefGroup = 437451FB193D163700654986 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -361,7 +369,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 10.0; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -372,7 +381,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = FlappyBird/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "io.fullstack.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; @@ -385,7 +397,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = FlappyBird/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "io.fullstack.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; @@ -406,7 +421,11 @@ "$(inherited)", ); INFOPLIST_FILE = FlappyBirdTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.fullstack.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -425,7 +444,11 @@ "$(inherited)", ); INFOPLIST_FILE = FlappyBirdTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.fullstack.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -466,6 +489,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 5CE2274924C112310060AE20 /* XCRemoteSwiftPackageReference "swift-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/optimizely/swift-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.4.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 5CE2274A24C112310060AE20 /* Optimizely */ = { + isa = XCSwiftPackageProductDependency; + package = 5CE2274924C112310060AE20 /* XCRemoteSwiftPackageReference "swift-sdk" */; + productName = Optimizely; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 437451F2193D163700654986 /* Project object */; } diff --git a/FlappyBird.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FlappyBird.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 379da4d..919434a 100644 --- a/FlappyBird.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/FlappyBird.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/FlappyBird.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FlappyBird.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..c7f8c52 --- /dev/null +++ b/FlappyBird.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Optimizely", + "repositoryURL": "https://github.com/optimizely/swift-sdk.git", + "state": { + "branch": null, + "revision": "dbfaa6665365bdcb2e8d023de9f0b7a4b2322e8d", + "version": "3.4.0" + } + } + ] + }, + "version": 1 +} From 0eb374e50dd438b77f9e4d049f2101cf39cef351 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 22:09:35 -0500 Subject: [PATCH 05/15] instantiate the optimizely sdk client and make it available in the gamescene class --- FlappyBird/AppDelegate.swift | 20 ++++++++++++++++---- FlappyBird/GameScene.swift | 2 ++ FlappyBird/GameViewController.swift | 5 +++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/FlappyBird/AppDelegate.swift b/FlappyBird/AppDelegate.swift index b3bdcbd..e0bfd0a 100644 --- a/FlappyBird/AppDelegate.swift +++ b/FlappyBird/AppDelegate.swift @@ -7,18 +7,30 @@ // import UIKit +import Optimizely @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - + var window: UIWindow? + + // Build OptimizelyClient -> REPLACE_WITH_SDK_KEY + let optimizely = OptimizelyClient(sdkKey: "REPLACE_WITH_SDK_KEY", periodicDownloadInterval: 30) func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + + optimizely.start { result in + switch result { + case .failure(let error): + print("Optimizely SDK initiliazation failed: \(error)") + case .success: + print("Optimizely SDK initialized successfully!") + } + } + return true } + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. diff --git a/FlappyBird/GameScene.swift b/FlappyBird/GameScene.swift index 518043c..f6bcbcd 100644 --- a/FlappyBird/GameScene.swift +++ b/FlappyBird/GameScene.swift @@ -9,6 +9,8 @@ import SpriteKit class GameScene: SKScene, SKPhysicsContactDelegate{ + var appDelegate: AppDelegate? + //remotely configurable variables var verticalPipeGap = 200.0 var gravity:Double = 4 diff --git a/FlappyBird/GameViewController.swift b/FlappyBird/GameViewController.swift index 6761d84..85fccae 100644 --- a/FlappyBird/GameViewController.swift +++ b/FlappyBird/GameViewController.swift @@ -30,6 +30,8 @@ extension SKNode { } class GameViewController: UIViewController { + + let delegate = UIApplication.shared.delegate as! AppDelegate override func viewDidLoad() { super.viewDidLoad() @@ -46,6 +48,9 @@ class GameViewController: UIViewController { /* Set the scale mode to scale to fit the window */ scene.scaleMode = .aspectFill + //attach delegate to scene from linked AppDelegate above + scene.appDelegate = delegate + skView.presentScene(scene) } } From dec1cf5951747d72eaf3709269a954f0541aad32 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Thu, 16 Jul 2020 23:40:18 -0500 Subject: [PATCH 06/15] connect remote config sdk methods to game variable updates --- FlappyBird/GameScene.swift | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/FlappyBird/GameScene.swift b/FlappyBird/GameScene.swift index f6bcbcd..5308100 100644 --- a/FlappyBird/GameScene.swift +++ b/FlappyBird/GameScene.swift @@ -195,6 +195,40 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ } func resetScene (){ + + // Remove all existing pipes + pipes.removeAllChildren() + let userId = "user123" + + let enabled = self.appDelegate!.optimizely.isFeatureEnabled(featureKey: "remoteConfig", userId: userId) + + if enabled { + print("remoteConfig feature enabled!!") + + do { + let remoteConfigGameSpeed = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gameSpeed", userId: userId) + let remoteConfigPipeGap = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "pipeGap", userId: userId) + let remoteConfigGravity = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gravity", userId: userId) + + self.gameSpeed = CGFloat(remoteConfigGameSpeed) + self.verticalPipeGap = Double(remoteConfigPipeGap) + self.gravity = Double(remoteConfigGravity) + self.physicsWorld.gravity = CGVector( dx: 0.0, dy: -self.gravity ) + + print("self.gameSpeed: \(self.gameSpeed)") + print("self.verticalPipeGap: \(self.verticalPipeGap)") + print("self.gravity: \(self.gravity)") + + } catch { + print("error getting feature variable from optimizely: \(error)") + } + resetPipes() + startNewPipes() + } else { + print("remoteConfig feature NOT enabled") + } + + // Move bird to original position and reset velocity bird.position = CGPoint(x: self.frame.size.width / 2.5, y: self.frame.midY) bird.physicsBody?.velocity = CGVector( dx: 0, dy: 0 ) @@ -202,8 +236,7 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ bird.speed = 1.0 bird.zRotation = 0.0 - // Remove all existing pipes - pipes.removeAllChildren() + // Reset _canRestart canRestart = false From a9ff5d0034399082658c3194eabfa28ebf2d1d0c Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 00:24:22 -0500 Subject: [PATCH 07/15] filter remote config values by attributes --- FlappyBird/GameScene.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/FlappyBird/GameScene.swift b/FlappyBird/GameScene.swift index 5308100..c8c1f83 100644 --- a/FlappyBird/GameScene.swift +++ b/FlappyBird/GameScene.swift @@ -199,16 +199,19 @@ class GameScene: SKScene, SKPhysicsContactDelegate{ // Remove all existing pipes pipes.removeAllChildren() let userId = "user123" + let attributes: [String: Any] = [ + "gamePhysicsDifficulty": "hard" + ] - let enabled = self.appDelegate!.optimizely.isFeatureEnabled(featureKey: "remoteConfig", userId: userId) + let enabled = self.appDelegate!.optimizely.isFeatureEnabled(featureKey: "remoteConfig", userId: userId, attributes: attributes) if enabled { print("remoteConfig feature enabled!!") do { - let remoteConfigGameSpeed = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gameSpeed", userId: userId) - let remoteConfigPipeGap = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "pipeGap", userId: userId) - let remoteConfigGravity = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gravity", userId: userId) + let remoteConfigGameSpeed = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gameSpeed", userId: userId, attributes: attributes) + let remoteConfigPipeGap = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "pipeGap", userId: userId, attributes: attributes) + let remoteConfigGravity = try self.appDelegate!.optimizely.getFeatureVariableInteger(featureKey: "remoteConfig", variableKey: "gravity", userId: userId, attributes: attributes) self.gameSpeed = CGFloat(remoteConfigGameSpeed) self.verticalPipeGap = Double(remoteConfigPipeGap) From 1c75d1afdf6ffefe6471359966b1703f48167600 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 14:08:03 -0500 Subject: [PATCH 08/15] update readme --- README.mkd | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/README.mkd b/README.mkd index 9c10ebc..67b9c32 100644 --- a/README.mkd +++ b/README.mkd @@ -1,8 +1,34 @@ +#TappyBird -# Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) by +Tutorial App for [Optimizely Remote Config Tutorial for iOS](www.optimizely.com) + +If you’ve ever thought, “if only I could just send an instant update to my deployed iOS app!” you wouldn’t be alone. Who wouldn’t want the ability to quickly squash a bug in their deployed iOS app, or remotely tweak the behavior of their app in response to user feedback? + +To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. + +##Scenario +Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app “Tappy Bird” suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. + +##What You'll Learn +In this tutorial you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, or the variables of your features without needing to wait for an app store review or resubmission process! + +##Getting Started +With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. + +Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), for steps on running the tutorial app. + + + + + + + + + +# With thanks 👋 Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) originally written by - Nate Murray - [@eigenjoy](https://twitter.com/eigenjoy) - Ari Lerner - [@auser](https://twitter.com/auser) -- Based on code by [Matthias Gall](http://digitalbreed.com/2014/how-to-build-a-game-like-flappy-bird-with-xcode-and-sprite-kit) +- and based on code by [Matthias Gall](http://digitalbreed.com/2014/how-to-build-a-game-like-flappy-bird-with-xcode-and-sprite-kit) From d46378b53d1bd2a9119145f205a856318396eb3a Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 14:09:04 -0500 Subject: [PATCH 09/15] update readme markdown type --- README.mkd => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.mkd => README.md (100%) diff --git a/README.mkd b/README.md similarity index 100% rename from README.mkd rename to README.md From 8654c177b7a97ee186c0870c9e889ce77a5f7545 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 14:12:12 -0500 Subject: [PATCH 10/15] space headers --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 67b9c32..bc7b36f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -#TappyBird +# TappyBird Tutorial App for [Optimizely Remote Config Tutorial for iOS](www.optimizely.com) @@ -7,13 +7,13 @@ If you’ve ever thought, “if only I could just send an instant update to my d To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. -##Scenario +## Scenario Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app “Tappy Bird” suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. -##What You'll Learn +## What You'll Learn In this tutorial you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, or the variables of your features without needing to wait for an app store review or resubmission process! -##Getting Started +## Getting Started With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), for steps on running the tutorial app. From e550c617193a0527e0d8fce1687a9452584b5281 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 14:20:21 -0500 Subject: [PATCH 11/15] readme updates --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bc7b36f..ffad603 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# TappyBird +# TappyBird 🦜 -Tutorial App for [Optimizely Remote Config Tutorial for iOS](www.optimizely.com) +Tutorial App for [Optimizely Remote Config Tutorial for iOS how-to guide](https://www.optimizely.com). -If you’ve ever thought, “if only I could just send an instant update to my deployed iOS app!” you wouldn’t be alone. Who wouldn’t want the ability to quickly squash a bug in their deployed iOS app, or remotely tweak the behavior of their app in response to user feedback? +If you’ve ever thought, “if *only* I could just send an instant update to my deployed iOS app!” you wouldn’t be alone. Who wouldn’t want the ability to quickly squash a bug in their deployed iOS app, or remotely tweak the behavior of their app in response to user feedback? -To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. +To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide [Optimizely Remote Config Tutorial for iOS](https://www.optimizely.com), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. ## Scenario -Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app “Tappy Bird” suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. +Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app **Tappy Bird** suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. ## What You'll Learn -In this tutorial you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, or the variables of your features without needing to wait for an app store review or resubmission process! +In [this tutorial](https://www.optimizely.com) you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, without needing to wait for an app store review or resubmission process! ## Getting Started With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. @@ -26,7 +26,7 @@ Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](ww -# With thanks 👋 Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) originally written by +### With thanks 👋 Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) originally written by - Nate Murray - [@eigenjoy](https://twitter.com/eigenjoy) - Ari Lerner - [@auser](https://twitter.com/auser) From bb237845fe3a2402ca7152c3cc8caa0e23dc6d46 Mon Sep 17 00:00:00 2001 From: Kody OConnell Date: Fri, 17 Jul 2020 14:55:24 -0500 Subject: [PATCH 12/15] add image to readme --- FlappyBird/AppDelegate.swift | 2 +- README.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/FlappyBird/AppDelegate.swift b/FlappyBird/AppDelegate.swift index e0bfd0a..a216249 100644 --- a/FlappyBird/AppDelegate.swift +++ b/FlappyBird/AppDelegate.swift @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // Build OptimizelyClient -> REPLACE_WITH_SDK_KEY - let optimizely = OptimizelyClient(sdkKey: "REPLACE_WITH_SDK_KEY", periodicDownloadInterval: 30) + let optimizely = OptimizelyClient(sdkKey: "X7B2oLeGUPJ415zWrW81F3", periodicDownloadInterval: 5) func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { diff --git a/README.md b/README.md index ffad603..5a2770b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # TappyBird 🦜 +![Remotely configuring game variables](https://user-images.githubusercontent.com/5668620/87825554-f60f1d00-c83c-11ea-80b7-be2b2933f840.png) + Tutorial App for [Optimizely Remote Config Tutorial for iOS how-to guide](https://www.optimizely.com). If you’ve ever thought, “if *only* I could just send an instant update to my deployed iOS app!” you wouldn’t be alone. Who wouldn’t want the ability to quickly squash a bug in their deployed iOS app, or remotely tweak the behavior of their app in response to user feedback? @@ -11,7 +13,7 @@ To quickly learn how to get started using Optimizely to power fast, reliable (an Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app **Tappy Bird** suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. ## What You'll Learn -In [this tutorial](https://www.optimizely.com) you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, without needing to wait for an app store review or resubmission process! +In [this tutorial](https://www.optimizely.com) you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, without needing to wait for an app store review or resubmission process 🕒. ## Getting Started With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. From d306e7352126121963f76aee91155a107b7c5819 Mon Sep 17 00:00:00 2001 From: Kody Date: Fri, 17 Jul 2020 19:19:43 -0500 Subject: [PATCH 13/15] update links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a2770b..1bb777f 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ ![Remotely configuring game variables](https://user-images.githubusercontent.com/5668620/87825554-f60f1d00-c83c-11ea-80b7-be2b2933f840.png) -Tutorial App for [Optimizely Remote Config Tutorial for iOS how-to guide](https://www.optimizely.com). +Tutorial App for [Optimizely Remote Config Tutorial for iOS how-to guide](https://www.linkedin.com/pulse/optimizely-remote-config-tutorial-ios-kody-o-connell/). If you’ve ever thought, “if *only* I could just send an instant update to my deployed iOS app!” you wouldn’t be alone. Who wouldn’t want the ability to quickly squash a bug in their deployed iOS app, or remotely tweak the behavior of their app in response to user feedback? -To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide [Optimizely Remote Config Tutorial for iOS](https://www.optimizely.com), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. +To quickly learn how to get started using Optimizely to power fast, reliable (and [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift)!) remote configuration on iOS, follow the detailed how-to guide [Optimizely Remote Config Tutorial for iOS](https://www.linkedin.com/pulse/optimizely-remote-config-tutorial-ios-kody-o-connell/), and use this completed tutorial app or the app at the commit specific zip file (linked in steps in the how-to guide) necessary to complete that step. ## Scenario Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app **Tappy Bird** suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. @@ -18,7 +18,7 @@ In [this tutorial](https://www.optimizely.com) you’ll learn how to remotely ch ## Getting Started With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. -Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](www.optimizely.com), for steps on running the tutorial app. +Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](https://www.linkedin.com/pulse/optimizely-remote-config-tutorial-ios-kody-o-connell/), for steps on running the tutorial app. From 3e19877c9a8fbaf0cbddb9d29d3b786d1a6629f3 Mon Sep 17 00:00:00 2001 From: Kody Date: Mon, 20 Jul 2020 11:59:38 -0500 Subject: [PATCH 14/15] update readme.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1bb777f..54ed0b6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TappyBird 🦜 -![Remotely configuring game variables](https://user-images.githubusercontent.com/5668620/87825554-f60f1d00-c83c-11ea-80b7-be2b2933f840.png) +![Remotely configuring game variables](https://user-images.githubusercontent.com/5668620/87964577-0cf18180-ca80-11ea-941a-9c3bf6339f4e.png) Tutorial App for [Optimizely Remote Config Tutorial for iOS how-to guide](https://www.linkedin.com/pulse/optimizely-remote-config-tutorial-ios-kody-o-connell/). @@ -13,7 +13,7 @@ To quickly learn how to get started using Optimizely to power fast, reliable (an Imagine we are an indie game developer team building iOS games with Apple’s [SpriteKit](https://developer.apple.com/spritekit/) framework. We go by the team name “Game Wizards” 🧙‍♂️🧙‍♀️, because our apps just have that special magic 💫! We’re thrilled because our most recent app **Tappy Bird** suddenly went viral last week. But the cost of our success means that we are already starting to get requests from users on social media and the App Store to change the way the game works. ## What You'll Learn -In [this tutorial](https://www.optimizely.com) you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, without needing to wait for an app store review or resubmission process 🕒. +In [this tutorial](https://www.linkedin.com/pulse/optimizely-remote-config-tutorial-ios-kody-o-connell/) you’ll learn how to remotely change variables in your deployed iOS app, enabling you to quickly change the behavior of your app, without needing to wait for an app store review or resubmission process 🕒. ## Getting Started With Optimizely’s [free](https://www.optimizely.com/rollouts-signup/ios/?utm_campaign=feature-flags-swift) & open source [SDKs](https://docs.developers.optimizely.com/full-stack/docs/sdk-reference-guides) for iOS and Android, you can customize the rate at which your mobile app polls the Optimizely API for new variable configurations (and feature rollouts) and rest assured that your app won’t be delayed waiting on a network call to return the remote configuration values, because they’re stored locally on the SDK client. And with local & deterministic user bucketing, you can confidently deliver different configurations to different users/filters across implementation contexts. @@ -28,7 +28,7 @@ Follow the detailed how-to guide: [Optimizely Remote Config Tutorial for iOS](ht -### With thanks 👋 Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) originally written by +### With thanks 👋 ⑂ Forked from [FlappySwift](https://github.com/fullstackio/FlappySwift) originally written by - Nate Murray - [@eigenjoy](https://twitter.com/eigenjoy) - Ari Lerner - [@auser](https://twitter.com/auser) From 28e918bfe5dbb04a12e0d70426ed425d5ecb3c0b Mon Sep 17 00:00:00 2001 From: Kody Date: Wed, 22 Jul 2020 18:16:55 -0500 Subject: [PATCH 15/15] update polling interval --- FlappyBird/AppDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FlappyBird/AppDelegate.swift b/FlappyBird/AppDelegate.swift index a216249..e0bfd0a 100644 --- a/FlappyBird/AppDelegate.swift +++ b/FlappyBird/AppDelegate.swift @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // Build OptimizelyClient -> REPLACE_WITH_SDK_KEY - let optimizely = OptimizelyClient(sdkKey: "X7B2oLeGUPJ415zWrW81F3", periodicDownloadInterval: 5) + let optimizely = OptimizelyClient(sdkKey: "REPLACE_WITH_SDK_KEY", periodicDownloadInterval: 30) func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {