Trouble with SKScenes and Segueing to ViewControllers SpriteKit - sprite-kit

In my GameViewController i have two scenes, one being the GameScene and another being a scene (EndScene) that is switched to when the player dies. In the first block of code below is my EndScene Scene that is supposed to switch to my main menu viewcontroller, however it wont for some reason. I'm not getting any errors or likewise, it just stays on EndScene. In the second block of code is my GameViewController.swift file. Can someone help point out what im doing wrong here and what i can do to fix it?
EndScene.swift
import SpriteKit
class EndScene : SKScene {
var viewController : UIViewController?
override func didMoveToView(view: SKView) {
self.segue()
}
func segue() {
self.viewController?.performSegueWithIdentifier("gameToMain", sender: viewController)
}
}
GameViewController.swift
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
scene.viewController = self
skView.presentScene(scene)
}
if let scene = EndScene(fileNamed: "EndScene"){
// 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
scene.viewController = self
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
}
}

try
let newScene: GameScene = GameScene(size: size)
let transition = SKTransition.fadeWithColor(SKColor.blackColor(), duration: 0.5)
view?.presentScene(newScene, transition: transition)
There is other transitions you can use, but try this code and see if it will switch your scenes

Related

Could not cast value of type 'Pong.MenuVC' (0x1072ea808) to 'Pong.GameViewController'

I have built an app using Xcode and swift 5.
Every time I click the "Easy", "Medium", "Hard" or "2 Player" button I get an error:
Could not cast value of type 'Pong.MenuVC' (0x1072ea808) to
'Pong.GameViewController'
Does anyone know how to fix it?
Thank you for your help.
Code of MenuVC:
enum gameType {
case easy
case medium
case hard
case player2
}
class MenuVC : UIViewController {
#IBAction func Player2(_ sender: Any) {
moveToGame(game: .player2)
}
#IBAction func Easy(_ sender: Any) {
moveToGame(game: .easy)
}
#IBAction func Medium(_ sender: Any) {
moveToGame(game: .medium)
}
#IBAction func Hard(_ sender: Any) {
moveToGame(game: .hard)
}
```
**Code with Thread 1: signal SIGABRT:**
```swift
func moveToGame(game : gameType) {
let gameVC = self.storyboard?.instantiateViewController(withIdentifier: "gameVC") as! GameViewController
currentGameType = game
self.navigationController?.pushViewController(gameVC, animated: true)
}
}
Code of GameViewController:
import UIKit
import SpriteKit
import GameplayKit
var currentGameType = gameType.medium
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: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
// 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
}
}
In your storyboard the id gameVC is of type MenuVC not GameViewController so change class name of the vc
let gameVC = self.storyboard?.instantiateViewController(withIdentifier: "gameVC") as! GameViewController

SpriteKit - SpriteNode never shows

I am attempting to learn SpriteKit. I want to add a rectangle/square to the scene in code; but the item never shows;
All I want to do is add a white square to the screen, but find that it never adds.
In a breakpoint, I notice that didMove() never seems to get called.
What am I doing wrong?
class GameScene: SKScene {
override func didMove(to view: SKView) {
let item = SKSpriteNode(color: .white, size: CGSize(width: 150, height: 200))
item.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
self.addChild(item)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
update
I did not change the view controller generated by xcode
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: "GameScene") {
// 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
}
}
There is no GameScene.sks, I deleted this file as I do not want to use sks files
If a breakpoint in didMove(to view:) is never reached, then definitely your ViewController doesn't present the scene for some reason. Can you open your ViewController's file (e.g. GameViewController.swift) and see if you have any of those lines there (or anything to that effect):
let viewSize = UIScreen.main.bounds.size
let scene = GameScene(size: viewSize)
let skView = self.view as! SKView
skView.presentScene(scene)
Turns out view controller was not presenting the scene and changing it to this, following code posted by #Stoyan worked and I saw my sprite showing
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
let viewSize = UIScreen.main.bounds.size
let scene = GameScene(size: viewSize)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
view.presentScene(scene)
}

iAd banner ad is not working because of the following error (Sprite Kit)

