SKLabelNode Won't Update Text From Function - swift

I have this game project and it has a coin system. I also have an option for users to watch a video ad to get 50 coins added to their total. Since the shop page is a SKScene, I run the ad through the view controller and when it is done presenting, the viewcontroller runs a function inside the scene that should update the amount of coins and the label that displays them.
Here is the code for my view controller:
class GameViewController: UIViewController , GADRewardBasedVideoAdDelegate {
var rewardBasedVideo: GADRewardBasedVideoAd!
var rewardvideoisinprogress = false
var interstitial: GADInterstitial!
var adcounter = 0
override func viewDidLoad() {
super.viewDidLoad()
adcounter = UserDefaults.standard.integer(forKey: "AdCounter")
print(adcounter)
createandloadvideoad()
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3343126174384559/7308554354")
let request = GADRequest()
interstitial.load(request)
ThemeShop().updatecoins()
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.presentvideoad), name: NSNotification.Name("video"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.inter), name: NSNotification.Name("inter_"), object: nil)
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "MainMenu") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
}
}
#objc func inter(){
adcounter = adcounter + 1
print(adcounter)
if adcounter == 2{
adcounter = 0
if interstitial.isReady {
interstitial.present(fromRootViewController: self)
interstitial = createad()
} else {
print("Ad wasn't ready")
}
}
UserDefaults.standard.set(adcounter, forKey: "AdCounter")
}
func createad() -> GADInterstitial {
let inter = GADInterstitial(adUnitID: "ca-app-pub-3343126174384559/7308554354`")
inter.load(GADRequest())
return inter
}
func createandloadvideoad(){
rewardBasedVideo = GADRewardBasedVideoAd.sharedInstance()
rewardBasedVideo?.delegate = self
if !rewardvideoisinprogress && rewardBasedVideo?.isReady == false{
//ca-app-pub-3343126174384559/3425197396
rewardBasedVideo?.load(GADRequest(), withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
rewardvideoisinprogress = true
}
}
#objc func presentvideoad(){
if rewardBasedVideo?.isReady == true{
rewardBasedVideo?.present(fromRootViewController: self)
}else{
print("Was NOt Reardyadjfsjfsalfkj")
}
createandloadvideoad()
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didFailToLoadWithError error: Error) {
print("Reward based video ad failed to load: \(error.localizedDescription)")
rewardvideoisinprogress = false
}
func rewardBasedVideoAdDidReceive(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
print("Reward based video ad is received.")
}
func rewardBasedVideoAdDidOpen(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
print("Opened reward based video ad.")
}
func rewardBasedVideoAdDidStartPlaying(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
print("Reward based video ad started playing.")
}
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
rewardvideoisinprogress = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500) , execute: {
print("Brikdsajfaslkd")
ThemeShop().updatecoins()
})
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didRewardUserWith reward: GADAdReward) {
var coins = UserDefaults.standard.integer(forKey: "Coins")
coins = coins + 50
UserDefaults.standard.set(coins, forKey: "Coins")
}
}
This is the function inside the SKScene:
func updatecoins(){
print("Updating")
coins = UserDefaults.standard.integer(forKey: "Coins")
print("Coins: \(coins)")
self.coinlabel.text = String(self.coins)
print(self.coinlabel.text)
}
I know that the coins are being added to the balance behind the scenes because if I exit the scene and reenter, the coins show up like they should.

you're trying to call a function on a class variable of ThemeShop you need to be calling the func on an instance variable of the class.
you don't show your ViewController code so you may have to adapt this accordingly
have a scene variable at the top of your viewController
private var themeShop: ThemeShop!
then in your viewDidLoad when you load the scene put it inside of the variable
//this is if you are loading your scene from an sks file.
//your code may be different if it is just loaded from code with no sks file
if let scene = SKScene(fileNamed: "ThemeShop") {
self.themeShop = scene
then in your viewController when you need to access the scene
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
rewardvideoisinprogress = false
sleep(1)
themeShop.updatecoins()
}

