I've been looking all over for an answer to this and I've found lots of examples in objective C (google developer docs, etc.) and some answers in swift, but not using spritekit, and being a novice, I just haven't been able to bridge the gaps in these tutorials to put it all together for my project. Honestly, I don't really care if the ad is called on app launch, or game over, I'd just be happy being able to call the ad period, though I guess on game launch is preferred.
Pretty sure I've got it all set up correctly in gameviewcontroller.swift, but I don't know how to actually call it. Here is the code from my gameviewcontroller.swift:
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController {
var interstitial : GADInterstitial!
func createAndLoadAd() -> GADInterstitial {
var ad = GADInterstitial()
ad.adUnitID = "ca-app-pub-4471013071748494/2980967718"
var request = GADRequest()
request.testDevices = [""]
return ad
}
Beyond this ... I also have this if statement to call the ad, but I don't know where it should be ... or if it's complete (in the tutorial, it was in a button, but I need it to be automatic, naturally:
if (self.interstitial.isReady) {
self.interstitial.presentFromRootViewController(self)
self.interstitial = self.createAndLoadAd()
}
Anyone have any experience with this? If anyone could help me complete this by letting me know where to place that above if statement, or if there is more that needs to be done ... your help will be much appreciated. Thank you.
Ok so I started a new project (Swift project) which is Game Project
In GameViewController:
class GameViewController: UIViewController
{
var interstitial = GADInterstitial()
override func viewDidLoad()
{
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? 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)
let delayTime = dispatch_time(DISPATCH_TIME_NOW,
Int64(5 * Double(NSEC_PER_SEC)))
//Creation of the ad and its request
self.interstitial = GADInterstitial()
self.interstitial.adUnitID = "ca-app-pub-4798156420380453/7714267723"
var request = GADRequest()
// request.testDevices = [""]
self.interstitial.loadRequest(GADRequest());//The method u were missing
dispatch_after(delayTime, dispatch_get_main_queue())
{
self.showAd()
}
}
}
func showAd()
{
if (self.interstitial.isReady)
{
self.interstitial.presentFromRootViewController(self)//Whatever shows the ad
}
}
It is my first swift code so don't judge me if I did something wrong
But when I lunch it after ±5 seconds i see the ad
Here is your example.
I am not familiar with Swift at all ,
but all you need to do is to get the interstitial delegate when it dismissed -> and request for the next interstitial, So in next time you will get the new AD
Feel free to ask anything !
P.S. Don't forget to change the admob ID to your ID.
My solution based on above comments was the following:
1) Add this in the GameViewController.swift
protocol AdmobInterstitialDelegate{
func showInterstitial()
}
...
// add this delegate in GameViewController definition
class GameViewController: UIViewController, GADInterstitialDelegate, AdmobInterstitialDelegate {
...
// and assign it to the GameScene class when you create its instance
let scene = GameScene()
scene.adDelegate = self
// do not forget to implement the delegated method itself
func showInterstitial(){
if (interstitial!.isReady) {
interstitial!.presentFromRootViewController(self)
}
}
and then you can use it in GameScene
class GameScene: SKScene {
....
var adDelegate: AdmobInterstitialDelegate?
....
// and finally - show the ad
override func didMoveToView(view: SKView) {
self.adDelegate?.showInterstitial();
....
hope this helps.
keep the if condition in viewDidAppear it will automatically execute
override func viewDidAppear(animated: Bool) {
if (interstitial.isReady) {
interstitial.presentFromRootViewController(self)
self.interstitial = self.createAndLoadInterstitial()
}
Related
I am trying to use a variable from my GameScene.swift file on my GameViewController.swift file to time my interstitial ads appropriately. It's a boolean value that determines if my player is dead or not.
var died = Bool()
That's all I did to create the variable in my GameScene.
When died == true in my GameScene, I want to send that to my GameViewController and then show an interstitial ad. I really just need to know how to pass a boolean between scenes. Thanks in advanced for your help.
You can follow these steps.
Do this in your GameScene:
protocol PlayerDeadDelegate {
func didPlayerDeath(player:SKSpriteNode)
}
class GameScene: SKScene {
var playerDeadDelegate:PlayerDeadDelegate?
...
// during your game flow the player dead and you do:
playerDeadDelegate.didPlayerDeath(player)
...
}
In the GameViewController you do:
class GameViewController: UIViewController,PlayerDeadDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
...
scene.playerDeadDelegate = self
}
}
func didPlayerDeath(player:SKSpriteNode) {
print("GameViewController: the player is dead now!!!")
// do whatever you want with the property player..
}
}
Your GameScene should have a reference object as delegate (e.g conforms to GameSceneDelegate protocol) which is actually pointing to GameViewController object. Then when died becomes true, inform your delegate object (GameViewController object) about this event via a delegate-method and implement that method by conforming to the above protocol in your GameViewController class.
I am trying to change the text of a field on a button cick
the button is getting called but the label displayed the old text.
If I use NSUserDefaults to save the value then I will have to close the app and reopen it to see the new value of text field.
Is there any way when a user presses a button the value gets reset instantaneously on the screen?
GameViewController Code
import UIKit
import SpriteKit
class GameViewController: UIViewController {
#IBOutlet var resetText: UIButton!
#IBAction func ResetTextPreseed(sender: AnyObject) {
GameScene().changeText()
}
override func viewDidLoad() {
super.viewDidLoad()
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 shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
GameScene Code
import SpriteKit
class GameScene: SKScene {
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
var text = "Hello, WOrld"
override func didMoveToView(view: SKView) {
/* Setup your scene here */
myLabel.text = text
myLabel.fontSize = 45
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
self.addChild(myLabel)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
func changeText(){
text = "I got changed"
myLabel.text = text
self.addChild(myLabel)
print ("The value of text is \(text)")
}
}
Currently, what you are doing will not work because you are not referencing the current scene but rather making a new instance of a GameScene scene and calling changeText() method on that instance, which has no effect on a current scene.
There is always a debate about should you or shouldn't use UIKit elements with SpriteKit. I would not go into that topic, but in general, SpriteKit and UIKit are different beasts and even if I really like both frameworks I would stick to SpriteKit only as much as I can when it comes to games ... And about some differences... For example, there is a difference between how SKScene renders its nodes vs how views are rendered. Some quotes from docs :
In the traditional view system, the contents of a view are rendered
once and then rendered again only when the model’s contents change.
This model works very well for views, because in practice most view
content is static. SpriteKit, on the other hand, is designed
explicitly for dynamic content. SpriteKit continuously updates the
scene contents and renders it to ensure that animation is smooth and
accurate.
More differences:
Different coordinate systems.
Views are added to the views (not the the scene).
Nodes are added to the scene (not the the view).
More about view's rendering cycle can be found here.
More about how SpriteKit renders a scene can be found here .
So because of these differences you may run (not necessarily of course) into different problems when mixing these two.
You have three solutions (I can think of):
1) Accessing current scene through self.view inside GameViewControllerr Ugly solution IMO, but it will work:
#IBAction func someAction(sender: AnyObject) {
let skView = self.view as! SKView
if let currentScene = skView.scene as? GameScene {
currentScene.changeText()
}
}
2) Nice solution, but again this is just my opinion - Implementing custom buttons using SKSpriteNode. Just search SO about this.
3)Use third party SpriteKit buttons like SKAButton or AGSpriteButton.
So, I've found two ways of displaying google ads in my SpriteKit game... Both ways work, but I'm concerned that one of them is a more efficient etc.
My game just has 1 ViewController and 1 GameScene. The difference from the two implementations are when and where they are created.
Both require:
import GoogleMobileAds
var googleBannerView: GADBannerView!
This was the way I implemented it first:
in: GameViewController.swift
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
googleBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
googleBannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
googleBannerView.rootViewController = self
let request: GADRequest = GADRequest()
googleBannerView.loadRequest(request)
googleBannerView.frame = CGRectMake(0, view.bounds.height - googleBannerView.frame.size.height, googleBannerView.frame.size.width, googleBannerView.frame.size.height)
self.view.addSubview(googleBannerView!)
if let skView = self.view as? SKView { //cast root as SKView
if skView.scene == nil {
//create and present gameScene
}
}
}
This is the second way:
in: GameScene.swift
override func didMoveToView(view: SKView) {
googleBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
googleBannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
googleBannerView.rootViewController = self.view?.window?.rootViewController
let request: GADRequest = GADRequest()
googleBannerView.loadRequest(request)
googleBannerView.frame = CGRectMake(0, view.bounds.height - googleBannerView.frame.size.height, googleBannerView.frame.size.width, googleBannerView.frame.size.height)
self.view?.addSubview(googleBannerView!)
addChild(worldNode) //make whole world a node, create game nodes, in worldNode
switchToMainMenu() //go to menu menu
}
I think the only real difference is how you set the rootViewController, and given my game only has the 1 ViewController, both work...
Which would be the better implementation?
You should definitely be doing this via the view controller. This makes more sense from a design standpoint. The GameScene's job is to worry about game content only. The view controller's job is to manage and control views (Hence the name "View Controller.")
Im following a tutorial right now and Im getting an error that I do not know how to fix.
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = StartGameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
On line 8 the let scene = StartGameScene(size: view.bounds.size)
is giving me an error:
use of Unresolved Identifier ' StartGameScene'.
I have created a CocoaTouch class and named StartGameScene. I dont know what the issue is. How do I fix it?
StartGameScene would need to be a class declared like this:
class StartGameScene: SKScene {...}
Either StartGameScene is not declared as an SKScene or the class itself is not declared.
The cocoa touch class that you have created has to inherit from SKScene. SKScene is the class in which you define your game's scene. Hence your code should look like:
class StartGameScene: SKScene {
}
If you have already done this, then please make sure there isn't any typographic error.
just change StartGameScene to GameScene
I am having trouble figuring out how to change view controllers when your player collided with an object.
I want to like a menu to pop-up displaying a menu button and a replay button, also so extra buttons that are not important at this moment of time. I am not sure how some of those end of game menus are made, I am thinking switching view controllers, if you know exactly how they are made please tell me.
This is the code I have at the moment, and the only thing it does is display a label that the game is over and when that label is tapped the game will restart:
import Foundation
import AVFoundation
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var movingGround: PPMovingGround!
var square1: PPSquare1!
var wallGen: PPWallGen!
var diamondGen: PPDiamondGen!
var isStarted = false
var isGameOver = false
var isDiamondContact = false
var playerNode: SKNode!
override func didMoveToView(view: SKView) {
//code that is not important was deleted
func collisionWithDiamond() {
isDiamondContact = true
}
func restart() {
let newScence = GameScene(size: view!.bounds.size)
newScence.scaleMode = .AspectFill
view!.presentScene(newScence)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if isGameOver {
restart()
} else {
square1.flip()
}
}
override func update(currentTime: CFTimeInterval) {
}
// MARK: - SKPhysicsContactDelegate
func didBeginContact(contact: SKPhysicsContact) {
if !isGameOver {
gameOver()
} else {
!isDiamondContact
collisionWithDiamond()
}
}
Note: I have deleted code that is unrelated or not necessary.
Updates:
Link to a game play of a game: https://www.youtube.com/watch?v=WUibTETfEQY
SKIP TO 2:32 TO SEE THE GAME OVER SCREEN
Link to image of game over screen: Image
(I was unable to post an image here because I don't have the required 10 rep points yet.)
// Edited Answer
This will be the easiest. Create a new GameOverScene.swift that is a SKScene. Then customize that scene however you want with background image, SKLabelNodes for buttons. Checkout creating buttons in skview to point to different scenes
When the game ends in GameScene,
let gameOverScene: GameOverScene = GameOverScene(size: self.size)
self.view!.presentScene(gameOverScene, transition: SKTransition.doorsOpenHorizontalWithDuration(1.0))
Here is a project that has this implemented, http://www.raywenderlich.com/76741/make-game-like-space-invaders-sprite-kit-and-swift-tutorial-part-2
// First Answer -----------------------------------------------
If you want to switch viewControllers, you will have to present the new viewController like this or with segue,
self.view?.window?.rootViewController?.presentViewController(newView, animated: true, completion: nil)
self.view?.window?.rootViewController?.performSegueWithIdentifier("id", sender: AnyObject)
Otherwise create a SKView and add buttons, then add it to the scene when game is over or add it before, hide it, then show it. Once user picks a choice, remove it or hide it with,
SKView.hidden = false
SKView.hidden = true
Add SKView with,
self.view?.addSubview(SKView)
Simple SKView overlay,
let view1 = SKView(frame: CGRectMake(0, 0, 200, 200))
view1.center = self.view!.center
self.view?.addSubview(view1)
If the game is over and you want to present a selective menu, you could present a UIAlertView that presents the user with whatever options that you want. From there they could restart the game, or they could choose to go to some other view like one that manages their player stats or something ( I don't know what exactly your game is).