Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new screenshot #90

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
58 changes: 50 additions & 8 deletions FlappyBird.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 52;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -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 */

Expand Down Expand Up @@ -49,6 +50,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CE2274B24C112310060AE20 /* Optimizely in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -138,6 +140,9 @@
dependencies = (
);
name = FlappyBird;
packageProductDependencies = (
5CE2274A24C112310060AE20 /* Optimizely */,
);
productName = FlappyBird;
productReference = 437451FA193D163700654986 /* FlappyBird.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -191,6 +196,9 @@
Base,
);
mainGroup = 437451F1193D163700654986;
packageReferences = (
5CE2274924C112310060AE20 /* XCRemoteSwiftPackageReference "swift-sdk" */,
);
productRefGroup = 437451FB193D163700654986 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -310,7 +318,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;
Expand Down Expand Up @@ -358,10 +366,11 @@
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";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)";
Expand All @@ -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)";
Expand Down Expand Up @@ -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 */;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 16 additions & 4 deletions FlappyBird/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
83 changes: 65 additions & 18 deletions FlappyBird/GameScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate{
let verticalPipeGap = 150.0
var appDelegate: AppDelegate?

//remotely configurable variables
var verticalPipeGap = 200.0
var gravity:Double = 4
var gameSpeed: CGFloat = 100

var bird:SKSpriteNode!
var skyColor:SKColor!
Expand All @@ -32,7 +37,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
Expand Down Expand Up @@ -85,18 +90,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")
Expand Down Expand Up @@ -151,7 +146,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)
Expand All @@ -178,21 +173,73 @@ 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 (){

// 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, attributes: attributes)

if enabled {
print("remoteConfig feature enabled!!")

do {
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)
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 )
bird.physicsBody?.collisionBitMask = worldCategory | pipeCategory
bird.speed = 1.0
bird.zRotation = 0.0

// Remove all existing pipes
pipes.removeAllChildren()


// Reset _canRestart
canRestart = false
Expand Down
5 changes: 5 additions & 0 deletions FlappyBird/GameViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ extension SKNode {
}

class GameViewController: UIViewController {

let delegate = UIApplication.shared.delegate as! AppDelegate

override func viewDidLoad() {
super.viewDidLoad()
Expand All @@ -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)
}
}
Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

# TappyBird 🦜

![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/).

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.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.

## What You'll Learn
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.

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.









### 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)
- and based on code by [Matthias Gall](http://digitalbreed.com/2014/how-to-build-a-game-like-flappy-bird-with-xcode-and-sprite-kit)

Loading