I think you label is not updating because you are not on the main queue. Also I made some changes to your code. You shouldn't use sleep() better use asyncAfter:
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
isRewardVideoInProgress = false
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
ThemeShop().updatecoins()
}
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didRewardUserWith reward: GADAdReward) {
var coins = UserDefaults.standard.integer(forKey: "Coins")
coins = coins + 50
UserDefaults.standard.set(coins, forKey: "Coins")
}
func updatecoins(){
print("Updating")
coins = UserDefaults.standard.integer(forKey: "Coins")
print("Coins: \(coins)")
DispatchQueue.main.async {
self.coinlabel.text = "\(self.coins)"
print(self.coinlabel.text)
}
}

Related

Connect UIViewRepresentable to SwiftUI

I have a SwiftUI based app with a simple button that when pressed is supposed to open a Camera Class from AVFoundation that utilizes UIKit as well. Under the sheet I am not sure what exactly to place there. I tried CameraSession() and a few other ideas but I am sort of lost on bridging this SwiftUI button to open camera app. Thank you!
//Content View
import SwiftUI
struct ContentView: View {
//#State private var image: Image?
#State private var showingCameraSession = false
//#Binding var isShown: Bool
var body: some View {
VStack{
ControlButton(systemIconName: "slider.horizontal.3"){
//Button("Seelect Image") {
showingCameraSession = true
} .sheet(isPresented: $showingCameraSession){
//What to place here?
}
}
}
}
//CameraSession
import AVFoundation
//import RealityKit
import UIKit
import SwiftUI
struct CameraSession : UIViewControllerRepresentable {
//#Binding var isShown: Bool
typealias UIViewControllerType = CaptureSession
func makeUIViewController(context: Context) -> CaptureSession{
return CaptureSession()
}
func updateUIViewController(_ uiViewController: CaptureSession, context: Context) {
// if(self.isShown){
//CameraSession.didTapTakePhoto()
// shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
}
}
class CaptureSession: UIViewController {
//#Binding var isShown: Bool
//Reference: https://www.youtube.com/watch?v=ZYPNXLABf3c
//CaptureSession
var session: AVCaptureSession?
//PhotoOutput --> to the Cloud
let output = AVCapturePhotoOutput()
// Video Preview
let previewLayer = AVCaptureVideoPreviewLayer()
//Shutter Button
private let shutterButton: UIButton = {
let button = UIButton(frame: CGRect(x:0, y:0, width: 100, height: 100))
button.layer.cornerRadius = 50
button.layer.borderWidth = 10
button.layer.borderColor = UIColor.white.cgColor
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
//previewLayer.backgroundColor = UIColor.systemRed.cgColor
view.layer.addSublayer(previewLayer)
view.addSubview(shutterButton)
checkCameraPermissions()
shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
}
override func viewDidLayoutSubviews(){
super.viewDidLayoutSubviews()
previewLayer.frame = view.bounds
shutterButton.center = CGPoint(x: view.frame.size.width/2, y: view.frame.size.height - 100)
}
private func checkCameraPermissions() {
switch AVCaptureDevice.authorizationStatus(for: .video){
case .notDetermined:
//Request Permission
AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
guard granted else {
return
}
DispatchQueue.main.async{
self?.setUpCamera()
}
}
case .restricted:
break
case .denied:
break
case .authorized:
setUpCamera()
#unknown default:
break
}
}
//with Photogrammetry, you also have to create a session similar https://developer.apple.com/documentation/realitykit/creating_3d_objects_from_photographs/
// example app: https://developer.apple.com/documentation/realitykit/taking_pictures_for_3d_object_capture
private func setUpCamera(){
let session = AVCaptureSession()
if let device = AVCaptureDevice.default(for: .video){
do{
let input = try AVCaptureDeviceInput(device: device)
if session.canAddInput(input){
session.addInput(input) //some Devices contract each other.
}
if session.canAddOutput(output) {
session.addOutput(output)
}
previewLayer.videoGravity = .resizeAspectFill //content does not get distored or filled
previewLayer.session = session
session.startRunning()
self.session = session
}
catch{
print(error)
}
}
}
//originally private
#objc private func didTapTakePhoto() {
output.capturePhoto(with: AVCapturePhotoSettings(),
delegate: self)
// let vc = UIHostingController(rootView: ContentView())
// present(vc, animated: true)
}
}
//AVCaptureOutput is AVFoundations version of photo output
extension CaptureSession: AVCapturePhotoCaptureDelegate {
func photoOutput( output: AVCaptureOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error:
Error?){
guard let data = photo.fileDataRepresentation() else { //where to store file information
return
}
let image = UIImage(data: data)
session?.stopRunning()
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFill
imageView.frame = view.bounds
view.addSubview(imageView)
}
}
So to get around this first make your app has permission to access the users camera(go to Info.plist or info tab beside the build settings at the top and add Privacy camera usage and add "We need your camera to perform this action")
After that a simple call in the sheet's modifier should do the trick
struct ContentView: View {
//#State private var image: Image?
#State private var showingCameraSession = false
//#Binding var isShown: Bool
var body: some View {
VStack{
// ControlButton(systemIconName: "slider.horizontal.3"){
Button("Seelect Image") {
showingCameraSession = true
} .sheet(isPresented: $showingCameraSession){
//What to place here?
CameraSession()
}
}
}
}