I am using sprite kit and I want the banner ad to display on all of my skscenes. I do not want to use self.candisplaybannerads because it pushes my scene up mid game and causes it to lead to a death in the game.
Here is the error: WARNING: More than 10 instances of ADBannerView or ADInterstitialView currently exist. This is a misuse of the iAd API, and ad performance will suffer as a result. This message is printed only once.
Here is my code:
import UIKit
import iAd
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, ADBannerViewDelegate {
var window: UIWindow?
var AdBanner = ADBannerView()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
// Override point for customization after application launch.
UIViewController.prepareInterstitialAds()
/* Ad Banner Settings */
AdBanner = ADBannerView()
AdBanner.frame = CGRectZero
AdBanner.delegate = self
AdBanner.backgroundColor = UIColor.clearColor()
/* All iAd Functions */
func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
/* whatever you need */
return true
}
func bannerViewActionDidFinish(banner: ADBannerView!) {
/* whatever you need */
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
AdBanner.hidden = false
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
NSLog("Error Loading Ad")
/* whatever you need */
AdBanner.hidden = true
}
func bannerViewWillLoadAd(banner: ADBannerView!) {
/* whatever you need */
}
return true
}
Here is where I am calling the banner ad
class GameViewController: UIViewController {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
override func viewDidLoad() {
super.viewDidLoad()
appDelegate.AdBanner.frame = CGRectMake(0, self.view.frame.size.height-appDelegate.AdBanner.frame.size.height, appDelegate.AdBanner.frame.size.width, appDelegate.AdBanner.frame.size.height)
self.view .addSubview(appDelegate.AdBanner)
//authenticateLocalPlayer()
if let scene = StartScreen(fileNamed:"StartScreen") {
// 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)
}
}
I had the same issue and solved it by using the automatic mode for banner ads. Just set 'canDisplayBannerAds' in your ViewController and Apple takes care about the number of instances:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.canDisplayBannerAds = true
...

Why is my app throwing EXC_BAD_ACCESS the second time I try to segue without a stacktrace?

I am trying to segue from a root view controller -> game view controller, then display a skscene of gameplay on gameviewcontroller, then go to a different skscene ( a game over scene), then unwindsegue to the root view controller, and then repeat. The problem is, when I try seguing to the game view controller the second time around, it throws exc_bad_access after the game view controller attempts to present the skscene (gameplay). There is no stacktrace, just an exc_bad_access on the first line of the appdelegate. When I run instruments w/ zombies the app does not throw any error, it works as intended. Putting an exception breakpoint does not seems to do anything. I'm not sure where or what my error is.
this is my root view controller:
class RootViewController: UIViewController {
//view that we present
#IBOutlet weak var MyLabel: UILabel?
var preload = true
override func viewDidLoad() {
super.viewDidLoad()
if preload {
textures.atlas.preloadWithCompletionHandler( {
print("finished preloading")
})
}
}
var lives: Int = 3
#IBOutlet weak var MyStepper: UIStepper!
#IBAction func didChangeValue(sender: UIStepper) {
lives = Int(sender.value)
MyLabel?.text = "lives: \(Int(sender.value).description)"
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
originalLives = lives
enemyLives = lives
heroLives = lives
print("seguing")
}
#IBAction func goBack(unwindSegue: UIStoryboardSegue) {
preload = false
}
}
//Controls a /view/ that displays scenes.
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//initialize the scene to fill screen
let myScene = GameScene(size: self.view.bounds.size)
myScene.scaleMode = .AspectFill
let theskView = self.view as! SKView
self.view.multipleTouchEnabled = true
// theskView.frameInterval = 2
//
// theskView.showsPhysics = true
// theskView.showsFPS = true
// theskView.showsNodeCount = true
// theskView.showsDrawCount = true
theskView.ignoresSiblingOrder = true
myScene.scaleMode = .AspectFill
myScene.size = theskView.bounds.size
myScene.controller = self
theskView.presentScene(myScene)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let dvc = segue.destinationViewController as? RootViewController {
}
}
deinit {
print("game view dies")
}
}
the scenes are straightforward: this is called (from the first skscene) to go to the game over scene
func gameOver(won: String) {
self.removeAllChildren()
let sceneToGoTo = GameOverScene()
sceneToGoTo.won = won == "nudgit" ? true : false
let theskView = self.view! as SKView
theskView.multipleTouchEnabled = true
// theskView.frameInterval = 2
theskView.ignoresSiblingOrder = true
sceneToGoTo.scaleMode = .AspectFill
sceneToGoTo.size = theskView.bounds.size
sceneToGoTo.controller = controller
theskView.presentScene(nil)
theskView.presentScene(sceneToGoTo)
}
and then the gameover scene segues from a touch:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
controller?.performSegueWithIdentifier("segue", sender: self)
}
where "controller?" is a weak var of the game view controller
I have checked deinits: both game scenes are deinitializing correctly, and the gameViewController is correctly deinitializing when it unwinds to the root view controller. I am at a lost as to what I could do to fix this.

