Presenting UIViewController from SKScene? - facebook

So at the beginning I was having trouble implementing social media sharing into my project using Swift/Sprite-Kit. I believe I have now accomplished that but I just cannot trigger the methods, or as it seems everybody's struggle, I cannot present the view controller from my SKScene. So what I first did, was to create my buttons on my EndGame Scene. Then on my touchesEnded method I called the NSNotificationCenter. Something like this:
import SpriteKit
import UIKit
import Social
class EndGameScene: SKScene {
var facebookButton: SKNode! = nil
var twitterButton: SKNode! = nil
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
// FacebookButton
facebookButton = SKSpriteNode(imageNamed: "facebookButton")
facebookButton.position = CGPoint(x: self.size.width * 0.3 , y: self.size.height * 0.45);
addChild(facebookButton)
// TwitterButton
twitterButton = SKSpriteNode(imageNamed: "twitterButton")
twitterButton.position = CGPoint(x: self.size.width * 0.5 , y: self.size.height * 0.45);
addChild(twitterButton)
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if facebookButton.containsPoint(location) {
NSLog("Button tapped")
NSNotificationCenter.defaultCenter().postNotificationName("FacebookID", object: nil)
}
if twitterButton.containsPoint(location) {
NSLog("Button tapped")
NSNotificationCenter.defaultCenter().postNotificationName("TwitterID", object: nil)
}
}
}
Then I created my SocialViewController with the methods that are supposed to be triggered with help of the NSNotificationCenter to show the sheets. This is the code I used for it:
import UIKit
import Social
class SocialViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showTweetSheet", name: "TwitterID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showFacebookSheet", name: "FacebookID", object: nil)
}
func showTweetSheet() {
let tweetSheet = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
tweetSheet.completionHandler = {
result in
switch result {
case SLComposeViewControllerResult.Cancelled:
break
case SLComposeViewControllerResult.Done:
break
}
}
tweetSheet.setInitialText("Test Twitter")
tweetSheet.addImage(UIImage(named: "TestImage.png"))
tweetSheet.addURL(NSURL(string: "http://twitter.com"))
self.presentViewController(tweetSheet, animated: false, completion: {
})
}
func showFacebookSheet() {
let facebookSheet = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
facebookSheet.completionHandler = {
result in
switch result {
case SLComposeViewControllerResult.Cancelled:
break
case SLComposeViewControllerResult.Done:
break
}
}
facebookSheet.setInitialText("Test Facebook")
facebookSheet.addImage(UIImage(named: "TestImage.png"))
facebookSheet.addURL(NSURL(string: "http://facebook.com"))
self.presentViewController(facebookSheet, animated: false, completion: {
})
}
I literally have no idea on what I might be missing or doing wrong. I've read several posts on this and using the NSNotificationCenter is supposed to be the best way to accomplish this but seems is not working for me. So if there is anyone there that could help me out I would really appreciate it. Thanks in advance!

You can download the Facebook Sdk from https://github.com/facebook/facebook-android-sdk. And after create the key hash using your cmd prompt. For more details for create the key hash see the link https://developers.facebook.com/docs/android/getting-started

Related

How to change button images from another class?

I´m new to coding and I want to know how to change the buton image in the menu class from the setting class.
Here is the menu class:
class Mainmenu: SKScene{
var ratingButton = SKSpriteNode(imageNamed: "RatingButton1")
}
In my setting class I want to change this image to "RatingButton2" just by clicking a button.
Here is the setting class:
class Settings: SKScene {
override func didMove(to view: SKView) {
self.backgroundColor = SKColor.white
let DCButton = SKSpriteNode(imageNamed: "ChangeButton")
DCButton.position = CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.8)
DCButton.setScale(0.53)
self.addChild(DCButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == DCButton {
//Change the button image here
}
}
}
}
Swift 3+ Use Notificationcenter to update your button image.
// Define identifier
let notificationName = Notification.Name("NotificationIdentifier")
// Register to receive notification in Mainmenu
NotificationCenter.default.addObserver(self, selector: #selector(receivedNotification), name: notificationName, object: nil)
// Post notification into Settings write this line into "touchesBegan" method
NotificationCenter.default.post(name: notificationName, object: nil)
// Stop listening notification if required.
NotificationCenter.default.removeObserver(self, name: notificationName, object: nil)
Notification Handler
func receivedNotification(notification: Notification){
// Set your button image here...
}
I would not recommend using NSNotificationCenter for this task, it adds a lot of overhead for something that will be rarely used.
Now unfortunately I do not know how your layout is structured, so I am not sure what answer is best for you.
If Menu and Settings are both on the scene at the same time, then you can search the scene to find the button you are looking for:
class Mainmenu: SKScene{
var ratingButton = SKSpriteNode(imageNamed: "RatingButton1")
ratingButton.name = "ratingButton"
}
class Settings: SKScene {
override func didMove(to view: SKView) {
self.backgroundColor = SKColor.white
let DCButton = SKSpriteNode(imageNamed: "ChangeButton")
DCButton.position = CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.8)
DCButton.setScale(0.53)
self.addChild(DCButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == DCButton {
let button = scene.childNode(withName:"//ratingButton") as! SKSpriteNode
button.texture = SKTexture(imageNamed:"RatingButton2")
}
}
}
}
If it is not on the scene and you are presenting it, then you want to use userData to assign what your button is before hand
let menu = Mainmenu(...)
menu.userData = ["ratingButton":SKTexture(imageNamed:textureName)] //texture name is either Ratingbutton1 or RatingButton2 depending on state
self.view.presentScene(menu)
Then in the viewDidLoad, just read the userData
func viewDidLoad(...)
{
ratingButton.texture = userData?["ratingButton"]
}