Rewarded Video ad show reward content on my label

I just working on an app with admob rewarded video ad.
I wanna know when the user click button to reward them.
I made this but my question is when I click second time on play ad button my current (Currency on label) not plusing with new one it just get new 100 not (current + 100).
I just wanna to make my (Current) currency (+100).
can you guys help meee. please....
struct Keys {
static var currency = "Currency"
static var currentCurr = "CurrentCurrency"
}
class ViewController: UIViewController, GADRewardBasedVideoAdDelegate {
var currency = 0
var userDefault = UserDefaults.standard
#IBOutlet weak var currencyShower: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
GADRewardBasedVideoAd.sharedInstance().load(GADRequest(), withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
GADRewardBasedVideoAd.sharedInstance().delegate = self
if userDefault.string(forKey: Keys.currency) != nil {
currencyShower.text = userDefault.string(forKey: Keys.currency)
} else {
return
}
}
//
#IBOutlet weak var playAdOut: UIButton!
#IBAction func playAd(_ sender: UIButton) {
if GADRewardBasedVideoAd.sharedInstance().isReady == true {
GADRewardBasedVideoAd.sharedInstance().present(fromRootViewController: self)
} else {
print("Video Did not Load...")
}
}
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
print("Video is Ready")
GADRewardBasedVideoAd.sharedInstance().load(GADRequest(),
withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didFailToLoadWithError error: Error) {
print("Error When Loading")
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didRewardUserWith reward: GADAdReward) {
currency += 100
currencyShower.text = String(currency)
}
}
You could save currency value to UserDefaults and then retrieve or update it when needed example in following link: example
PS! If you don't want to save strings to userDefaults you can also save numbers.

How to run function multiple times in xcode?