iAds banner jerking/changing size of scene, every time iAd banner is loaded.

Im having troubles with implementing iAds into game without the iAds banner changing the scene e.g. jerking the screen, Every time the ad is loaded. Please help with a solution to stop this from happining.
class GameViewController: UIViewController,ADBannerViewDelegate{
#IBOutlet var adBannerView: ADBannerView? //connect in IB connection inspector with your ADBannerView
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
var defaultsV = NSUserDefaults.standardUserDefaults();
defaultsV.setInteger(0, forKey: "gameOverCount")
defaultsV.setBool(false, forKey: "firstSessionEnded")
defaultsV.synchronize()
//self.adBannerView!.frame = CGRectMake(0, self.view.frame.size.height-self.adBannerView!.frame.size.height, self.adBannerView!.frame.size.width, self.adBannerView!.frame.size.height)
self.adBannerView!.delegate = self
self.adBannerView!.hidden = true //hide until ad loaded
self.canDisplayBannerAds = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
self.adBannerView?.sizeToFit()
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
func bannerViewWillLoadAd(banner: ADBannerView!) {
NSLog("bannerViewWillLoadAd")
//self.canDisplayBannerAds = true
self.adBannerView!.hidden = true //hide until ad loaded
self.adBannerView!.frame = CGRectMake(0, self.view.frame.size.height-self.adBannerView!.frame.size.height, self.adBannerView!.frame.size.width, self.adBannerView!.frame.size.height)
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
NSLog("bannerViewDidLoadAd")
self.adBannerView!.frame = CGRectMake(0, self.view.frame.size.height-self.adBannerView!.frame.size.height, self.adBannerView!.frame.size.width, self.adBannerView!.frame.size.height)
self.adBannerView!.hidden = false //now show banner as ad is loaded
//self.canDisplayBannerAds = true
}
func bannerViewActionDidFinish(banner: ADBannerView!) {
NSLog("bannerViewDidLoadAd")
//optional resume paused game code
}
func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
NSLog("bannerViewActionShouldBegin")
//optional pause game code
return true
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
NSLog("bannerView")
self.adBannerView!.hidden = true
}
You suggest you should always set canDisplayBannerAds to false as this allows the viewController to resize the view when an ad is shown. If you need create another Bool value to determine the state of your ads.
//ViewControlller.m
self.canDisplayBannerAds = false
use the method for iads banner:
override func viewWillAppear(animated: Bool) {
// View is about to be obscured by an advert.
// Pause activities if necessary
}
override func viewWillDisappear(animated: Bool) {
// Advert has been dismissed. Resume paused activities
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError
error: NSError!) {
banner.removeFromSuperview()
self.view.layoutIfNeeded()
}
override func viewDidLoad() {
super.viewDidLoad()
self.canDisplayBannerAds = true
rectangleAdView = ADBannerView(adType: ADAdType.MediumRectangle)
rectangleAdView?.delegate = self
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
self.view.addSubview(banner)
self.view.layoutIfNeeded()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
banner.removeFromSuperview()
self.view.layoutIfNeeded()
}
http://www.techotopia.com/index.php/Integrating_iAds_into_an_iOS_8_App_using_Swift