Spritekit Supporting iAd

I have been looking everywhere on the web for tutorials on how to include iad banners in my spritekit game. For example I looked at this: Swift SpriteKit iAd but I got some errors, probaly due to the new swift 2 and swift 1. But could you explain what to do to include IAD in my spritekit game. Thank you in advance.
Make sure you have this code in your GameViewController. I just tested this out and it works for landscape and portrait mode.
class GameViewController: UIViewController, ADBannerViewDelegate {
//--------------------
//-----iAd Banner-----
//--------------------
var SH = UIScreen.mainScreen().bounds.height
let transition = SKTransition.fadeWithDuration(0)
var UIiAd: ADBannerView = ADBannerView()
override func viewWillAppear(animated: Bool) {
let BV = UIiAd.bounds.height
UIiAd.delegate = self
UIiAd.frame = CGRectMake(0, SH + BV, 0, 0)
self.view.addSubview(UIiAd)
}
override func viewWillDisappear(animated: Bool) {
UIiAd.delegate = nil
UIiAd.removeFromSuperview()
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.alpha = 1 // Fade in the animation
UIView.commitAnimations()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5)
UIiAd.alpha = 0
UIView.commitAnimations()
}
func showBannerAd() {
UIiAd.hidden = false
let BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH - BV, UIScreen.mainScreen().bounds.width, 0)
UIView.commitAnimations()
}
func hideBannerAd() {
UIiAd.hidden = true
let BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.5) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH + BV, UIScreen.mainScreen().bounds.width, 0) //Beginning position of the ad
UIView.commitAnimations()
}
//--------------------
//-----View Loads-----
//--------------------
override func viewDidLoad() {
super.viewDidLoad()
//iAd Control
self.UIiAd.hidden = true
self.UIiAd.alpha = 0
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.hideBannerAd), name: "hideadsID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.showBannerAd), name: "showadsID", object: nil)
}
Add the following outside your class declarations. It doesn't matter what class you go to, as long as it's global so you can access them from any game scene.
//-------------
//-----Ads-----
//-------------
func showAds() {
NSNotificationCenter.defaultCenter().postNotificationName("showadsID", object: nil)
}
func hideAds() {
NSNotificationCenter.defaultCenter().postNotificationName("hideadsID", object: nil)
}
And then whenever you want to show ads in the specific scene or whenever, just call the "showAds()" function or "hideAds()" to hide them.

swift animation not work in UIKeyboardWillShowNotification event

I don't know why animation work fine in UIKeyboardDidShowNotification event but not work in UIKeyboardWillShowNotification event.
Code looks like this:
anim in the comment code not work good, color will change but duration = 4 is not right
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name:UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidHide:"), name:UIKeyboardDidHideNotification, object: nil)
}
deinit {NSNotificationCenter.defaultCenter().removeObserver(self)}
func keyboardDidShow(notification: NSNotification) {
showAnima1()
}
func keyboardDidHide(notification: NSNotification) {
showAnima2()
}
func keyboardWillShow(notification: NSNotification) {
// showAnima1() // animate not work here
}
func keyboardWillHide(notification: NSNotification) {
// showAnima2() // animate not work here
}
func showAnima1() {
UIView.animateWithDuration(4, delay: 0, options: UIViewAnimationOptions(rawValue: 7), animations: { () -> Void in
self.view.backgroundColor = UIColor.greenColor()
}) { (finish) -> Void in
print("animate state = \(finish)")
}
}
func showAnima2() {
UIView.animateWithDuration(4, delay: 0, options: UIViewAnimationOptions(rawValue: 7), animations: { () -> Void in
self.view.backgroundColor = UIColor.whiteColor()
}) { (finish) -> Void in
print("animate state = \(finish)")
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {self.view.endEditing(false)}
}
Sorry, i see comment in source code says:
// Each notification includes a nil object and a userInfo dictionary containing the
// begining and ending keyboard frame in screen coordinates. Use the various UIView and
// UIWindow convertRect facilities to get the frame in the desired coordinate system.
// Animation key/value pairs are only available for the "will" family of notification.
The last comment maybe it means "did" family of notification???
I had the same problem.
It looks like the animate function has to be called from the main thread. Wrapping the animation in DispatchQueue.main.async worked for me:
#objc func keyboardWillHide(notification: NSNotification) {
DispatchQueue.main.async {
UIView.animate(withDuration: 2.0) {
self.view.frame.origin.y = 0
}
}
}