I want to show my interstitial ad after the player have died. Meaning the interstitial ad will load in my game over scene. But i can't just write the function name in the viewdidload section. So is there a way for me to run my interstitialAd function when the player gets to the gameOverScene?
If there was an update function, i would just make a boolean value like so:
var interstitialAdShow = false
and then write this in my didmovetoview:
interstitalAdShow = true
and then in my update function:
If interstitailAdShow == true{
interstitial.present(fromRootViewController: self)
}
But now when there is no update function in the GameViewController, and i can't do it inside of my gameOverScene.swift i can't use this solution, is there another way for me to trigger my interstitial ad function when the gameOverScene comes up.
BTW here is my codes
import UIKit
import SpriteKit
import StoreKit
import GameplayKit
import GoogleMobileAds
var reklameNummer = 0
class GameViewController: UIViewController, GADBannerViewDelegate, GADRewardBasedVideoAdDelegate {
var rewardBaseAd: GADRewardBasedVideoAd!
var interstitial: GADInterstitial!
#IBOutlet weak var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
let request2 = GADRequest()
request2.testDevices = [kGADSimulatorID]
bannerView.delegate = self
bannerView.adUnitID = "ca-app-pub-1110799225910030/5762940412"
bannerView.rootViewController = self
//bannerView.load(request2)
interstitial = GADInterstitial(adUnitID: "ca-app-pub-1110799225910030/7460037600")
let request = GADRequest()
interstitial.load(request)
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "MenuScene") {
runTheInterStitialAd()
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
rewardBaseAd = GADRewardBasedVideoAd.sharedInstance()
rewardBaseAd.delegate = self
//rewardBaseAd.load(GADRequest(), withAdUnitID: "ca-app-pub-1110799225910030/4904503594")
}
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
//MARK: Video ad
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didRewardUserWith reward: GADAdReward) {
}
func rewardBasedVideoAdDidReceive(_ rewardBasedVideoAd:GADRewardBasedVideoAd) {
//print.text?.append("Reward based video ad is received.\n")
}
func rewardBasedVideoAdDidOpen(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
//print.text?.append("Opened reward based video ad.\n")
}
func rewardBasedVideoAdDidStartPlaying(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
//print.text?.append("Reward based video ad started playing.\n")
}
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
}
func rewardBasedVideoAdWillLeaveApplication(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
//print.text?.append("Reward based video ad will leave application.\n")
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didFailToLoadWithError error: Error) {
//print.text?.append("Reward based video ad failed to load.\n")
}
//MARK: Interstitial ad
func runTheInterStitialAd(){
var runFunc = SKAction.run(showInterstitialAdInScene)
var wait = SKAction.wait(forDuration: 1)
var sequence = SKAction.sequence([wait, runFunc])
}
func showInterstitialAdInScene() {
print("this code is working")
if var scene = SKScene(fileNamed: "Gameoverscene") {
// TRUE
if (interstitial.isReady) == true{
interstitial.present(fromRootViewController: self)
gameNumber = 0
}
// FALSE
if (interstitial.isReady) == false{
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/1033173712")
let request = GADRequest()
interstitial.load(request)
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if rewardBaseAd.isReady{
if reklameNummer == 1{
reklameNummer += 1
//rewardBaseAd.present(fromRootViewController: self)
//rewardBaseAd.load(GADRequest(), withAdUnitID: "ca-app-pub-1110799225910030/4904503594")
}
}
if rewardBaseAd.isReady{
if reklameNummer == 2{
reklameNummer = 0
//rewardBaseAd.present(fromRootViewController: self)
//rewardBaseAd.load(GADRequest(), withAdUnitID: "ca-app-pub-1110799225910030/4904503594")
}
}
if gameNumber == 2{
//showInterstitialAdInScene()
}
}
}
One way to do this is use a callback, which is a way to send the class that created a new class(scene) to that new class(scene) as an argument. This way the new class(scene) can call functions from the old class. Beneath is how to implement this in your code. First I make a custom initialiser which takes in the creating class as an argument and assigns it to a local variable(myCreator). Then in the function called when a player dies(deathFunction()), I call the runIntersitialAd() function from the creating class. I also changed the code which sets up the MenuScene from the GameViewController to send itself(GameViewController class) as an argument inside the MenuScene initialisation.
Change your scene class to something like this:
class MenuScene {
var myCreator : GameViewController!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience init(fileNamed: String, VCwhoCreatedMe: GameViewController) {
self.init(fileNamed: fileNamed, VCwhoCreatedMe: VCwhoCreatedMe)
myCreator = VCwhoCreatedMe
}
....your other code
deathFunction() { //whatever code you use when the player dies
myCreator.runTheInterStitialAd() //because of the callback construction this is now possible.
...other code
}
}
Inside your GameViewController, function viewDidLoad():
if let view = self.view as! SKView? {
if let scene = MenuScene(fileNamed: "MenuScene",VCwhoCreatedMe: self ) {
runTheInterStitialAd()
scene.scaleMode = .aspectFill
view.presentScene(scene)
..... other code
}
}

Swift2: TKSubmitTransitionButton. How do i stop a button from transition/ animating when user login/ signup are incorrect

I have tried a number of times and the best i get is there would be an animation which never cancels or stop regardless of the command i use.
After following #Mattias example, i updated my code and looks something like this:
// DESIGN ANIMATION... TKTRANSITIONSUBMITBUTTON
#IBOutlet weak var btnFromNib: TKTransitionSubmitButton!
#IBAction func onTapButton(sender: AnyObject) {
btnFromNib.startLoadingAnimation()
if let email = self.emailField.text where email != "", let password = self.passwordField.text where password != "" {
DataService.ds.REF_BASE.authUser(email, password: password, withCompletionBlock: { error, authData in
if error != nil {
self.btnFromNib.returnToOriginalState()
if error.code == STATUS_ACCOUNT_NONEXIST {
self.showErrorAlert("This User does not exist", msg: "Please Sign Up")
} else {
}
} else {
self.btnFromNib.startFinishAnimation(1, completion: {
let myTabbarController = self.storyboard?.instantiateViewControllerWithIdentifier("myTabbarController") as! UITabBarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = myTabbarController
myTabbarController.transitioningDelegate = self
})
}
})
}
}
The button yet keeps spinning / animating without stopping. After checking the custom animation class the function inherits from :
public func startLoadingAnimation() {
self.cachedTitle = titleForState(.Normal)
self.setTitle("", forState: .Normal)
self.shrink()
NSTimer.schedule(delay: shrinkDuration - 0.25) { timer in
self.spiner.animation()
}
}
public func startFinishAnimation(delay: NSTimeInterval, completion:(()->())?) {
NSTimer.schedule(delay: delay) { timer in
self.didEndFinishAnimation = completion
self.expand()
self.spiner.stopAnimation()
}
}
public func animate(duration: NSTimeInterval, completion:(()->())?) {
startLoadingAnimation()
startFinishAnimation(duration, completion: completion)
}
public override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
let a = anim as! CABasicAnimation
if a.keyPath == "transform.scale" {
didEndFinishAnimation?()
NSTimer.schedule(delay: 1) { timer in
self.returnToOriginalState()
}
}
}
func returnToOriginalState() {
self.layer.removeAllAnimations()
self.setTitle(self.cachedTitle, forState: .Normal)
}
I noticed it had a public overide func animationDidStop(anim: CAAnimation, finished: Bool) to be the function to stop the animation. But when i use it, i get this error!
How do i rightfully get this to work? ...
Thanks in Advance
** UPDATED QUESTION **
I checked the code of TKTransitionSubmitButton and there are public methods called startLoadingAnimation(), returnToOriginalState() and startFinishAnimation().
I suggest:
Button tapped
startLoadingAnimation()
Check credentials
If wrong/error: returnToOriginalState()
If correct: startFinishAnimation()
Transition, from TKTransitionSubmitButton documentation:
btn.startFinishAnimation {
//Your Transition
let secondVC = SecondViewController()
secondVC.transitioningDelegate = self
self.presentViewController(secondVC, animated: true, completion: nil)
}
Edit: As far as I can see .animate() of the class calls both the start and finish animation, and that's why you can't cancel it.
EDIT2 This one works as intended for me (however I'm not sure about the static cornerRadius)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var submitButton: TKTransitionSubmitButton!
override func viewDidLoad() {
super.viewDidLoad()
submitButton.layer.cornerRadius = 15
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPressed(sender: AnyObject) {
submitButton.startLoadingAnimation()
delay(2, closure: {
self.checkCredentials()
})
}
func checkCredentials()
{
//FAKING WRONG CREDENTIALS
let userAndPasswordCorrect = false
if !userAndPasswordCorrect
{
submitButton.returnToOriginalState()
//Alert or whatever
}
}
//Faking network delay
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
}
I checked the code of TKTransitionSubmitButton.
I resolve this issue. please try to stop animation under DispatchQueue.main.async and working well.
'func apicallforLogin() {
let urlString = "http://"
guard let requestUrl = URL(string:urlString) else { return }
let request = URLRequest(url:requestUrl)
let task = URLSession.shared.dataTask(with: request) {
(data, response, error) in
if error == nil,let usableData = data {
DispatchQueue.main.async {
self.btnLogin.startFinishAnimation(0.1, completion: {
let HomeVC = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
HomeVC.transitioningDelegate = self
self.navigationController?.pushViewController(HomeVC, animated: false)
})
}
print(usableData)
}else{
DispatchQueue.main.async {
self.btnLogin.returnToOriginalState()
}
}
}
task.resume()'
Well you might have got the answer by now but just I would like to give my answer. You can just copy below code and everything will work fine. I have made the change and had created the pull request for this issue.
import Foundation
import UIKit
#IBDesignable
open class TKTransitionSubmitButton : UIButton, UIViewControllerTransitioningDelegate, CAAnimationDelegate {
lazy var spiner: SpinerLayer! = {
let s = SpinerLayer(frame: self.frame)
return s
}()
#IBInspectable open var spinnerColor: UIColor = UIColor.white {
didSet {
spiner.spinnerColor = spinnerColor
}
}
open var didEndFinishAnimation : (()->())? = nil
let springGoEase = CAMediaTimingFunction(controlPoints: 0.45, -0.36, 0.44, 0.92)
let shrinkCurve = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
let expandCurve = CAMediaTimingFunction(controlPoints: 0.95, 0.02, 1, 0.05)
let shrinkDuration: CFTimeInterval = 0.1
#IBInspectable open var normalCornerRadius:CGFloat = 0.0 {
didSet {
self.layer.cornerRadius = normalCornerRadius
}
}
var cachedTitle: String?
var isAnimating = false
public override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
public required init!(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setup()
}
func setup() {
self.clipsToBounds = true
spiner.spinnerColor = spinnerColor
}
open func startLoadingAnimation() {
self.isAnimating = true
self.cachedTitle = title(for: UIControlState())
self.setTitle("", for: UIControlState())
self.layer.addSublayer(spiner)
// Animate
self.cornerRadius()
self.shrink()
_ = Timer.schedule(delay: self.shrinkDuration - 0.25) { timer in
self.spiner.animation()
}
}
open func startFinishAnimation(_ delay: TimeInterval,_ animation: CAMediaTimingFunction, completion:(()->())?) {
self.isAnimating = true
_ = Timer.schedule(delay: delay) { timer in
self.didEndFinishAnimation = completion
self.expand(animation)
self.spiner.stopAnimation()
}
}
open func animate(_ duration: TimeInterval,_ animation: CAMediaTimingFunction, completion:(()->())?) {
startLoadingAnimation()
startFinishAnimation(duration, animation, completion: completion)
}
open func setOriginalState() {
self.returnToOriginalState()
self.spiner.stopAnimation()
}
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
let a = anim as! CABasicAnimation
if a.keyPath == "transform.scale" {
didEndFinishAnimation?()
_ = Timer.schedule(delay: 1) { timer in
self.returnToOriginalState()
}
}
}
open func returnToOriginalState() {
self.spiner.removeFromSuperlayer()
self.layer.removeAllAnimations()
self.setTitle(self.cachedTitle, for: UIControlState())
self.spiner.stopAnimation()
self.isAnimating = false
}
func cornerRadius() {
let cornerRadiusAnim = CABasicAnimation(keyPath: "cornerRadius")
// cornerRadiusAnim.fromValue = frame.width
cornerRadiusAnim.toValue = frame.height/2
cornerRadiusAnim.duration = shrinkDuration
cornerRadiusAnim.timingFunction = shrinkCurve
cornerRadiusAnim.fillMode = kCAFillModeForwards
cornerRadiusAnim.isRemovedOnCompletion = false
layer.add(cornerRadiusAnim, forKey: cornerRadiusAnim.keyPath)
}
func shrink() {
let shrinkAnim = CABasicAnimation(keyPath: "bounds.size.width")
shrinkAnim.beginTime = CACurrentMediaTime() + 0.1
shrinkAnim.fromValue = frame.width
shrinkAnim.toValue = frame.height
shrinkAnim.duration = shrinkDuration
shrinkAnim.timingFunction = shrinkCurve
shrinkAnim.fillMode = kCAFillModeForwards
shrinkAnim.isRemovedOnCompletion = false
layer.add(shrinkAnim, forKey: shrinkAnim.keyPath)
}
func expand(_ animation: CAMediaTimingFunction) {
let expandAnim = CABasicAnimation(keyPath: "transform.scale")
expandAnim.fromValue = 1.0
expandAnim.toValue = 26.0
expandAnim.timingFunction = animation
expandAnim.duration = 0.3
expandAnim.delegate = self
expandAnim.fillMode = kCAFillModeForwards
expandAnim.isRemovedOnCompletion = false
layer.add(expandAnim, forKey: expandAnim.keyPath)
}
}

