Sharing highscore with social media - swift

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)
}

Related

Could not cast value of type 'SKScene'

I created a new Xcode Game project. I stripped the default animations in the project and added a new Swift file and a new .sks both called MenuScene.
In my GameViewController, I replaced references to by GameScene with MenuScene as I want this scene to launch first:
override func viewDidLoad() {
super.viewDidLoad()
// Load 'GameScene.sks' as a GKScene. This provides gameplay related content
// including entities and graphs.
if let scene = GKScene(fileNamed: "MenuScene") {
// Get the SKScene from the loaded GKScene
if let sceneNode = scene.rootNode as! MenuScene? {
// Set the scale mode to scale to fit the window
sceneNode.scaleMode = .aspectFill
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
}
When I try to launch I get the following error:
Could not cast value of type 'SKScene' (0x1105624) to 'Spritekit10.MenuScene' (0x104c38).
If I change it back to GameScene, which appears to have the exact same setup, all seems fine.
Can anyone point me in the right direction with what the problem is with this?
On my MenuScene.sks under Custom Class, I've added MenuScene thinking that was the problem but the error still shows (and the textfield seems to randomly clear itself when I go back to it.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func sceneDidLoad() {
}
}
.
import SpriteKit
import GameplayKit
class MenuScene: SKScene {
override func sceneDidLoad() {
}
}
So I figured out the issue.
For the .sks file, I had to add a name to the scene in the attributes inspector (even though it was blank in the GameScene). Once I done this, the custom class value saved and the file now loads without an error. Not sure if thats a bug or by design.
Your problem is you are trying to upcast an SKScene to a MenuScene.
This cannot be done, I see you have checked your custom class in your sks file to ensure that it is set to MenuScene, but did you make sure you saved it correctly? You need to type it in and hit enter, if you do not, then the scene will not auto save it, and when you leave will clear it out.
For Xcode 8.0/8.1 , create a swift file named "Menuscene" and an sks file named "Menuscene" too.
delete everything in the Menuscene swift file and insert this code
import SpriteKit
import GameplayKit
class Menuscene: SKScene {
override func didMove(to view: SKView) {
let menutext = SKLabelNode()
menutext.text = "MEnuscene"
menutext.position = CGPoint(x: 0, y: 0)
menutext.fontSize = 120
self.backgroundColor = UIColor.blue
addChild(menutext)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let gamescene = SKScene(fileNamed: "GameScene")
gamescene?.scaleMode = .fill
self.scene?.view?.presentScene(gamescene!,transition: SKTransition.doorsCloseHorizontal(withDuration: 1.0))
}
override func update(_ currentTime: TimeInterval) {
}
}
and in the attribute inspector tab, set name to "Menuscene", hit enter (very important). then on the next tab, set custom class name to "Menuscene",hit enter (very important).
In your Gamescene.swift file, double-check to be sure your class starts with
class GameScene: SKScene {
add this code to your touchesBegan func
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let Menuscene = SKScene(fileNamed: "Menuscene")
Menuscene?.scaleMode = .fill
self.scene?.view?.presentScene(Menuscene!,transition: SKTransition.doorsOpenVertical(withDuration: 1.0))
}
finally in your Gameviewcontroller file, delete everything and insert this code
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "Menuscene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
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
}
}
you're welcome! you should be able to tap from game screen to menu screen.
I found something weird.
My project name has a "-" character.
After I removed this character from Target name, the project could cast scene.rootNode to GameScene.
It works on iOS 10.3.1 for me.
override func viewDidLoad() {
super.viewDidLoad()
let fileName = "GameScene"
// Load 'GameScene.sks' as a GKScene. This provides gameplay related content
// including entities and graphs.
guard let scene = GKScene(fileNamed: fileName) else {
return
}
guard let sceneNode = scene.rootNode as? GameScene ?? GameScene(fileNamed: fileName) else {
return
}
// Copy gameplay related content over to the scene
sceneNode.entities = scene.entities
sceneNode.graphs = scene.graphs
// Set the scale mode to scale to fit the window
sceneNode.scaleMode = .aspectFill
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}

Function not called with selector action

I'm trying to handle tap gesture in an external UIViewController's class but my function was never called. Here is my
code:
import SceneKit
import UIKit
class SceneManager
{
private let assetFolder: String
private let mainCamera: SCNNode
private let view: SCNView
private let scene: SCNScene
init(view: SCNView, assetFolder: String, sceneFile: String, mainCameraName: String, backgroundColor: UIColor) {
self.assetFolder = assetFolder
self.scene = SCNScene(named: (self.assetFolder + "/scene/" + sceneFile))!
self.mainCamera = self.scene.rootNode.childNodeWithName(mainCameraName, recursively: true)!
self.view = view
self.view.backgroundColor = backgroundColor
self.view.allowsCameraControl = false
self.view.pointOfView = self.mainCamera
self.view.scene = self.scene
//PROBLEM BELOW
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.addGestureRecognizer(gesture)
}
#objc func handleTap(sender: UITapGestureRecognizer) {
print("hello")
}
}
Here is my ViewController Class :
import UIKit
import QuartzCore
import SceneKit
class ViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
let view = self.view as! SCNView
view.showsStatistics = true
_ = SceneManager(view: view, assetFolder: "art.scnassets", sceneFile: "EURO_COPTER.dae", mainCameraName: "camera", backgroundColor: UIColor.blackColor())
}
}
If someone has an idea. Thanks in advance.
Try following code it may help
let gesture = UITapGestureRecognizer(target: self, action: #selector(SceneManager.handleTap(_:)))
Try to this way:-
When you declare your class, add UIGestureRecognizerDelegate after the class it subclasses. Here's what that looks like in my case:
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.userInteractionEnabled = true;
gesture.delegate = self
self.view.addGestureRecognizer(gesture)

Displaying interstitial admob when the game is over with Sprite Kit and iOS

I have been trying to display adds when the game is over for my game app. I have created a game over variable on GameScene.swift and I call that variable in the GameViewController.swift. However, the add is displayed shortly after the game starts. Could anyone point out what am I doing wrong? Here is my code:
import UIKit
import SpriteKit
import GoogleMobileAds
private var interstitial: GADInterstitial?
class GameViewController: UIViewController, GADInterstitialDelegate {
private var interstitial: GADInterstitial?
override func viewDidLoad() {
super.viewDidLoad()
interstitial = createInterstitial()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
override func prefersStatusBarHidden() -> Bool {
return true
}
private func createInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-5713504307801022/7610056592")
interstitial.delegate = self
let request = GADRequest()
request.testDevices = ["ca-app-pub-5713504307801022/7610056592"]
interstitial.loadRequest(request)
return interstitial
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
interstitial = createInterstitial()
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (interstitial!.isReady) {
if gameOver1 == true {
self.interstitial!.presentFromRootViewController(self)
interstitial = createInterstitial()
}
}
}
}
First - this is how you should load and recycle AdMob interstitials -https://stackoverflow.com/a/37938286/2405378
Second - viewWillLayoutSubviews can be called multiple times and each time this method creates new instance of the GameScene - with gameOver1 being false?

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

Presenting UIViewController from SKScene?

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