I am trying to integrate iAd with my current sprite kit project. I have scoured existing questions, most of which say adding
self.canDisplayBannerAds = YES;
will get the ads to work. However, every time I try one of the solutions posted, I get this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setShowsFPS:]: unrecognized selector sent to instance 0x14dbcc50'
In the storyboard, I have tried setting the view to SKView. I have added the iAd framework to the project.
Here is my viewWillLayoutSubviews method:
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
if(!skView.scene){
// Create and configure the scene.
SKScene * scene = [Intro sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
self.canDisplayBannerAds = YES;
}
}
how should I solve this problem? Any and all suggestions are appreciated!
EDIT:
Here is a screenshot of my storyboard, with the view selected. I think this is how to change the view's class using storyboard. But I still get the same error.
You are not crashing due to the banner ads. You are crashing on the line
skView.showsFPS = NO;
because self.view is a UIView not a SKView.
Edit:
This appears to be a side effect of using UIViewController's iAD category extension. You can retrieve the SKView using the following:
SKView * skView = (SKView*)self.originalContentView;
Related
I am developing a game and would like to have one sprite-kit scene have its own view controller (a conclusion I've reached after much debate), and would like to avoid using storyboard (I can accomplish what I want with storyboard, but would like to learn how to do it without storyboard).
In my main view controller, after clicking a button, I have the following code
MyViewController2 *test = [[MyViewController2 alloc] init];
test.view = [[SKView alloc] init];
[self presentViewController: test animated:YES completion:nil];
However, this just transitions a grey screen with nothing on it (did not overwrite "-(id)init" yet). The following code gets called if I overwrite the "-(id)init" method in MyViewController2:
-(id)init
{
NSLog(#"init overwrite works");
SKView * skView = (SKView *)self.view;
SKScene2 *scene = [SKScene2 sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeFill;
[skView presentScene:scene];
return self;
}
but it won't display because I get this error:
-[UIView presentScene:]: unrecognized selector sent to instance
I know what this error means (the presentScene can only be executed by skView and can't be executed by UIView), but even though when I create the ViewController and in its init I set views to be only SKView, I still get this error. How can I fix this? Thanks for your time and help.
The view property is managed by the UIViewController and represents the root view. You cannot simply assign your own view at any point.
Option 1
If you wish to replace the view property with your own view you can override UIViewController's loadView method and assign the view there. It is documented in the class reference for this method:
The view controller calls this method when its view property is
requested but is currently nil. This method loads or creates a view and assigns it to the view property
...
You can override this method in order to create your views manually.
If you choose to do so, assign the root view of your view hierarchy to
the view property
So it will look something like this:
- (void)loadView
{
self.view = [[SKView alloc] init];
}
Option 2
You can add your SKView as a subview.
Add a property to your view controller so you can access it when necessary:
#property (strong, nonatomic) SKView *skView;
Initialize and add it as a subview when the view is loaded:
- (void)viewDidLoad
{
[super viewDidLoad];
self.skView = [[SKView alloc] init];
[self.view addSubview:self.skView];
SKScene2 *scene = [SKScene2 sceneWithSize:self.skView.bounds.size];
scene.scaleMode = SKSceneScaleModeFill;
[self.skView presentScene:scene];
}
I am new to the spritekit system. However, I have some questions. I have an app that has a menu screen, instructions page, etc..., none of which recquire me loading a skcene. However, I want to be able to load my "Game" scene on the press of a button. How would I do that regarding code?
FIXED:
I just did not check the IB settings for one of my views: my view type should be SKView.
Create new SKView in your view controller's -viewDidLoad: method
SKView *spriteView = (SKView *) self.view;
Then create new SKScene class in a separate file
#interface GameScene : SKScene
#end
Return to your previous view controller and place this code in your
button's event handler
GameScene* scene = [[GameScene alloc] initWithSize:CGSizeMake(768,1024)];
SKView *spriteView = (SKView *) self.view;
[spriteView presentScene: scene];
More info in Apple's documentation.
When Im finished with my SKScene is there a way to dismiss the SKScene from within my SKScene class?
If not back in my Viewcontroller where I present my SKScene [skView presentScene:theScene]; is there a way to restart the scene or remove in from my SKView?
The SKScene Class Reference and SKView Class Reference are no help.
Update:
The following code removes my scene from my SKView [yourSKView presentScene:nil]; but when Im back in my view controller the scene is still running in the background. I can always pause it when the game is over and I'm sent back to my view controller(menu) but I'm wondering is there another method other then pausing it like completely removing it?
-(void)endTheGame {
[highscoreLabel removeFromSuperview];
NSLog(#"Game Over");
//would like to end here before calling the below method in my view controller
[self.delegate mySceneDidFinish:self];
}
Having met a similar issue I stumbled around your question, and since nobody gave a decent answer here's how I solved it:
in my scene I called both lines
[self removeFromParent];
[self.view presentScene:nil];
in my controller (the controller that displays the SKScene) I changed the template code from Apple, which was creating and presenting my scene from viewDidLoad in order to create and present my scene in viewWillAppear, only if the view's scene is nil
here's my Swift code, even if you're using Objective C you'll understand what it does; the key line being the "if skView.scene == nil" test :
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let skView = self.view as SKView
if skView.scene == nil {
let scene = GameScene(size:skView.bounds.size)
scene.controller = self
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
You can use:
[yourSKView presentScene:nil];
to remove the scene.
"You can't go "Back to the View Controller" from a scene. The scene is a View, the view controller controls and displays views. Use the view controller to change views. Remember the view controller itself is not a view." -Wharbio
Best solution here is to create another View Controller. This view controller will be my menu. Then the other viewcontroller will act as a host for the skscene.
In my situation I then use my menu viewcontroller to dismiss the viewcontroller displaying in the skview.
From within your SKScene, you can simply do [self.view presentScene:aNewScene] to present another scene
I completely remove scenes by using this block in my view controller:
Obviously you will need to declare your Size, and "newSKview"
SKView * skView = (SKView *)self.view;
SKScene *newScene = [[newSKView alloc]initWithSize:size];
newScene.scaleMode = SKSceneScaleModeAspectFill;
SKScene *oldScene=(skView.scene);
[oldScene removeFromParent];
[skView presentScene:newScene];
This works fine for me. None of my Scenes are retained or strong.
I prefer to use an additional UIViewController for SKView and Notification Center in where the UIViewController made SkScene.
The callback function is
#objc func cb_dismissingVC(_ notificaiton: Notification) {
self.dismiss(animated: true, completion: nil)
}
Maybe my variant will be helpful:
[[self.scene childNodeWithName:#"YourChildNodeName"] removeFromParent];
I am working on a SpriteKit project and I'm struggling to pause the game when the iAd is clicked, and unpause when the iAd is dismissed. The main problem is pausing the Scene from the ViewController, I know that if I want to pause the Scene from the Scene.m I should use the code
self.scene.view.paused = YES;
however this code doesn't work in the ViewController.
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
//pause game
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
//unpause game
}
I know that I would like to pause the game in the section above but I'm having trouble finding the resources to know how to perform this. Any help is appreciated, thanks.
If you have an SKView that's presenting a scene, you can call pause from within its ViewController like this:
Objective-C:
SKView *skView = (SKView *)self.view;
skView.scene.paused = YES;
Swift
let skView: SKView = self.view as! SKView
skView.scene.paused = true
I have this code below that loads a scene in the viewDidLoad: method.
SKView *spriteView = (SKView *) self.view;
spriteView.showsDrawCount = YES;
spriteView.showsNodeCount = YES;
spriteView.showsFPS = YES;
PFPiePlanesScene *scene = [PFPiePlanesScene sceneWithSize:self.view.frame.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[spriteView presentScene:scene];
When I call anything on the spriteView, it crashes with this message:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setShowsDrawCount:]: unrecognized selector sent to instance 0x9685030'
I assume this is because it is not treating the instance as a SKView and instead as a UIView.
Thanks in advance.
Some extra:
Sprite kit uses this code to load a scene.
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
// Create and configure the scene.
self.scene = [SKMyScene sceneWithSize:skView.bounds.size];
self.scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:self.scene];
And, with no error. The classes are the exact same. Would just coming into the view screw this up?
Joe
If you are following apple's walk-thougrh you skipped the part : "Open the storyboard for the project. It has a single view controller (SpriteViewController). Select the view controller’s view object and change its class to SKView.
self.view is a UIView object. Simply casting the pointer does not make it a different type of object.
SKView *spriteView = (SKView *) self.view;
spriteView is now pointing to the object, that self.view is pointing to, telling the compiler, that it actually points to an object of type SKView. That's why you don't get any compiler errors or warnings. At runtime you are sending messages that can't be handled by spriteView because it is still just a UIView object.
Don't forget add SpriteKit.framework under Linked Frameworks and Libraries.
Cheers,
Jesse
what you have to do is to change the subclass of view from UIView To SKView select ur viewcontroller under that view and change it subclass
#Sebastian is not correct.
i guess you are following apple's walk-thougrh.
maybe the following tutorial will help:
http://www.raywenderlich.com/49625/sprite-kit-tutorial-space-shooter
Before casting your UIView to SKView , you must make sure to set your custom class as SKView in your storyboard.
If you notice the first view controller comes with these imports in the header file.
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
When you create a new view controller, by default Spritekit is not included. After adding sprite kit it should work with the default code apple provides