How to put GameCenter on application with swift?

I made a game using SpriteKit and Xcode 7 beta. I tried to add GameCenter and Leaderboard but the problem is that the score in the leaderboard won't change (HighScore doesn't upload to GameCenter), It stay 0 all the time and I don't know how to fix it. I'm using 2 different files: GameViewController.swift, and PointsLabel.swift
GameViewController.swift:
import GameKit
class GameViewController: UIViewController,UIGestureRecognizerDelegate, GKGameCenterControllerDelegate {
var score: PointsLabel!
override func viewDidLoad() {
super.viewDidLoad()
//initiate gamecenter
func authenticateLocalPlayer(){
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(GameViewController, error) -> Void in
if (GameViewController != nil) {
self.presentViewController(GameViewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
}
#IBAction func leaderboard(sender: UIButton) {
saveHighscore(score)
showLeader()
}
//send high score to leaderboard
func saveHighscore(score:Int) {
//check if user is signed in
if GKLocalPlayer.localPlayer().authenticated {
let scoreReporter = GKScore(leaderboardIdentifier: "Leaderboard_01")
scoreReporter.value = Int64(score)
let scoreArray: [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: {error -> Void in
if error != nil {
print("error")
}
})
}
}
//shows leaderboard screen
func showLeader() {
let vc = self.view?.window?.rootViewController
let gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
}
//hides leaderboard screen
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
There is an Error in this file:
Cannot invoke 'saveHighscore' with an argument list of type '(PointsLabel!)'
on code:
#IBAction func leaderboard(sender: UIButton) {
saveHighscore(score) //<- Here is Error
showLeader()
}
PointsLabel.swift:
import Foundation
import UIKit
import SpriteKit
class PointsLabel: SKLabelNode {
var score:Int = 0
init(num: Int) {
super.init()
fontColor = UIColor.blackColor()
fontSize = 30.0
score = num
text = "\(num)"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func increment() {
score++
text = "\(score)"
}
func setTo(num: Int) {
self.score = num
text = "\(self.score)"
}
}
I don't know how to fix it!
Your score variable is of type PointsLabel but your saveHighscore function expects an Int as parameter.
Looking at your code, the variable score will be an instance of PointsLabel so I guess you could use the score property of your instanciated class, which is an Int (the fact that you used "score" as a name for both variables is confusing. I suggest changing names to make them more explicit.).
#IBAction func leaderboard(sender: UIButton) {
saveHighscore(score.score)
showLeader()
}