This is my first time developing an app using swift and sprite-kit. I would like to integrate adMob into it. I have been searching a solution to my problem but I've had no success.
I have the following code set up inside GameViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
bannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
bannerView.isHidden = true
bannerView.adUnitID = "ca-app-pub-************************"
bannerView.rootViewController = self
view.addSubview(bannerView)
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = false
skView.showsNodeCount = false
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
// Create and configure the scene.
let aspectRatio = skView.bounds.size.height / skView.bounds.size.width
let scene = MainMenuScene(size:CGSize(width: 320, height: 320 * aspectRatio))
skView.presentScene(scene)
showBanner()
}
func showBanner() {
bannerView.isHidden = false
let request = GADRequest()
request.testDevices = ["******************"]
bannerView.load(request)
}
This setup displays the ad on all of my scenes perfectly but my question is, how would I be able to make it show on MainMenuScene.swift and GameOverScene.swift by using NotificationCenter? Both of these are their own class.
As you mentioned you can use Notification Center.
Create a key for your notification to avoid typos. You can put this anywhere you like in your project (outside any class or a new .swift file)
extension Notification.Name {
static let showBannerAd = Notification.Name(rawValue: "ShowBanner")
}
Than in your GameViewController add the observer in ViewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(showBanner), name: .showBannerAd, object: nil) // selector is the method to call
and in your SKScene(s) you can post the notification like so when you need to show the banner.
NotificationCenter.default.postNotificationName(.showBannerAd, object: nil)
Alternatively I have a helper on Github which will make this much easier and cleaner.
https://github.com/crashoverride777/SwiftyAds
Hope this helps
Related
hello there i am trying to figure out what the issue is why i cant get a cross on the game board when a tap is made. the TTT class is the one below the first code and it is called in the main code. i will appreciate if some can help me on this
#IBOutlet var fields: [TTTImageView]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func fieldTapped (recognizer:UITapGestureRecognizer) {
let tappedField = recognizer.view as! TTTImageView
tappedField.setPlayer(_player: "x.png")
}
func setupField () {
for index in 0 ... fields.count - 1 {
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(fieldTapped))
gestureRecognizer.numberOfTapsRequired = 1
fields[index].addGestureRecognizer(gestureRecognizer)
}
}
import UIKit
class TTTImageView: UIImageView {
var player:String?
var activated:Bool! = false
func setPlayer (_player:String) {
self.player = _player
if activated == false {
if _player == "x.png" {
self.image = UIImage (named: "x.png")
}else{
self.image = UIImage (named: "o.png")
}
activated = true
}
}
}
Make sure when you set fields[index].addGestureRecognizer(gestureRecognizer) to set isUserInteractionEnabled to true.
fields[index].isUserInteractionEnabled = true
Whenever you want to detect user activity (e.g. UITapGestureRecognizer on a UIImageView, you need to set this to true
EDIT:
I also wanted to mention something I noticed after looking at your code again: the method you are using for selectors has been deprecated. If you are using Swift 3 (which I highly recommend you do), you shouldn't call selectors like this: "functionName:" anymore. Now we use selectors like so: #selector(functionName(_:)). You should start updating your code to the most current syntax sooner rather than later.
I have five iPad scenes, and 5 iPhone Scenes in my GVC I have this, I can call the Welcome Scene and Hud Scene no problem, yet I can not replicate the same calls for the other scenes. I do not know if it is the curly braces, yet I can not seem to call the other iPad scenes it defaults to the iPhone scene. (trust me I was pretty excited when the HUD, showed up.) Can someone give some advice on the structure of my code. Please....
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
if let scene = WelcomeScene(fileNamed:"WelcomeScene") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
} else {
if let scene = WelcomeScenePad(fileNamed: "WelcomeScenePad") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
if let scene = HudScenePad(fileNamed: "HudScenePad") {
let skView = self.view as! SKView
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
} else if let scene = WelcomeScene(fileNamed:"WelcomeScene") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
}
override func prefersStatusBarHidden() -> Bool {
return false
}
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.
}
}
This bit of code lets me know that the game scene is going to proper sks file, and prints the value in the editor, to verify, this is in my gameOver Function.
if (UIDevice.currentDevice().userInterfaceIdiom == .Pad ){
if let _ = SceneTypePad(rawValue: fullSKSNameToLoad + String("Pad")) {
fullSKSNameToLoad = "fileNamed" + "Pad"
goToScenePad(SceneTypePad.DebateScene1Pad)
print(("Went to DebateScenePad"))
_ = SKTransition.fadeWithDuration(3)
_ = DebateScene1Pad()
}
} else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone ){
goToScene(SceneType.DebateScene1)
(print("Went to DebateScenePhone"))
_ = SKTransition.fadeWithDuration(3)
_ = DebateScene1()
}
Three secs is too long to wait btw... :)
I needed to create a new static variable to call the SKs pad scene in my GlobalData/Base Scene file. Noob mistake. Word to the wise when duplicating code for the new files double check the variables, when duplicated swift files. Also, it is good to give the mind a break, individuals can not keep their attention span and be sharp after 14 hours of coding.... Take a walk, sort it out with a fresh mind. Deadlines are crucial in this business, yet sometimes pressure can bring about silly decisions that can be easily solved.
static var previousScenePad:SceneTypePad?
static var nextScenePad:SceneTypePad?
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
if (UIDevice.currentDevice().userInterfaceIdiom == .Pad ){
if let _ = SceneTypePad(rawValue: fullSKSNameToLoad + String("Pad")) {
fullSKSNameToLoad = "fileNamed" + "Pad"
}
} else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone ){
}
Does work in GVC when calling particular SKS files. Obviously it renders the proper view based upon using the correct fileName "" that is defined in the base class, yes I am aware, that there are better way to use one SKS files, and using camera nodes to adjust views. When it comes to content, and having more space it gives opportunity to create a different experience with more pixels, and more space. Assets are equally important, as in the beginning I was calling the wrong assets per device, I decided to hard code, the scale factors for my look without losing resolution. The end result will be a universal app that works cross platforms. If you optimize right, I was able to condense a 140mb app, to 76mb, even though I added 5 new scenes to my app bundle. Check your background music, check your sound effects, and PNG files. Limit emitters to the effect that looks good. You can always go back and find cleaner approach in the next update!!!
I get an error that "Class 'GameScene' has no initializers" when I try to add a level selection to my game.
I present the scene in GameViewController.swift like this:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.level(1) {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsPhysics = 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)
}
}
And in my GameScene.swift I wanted to handle the level selection like this (got this from Ray Wenderlich iOS Game Development Books)
class func level(levelNum: Int) -> GameScene? {
let scene = GameScene(fileNamed: "Level\(levelNum)")!
scene.currentLevel = levelNum
scene.scaleMode = .AspectFill
return scene
}
But then I get the error as I mentioned and I dont know how to fix this issue :-? Are there any other ways to make a level selection? Currently I have for each level one sks file, which is something I find really handy, since I enables me to lay out the levels visually.
Any recommendations and/or help?
Thanks in advance
I'm trying to translate SKScene * scene = [GameScene sceneWithSize:skView.bounds.size]; into swift but I get the error
'sceneWithSize' is unavailable: use object construction 'SKScene(size:)'.
I am using viewWillLayoutSubviews and cutting out the viewDidLoad() because it does not give correct dimensions for the screen dimensions of the device I choose. It actually makes me question why viewDidLoad() exists at all?
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews();
let skView = self.view as SKView;
if skView.scene != nil {
skView.showsFPS = true;
skView.showsNodeCount = true;
skView.showsPhysics = true;
// Create and configure the scene
let scene:SKScene = GameScene.sceneWithSize(skView.bounds.size); // ERROR MESSAGE!
// Objective-C code in next 2 lines
// SKScene * scene = [GameScene sceneWithSize:skView.bounds.size];
// scene.scaleMode = SKSceneScaleModeAspectFill;
// Present Scene
skView.presentScene(scene)
}
}
Try changing
let scene:SKScene = GameScene.sceneWithSize(skView.bounds.size);
by
let scene:SKScene = GameScene(size: skView.bounds.size);
Hope this helps ;)
As the error says, the function you are trying to use is not available. You should instead use the constructor init(size size: CGSize):
let scene = SKScene(size: skView.bounds.size)
Note also that the :SKScene is not necessary as the type is obvious from the constructor.
If you open the documentation, you will see that +sceneWithSize: is not available for Swift.
When a view's bounds change, the view adjusts the position of its subviews. Your view controller can override this method to make changes before the view lays out its subviews. The default implementation of this method does nothing.
I have some troubles to make the invite accept in swift.
could someone help me with the right coding? Here is mine
GKMatchmaker.sharedMatchmaker().matchForInvite(Invitation!, completionHandler = {(InvitedMatch:GKMatch!, error: NSError!) -> Void in
if InvitedMatch != nil {
myMatch=match
LocalGame=false
if let scene = GameScene.unarchiveFromFile(environment_Prefix!+"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 = .Fill
skView.presentScene(scene, transition: SKTransition.flipVerticalWithDuration(2.0))
}
}
})
Thanks
Finally I have figured out the solution which works. I had to implement the GKLocalPlayerListener like this and call the match for invite within the delegate function.
func player(player: GKPlayer!, didAcceptInvite invite: GKInvite!) {
GKMatchmaker.sharedMatchmaker().matchForInvite (invite, {(InvitedMatch, error) in
if InvitedMatch != nil {
myMatch=InvitedMatch
LocalGame=false
if let scene = GameScene.unarchiveFromFile(environment_Prefix!+"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 = .Fill
skView.presentScene(scene, transition: SKTransition.flipVerticalWithDuration(2.0))
}
}
})
}
To get the player function called I have to register the listener at the local player authenticated block like this:
localPlayer.registerListener(self)
Now game invite works perfectly.