I can't find anything about this when searching around so I decided to ask.
For some reason when I try to create a GameScene and try to scale it to the iPad according the suggestions around here. I get black borders around my view like so:
Here is my code:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
skView.multipleTouchEnabled = false;
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .ResizeFill
scene.backgroundColor = UIColor.whiteColor()
print(scene.frame.size)
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
return .Landscape
} else {
return .AllButUpsideDown
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
and this:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let testLabel = SKLabelNode(text: "Hello World!")
testLabel.position = CGPoint(x: size.width/2, y: size.height/2)
testLabel.fontColor = UIColor.blueColor()
addChild(testLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
How can I get rid of the black borders around my view?
First set in your project targets in the deployment info section Devices to universal (I think you set it up with iPhone) see screenshot:
Then set scene.scaleMode = .ResizeFill to scene.scaleMode = .AspectFill and after that run your app and see the result with no black borders:
Related
How do I show an interstitial ad from admob every x times the user has died or every x times the user does something like presses a button? This is how I showed an interstitial ad on my GameScene and limited ad impressions with a simple if statement.
This will only work if you have the GoogleMobileAds.sdk and have imported the googlemobileads module into your GameViewController, and GameScene, OR GameOverScene.
I'll be showing you cross-scene ad implementation and programmatically limiting ad impressions.
First, in your GameViewController:
import GoogleMobileAds
class GameViewController: UIViewController, GADInterstitialDelegate {
var myAd = GADInterstitial()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.loadAndShow), name: "loadAndShow", object: nil)
}
Create two functions at the bottom of your GameViewController:
func loadAndShow() {
myAd = GADInterstitial()
let request = GADRequest()
myAd.setAdUnitID("ca-app-pub-3940256099942544/4411468910")
myAd.delegate = self
myAd.loadRequest(request)
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (self.myAd.isReady) {
myAd.presentFromRootViewController(self)
}
}
You are done with GameViewController. Now head to GameOverScene or GameScene, whatever you need.
Create a global int variable:
var playCount = Int()
In your DidMoveToView say:
playCount = 1
This part is sort of confusing, kinda, not really. Go to your touchesBegan and find where you add actions to a button if it's pressed. For example, a resetGame button resets the scene. Add this there and increment the playButton Int like so:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let location = touch.locationInNode(self)
if resetGame.containsPoint(location) {
restartScene()
playCount += 1
}
Last step. Add these two functions to the bottom of the scene you want to show interstitial ads in:
func displayAd() {
NSNotificationCenter.defaultCenter().postNotificationName("loadAndShow", object: nil)
}
func checkAd() {
if playCount % 4 == 0 {
displayAd()
}
}
}
Now every fourth time that the user presses the reset game button or dies, an interstitial ad should show up. I hope this helps.
EDIT: I forgot to tell you to call the checkAd() function. Call this function wherever your players dies. So if you have a Bool variable called died or gameover call it in the same spot. For example..
if died == true {
checkAd()
}
import UIKit
import SpriteKit
import GoogleMobileAds
var playCount = Int()
class GameViewController: UIViewController, GADBannerViewDelegate {
#IBOutlet var banner: GADBannerView!
var myAd = GADInterstitial()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.loadAndShow), name: "loadAndShow", object: nil)
let scene = MainScene(size: CGSize(width: 1536, height: 2048))
// 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
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
banner.hidden = true
banner.delegate = self
banner.adUnitID = "ca-app-pub-8889875503423788/7902691359"
banner.rootViewController = self
banner.loadRequest(GADRequest())
}
func loadAndShow() {
myAd = GADInterstitial()
let request = GADRequest()
myAd.setAdUnitID("ca-app-pub-8889875503423788/7902691359")
myAd.delegate = self
myAd.loadRequest(request)
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (self.myAd.isReady) {
myAd.presentFromRootViewController(self)
}
}
func adViewDidReceiveAd(bannerView: GADBannerView!) {
banner.hidden = false
}
func adView(bannerView: GADBannerView!, didFailToReceiveAdWithError error: GADRequestError!) {
banner.hidden = true
}
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
}
}
Explanation
My question is pretty straight forward: how do I print a variable from GameScene on GameViewController?
Code
I created this code below so it's easier to get the idea.
GameScene.swift
import SpriteKit
class GameScene: SKScene {
var variable = Int()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
variable = 50
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
NSNotificationCenter.defaultCenter().postNotificationName("calledFromGameSceneVC", object: nil)
}
}
GameViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Set view size.
let scene = GameScene(size: view.bounds.size)
// Configure the view.
let skView = 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 = .ResizeFill
skView.presentScene(scene)
//------------------------------//
//Register observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.calledFromGameScene), name: "calledFromGameSceneVC", object: nil)
}
func calledFromGameScene(){
//Print variable
let scene = GameScene(size: view.bounds.size)
print("My variable from GameScene is: ", scene.variable)
}
}
Sorry for the brief explanation.
Thanks in advance,
Luiz.
The type of inter-object communication you are trying to achieve is probably best addressed through a delegation pattern using a protocol:
GameScene.swift
import SpriteKit
protocol GameSceneDelegate {
func calledFromGameScene(scene: GameScene)
}
class GameScene: SKScene {
var variable = Int()
var gameDelegate: GameSceneDelegate?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
variable = 50
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
gameDelegate?.calledFromGameScene(self)
}
}
GameViewController.swift
class GameViewController: UIViewController, GameSceneDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Set view size.
let scene = GameScene(size: view.bounds.size)
// Configure the view.
let skView = 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 = .ResizeFill
/* Set the delegate */
scene.gameDelegate = self
skView.presentScene(scene)
}
func calledFromGameScene(scene:GameScene){
//Print variable
print("My variable from GameScene is: ", scene.variable)
}
}
Note that you can't use the property name delegate on your GameScene as SKScene already has a delegate property
I currently have a bug with the app I am working on where when a user taps on an iAd banner and the ad loads, the game resets. By "resets" I mean all their progression (other than the NSUserDefaults data) is reset to 0 and the scene is reset back to the start of the game.
My game primary runs from didMoveToView() and touchesBegan(). In my GameViewController the game scene is built from viewWillLayoutSubviews().
Here is how I control my ads and placement. Not sure if has to do with the placement of my code or the ad.
import UIKit
import SpriteKit
import iAd
// Global Ad Variable
var adBanner: ADBannerView!
class GameViewController: UIViewController, ADBannerViewDelegate {
/* Load Ads */
func loadAds() {
adBanner = ADBannerView(frame: CGRect(x: 0, y: view.bounds.size.height - 50, width: 320, height: 50))
adBanner.delegate = self
adBanner.hidden = true
self.view.addSubview(adBanner)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
// Create and Configure the scene
scene.size = skView.bounds.size
skView.showsFPS = false // SHOW OR HIDE FRAMES PER SECOND
skView.showsNodeCount = false
/* 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 awakeFromNib() {
super.awakeFromNib()
loadAds()
}
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
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
adBanner.hidden = true
print("There was an error loading ad")
}
func bannerViewWillLoadAd(banner: ADBannerView!) {
print("Ad Loading")
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
adBanner.hidden = false
print("Ad Loaded")
}
}
I have an SKSpriteNode that functions properly. But when I add a UIImage, the SKSpriteNode becomes hidden behind the UIImage. I have been trying to figure out why, but I am having a little bit of trouble and can't seem to figure out what I am missing to allow the SKSSpriteNode to appear on top of the UI background Image, instead of behind it where it can't be seen. Any help would be greatly appreciated!
import UIKit
import SpriteKit
class GameViewController: UIViewController {
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
}
}
import SpriteKit
import SceneKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var blueBall:SKSpriteNode!
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
self.physicsWorld.contactDelegate = self
blueBall = SKSpriteNode( imageNamed: "ball")
blueBall.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
blueBall.physicsBody = SKPhysicsBody(circleOfRadius: blueBall.size.width / 1.5 )
blueBall.physicsBody!.dynamic = true
blueBall.physicsBody!.allowsRotation = false
self.addChild(blueBall)
}
override func touchesBegan(touches: Set<UITouch> , withEvent event: UIEvent?) {
self.blueBall.physicsBody?.velocity = CGVectorMake(35, 0)
self.blueBall.physicsBody?.applyImpulse(CGVectorMake(4, 10))
}
}
For draw order use the zPosition property:
In your case you will need to give the Sprite you want to be displayed in front a higher .zPosition value than the one to be displayed further back.
Example: ball.zPosition = 10
zPosition definition:
The height of the node relative to its parent.
Tipps:
The default value is 0.0. The positive z axis is projected toward the viewer so that nodes with larger z values are closer to the viewer.
This question has been asked before but I've never found the answer I was looking for.
The story goes like this: I wanted to make a universal game, I had the scene size in the level editor set to the largest size, 2048x1536.
Everything was going fine, until I implemented iAd which started to give me problems with the scene and the way it resized itself to fit on all the devices. When I opened the ad on a device which wasn't 2048 pixels wide the ad stretched the scene and other strange behaviour.
So now I want to make an iPhone version and an iPad version of my game and my question is: which size do I set the scene in the level editor? Do I set it to be the one of the biggest device? or the smallest?
And how do I position the sprites in the scene?
If it can be useful, mine is not a tile based game, I don't have a 'world' or a camera, what's on the scene is what you see in the game.
This is my GameViewController:
class GameViewController: UIViewController, ADBannerViewDelegate {
var adBannerView: ADBannerView!
func loadAds() {
adBannerView = ADBannerView(frame: view.frame)
adBannerView.delegate = self
adBannerView.hidden = true
view.addSubview(adBannerView)
}
override func viewDidLoad() {
super.viewDidLoad()
if let scene = MainMenuScene.unarchiveFromFile("MainMenuScene") as? MainMenuScene {
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = false
skView.showsDrawCount = false
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
loadAds()
}
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return [UIInterfaceOrientationMask.LandscapeLeft, UIInterfaceOrientationMask.LandscapeRight]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func bannerViewWillLoadAd(banner: ADBannerView!) {
print("Ad about to load")
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
adBannerView.hidden = false
print("Displaying the Ad")
}
func bannerViewActionDidFinish(banner: ADBannerView!) {
print("Close the Ad")
}
func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
print("Leave the application to the Ad")
return true
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
adBannerView.hidden = true
print("Ad is not available")
}
}
For the ad I've tried all of the scaleModes and the one who makes the ad work right (not perfectly though) both on iPhone and iPad is .Fill but then my sprites are resized in a way I don't like. And I'm using the Scene Editor so changing the images or the positions of the sprites in code doesn't seem like the most efficient way.
Depending on how you set up object constraints, you could possibly try setting the
SKSceneScaleMode
To
.ResizeFill
Then adding the following variables
var screenSize = UIScreen.mainscreen().bounds
var screenWidth = screenSize.width
var screenHeight = screenSize.height
And when adding your nodes and other objects position and size them based on screenWidth and screenSize