Game Center Not Properly Working. Swift, Sprite Kit

I recently tried to add Game Center to my Sprite Kit Game, but it's not working properly.
When the game starts in the simulator, the Game Center login page does show up. When I start the game on my phone it does not. Can someone tell me what I am doing wrong.
//GameViewController.Swift
import GameKit
class GameViewController: UIViewController, ADBannerViewDelegate, GKGameCenterControllerDelegate {
var bannerView:ADBannerView?
override func viewDidLoad() {
super.viewDidLoad()
// Presenting scene without using GameScene.sks
let skView = view as! SKView
let myScene = GameScene(size: skView.frame.size)
myScene.scaleMode = .ResizeFill
skView.presentScene(myScene)
authenticateLocalPlayer()
}
//initiate gamecenter
func authenticateLocalPlayer(){
var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
}
else {
println((GKLocalPlayer.localPlayer().authenticated))
}
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
//GameScene.Swift
import GameKit
class GameScene: SKScene, SKPhysicsContactDelegate{
var playerScore = 0
func playerScoreUpdate() {
playerScorelabel.text = "\(playerScore)"
}
func saveHighScore(high:Int) {
NSUserDefaults.standardUserDefaults().setInteger(high, forKey: "highscore")
//check if user is signed in
if GKLocalPlayer.localPlayer().authenticated {
var scoreReporter = GKScore(leaderboardIdentifier: "TF1G002ID") //leaderboard id here
scoreReporter.value = Int64(playerScore) //score variable here (same as above)
var scoreArray: [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: {(error : NSError!) -> Void in
if error != nil {
println("error")
}
})
}
}
//GameOver.Swift
import GameKit
class GameOverScene: SKScene, GKGameCenterControllerDelegate {
//shows leaderboard screen
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
// Press Finger
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "replay" {
playSound(sound)
}
if node.name == "leaderboard" {
showLeader()
}
}
}
//hides leaderboard screen
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
Did you import the GameKit framework into your app?
Go to your project -> General -> scroll until you see linked frameworks -> click the plus sign -> add GameKit framework by searching

Sharing highscore with social media

I Want that when the player is done with the level, he can click a button(shareButton) so an UIActivityviewcontroller pops up where the player can share its highscore with the social media.
But my problem is, the button is in the GameScene, but the UIActivityviewcontroller can only be called in the GameViewController.. how do I do this?
Game starts with GameMenuScene, when play is clicked it will move to GameScene:
class GameMenuScene: SKScene {
if nodeAtPoint.name == "play"{
NSUserDefaults.standardUserDefaults().setInteger(score+1, forKey: "currentLevel")
NSUserDefaults.standardUserDefaults().synchronize()
self.removeAllActions()
self.removeAllChildren()
var scene1:SKScene = GameScene(size: self.size) ##Updated : error: SKSCene does not have a member named "weakGameVC"
self.view?.presentScene(scene1)
}
}
GameScene:
Here is the GameViewController(as you can see, first scene is GameMenuScene:
import UIKit
import SpriteKit
import AVFoundation
import Social
class GameViewController: UIViewController, UITextFieldDelegate{
var player:SKSpriteNode = SKSpriteNode()
var scene:GameMenuScene!
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as SKView
skView.multipleTouchEnabled = false
scene = GameMenuScene(size: skView.bounds.size)
//scene.scaleMode = SKSceneScaleMode.ResizeFill
skView.showsFPS = true
skView.showsNodeCount = true
skView.presentScene(scene)
}
/*
func shareButton() {
var myShare = "aa"
let activityVC:UIActivityViewController = UIActivityViewController(activityItems: ["aa"], applicationActivities: nil)
presentViewController(activityVC, animated: true, completion: nil)
}
*/
override func prefersStatusBarHidden() -> Bool {
return true
}
}
And here the part of GameScene where the touch in the share button is detected:
import SpriteKit
import Social
class GameScene: SKScene, SKPhysicsContactDelegate {
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location: CGPoint! = touch.locationInNode(self)
let nodeAtPoint = self.nodeAtPoint(location)
if (nodeAtPoint.name != nil) {
if nodeAtPoint.name == "share"{
//shareButton()
}
}
}
}
}
This work for me:
if nodeAtPoint.name == "share"{
var myShare = "My best is \(highScoreText.text)"
let controller = self.view?.window?.rootViewController as GameViewController
let activityVC: UIActivityViewController = UIActivityViewController(activityItems: [myShare], applicationActivities: nil)
controller.presentViewController(activityVC, animated: true, completion: nil)
}