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];
Related
I have a SKScene object setup in GameViewController. I implemented dealloc into the SKScene subclass as follow:
- (void)dealloc {
NSLog(#"Dealloc: %#", self);
}
Now I want to present another view controller on top of GameViewController. I used storyboard segue to do this. But after the new view controller is presented, I never received the SKScene dealloc. It got stuck in the memory. My app starts to freeze after a few minute due to low memory. How can I dealloc the scene after presenting the new view controller.
In order to deallocate you SKScene instance -> you Should Eliminate every pointer that retains it -> then ARC will automagically release it.
Simply call the [skView presentScene:nil]; method which also will remove the SCScene and deallocate it by setting SKView.scene property to nil.
SKView *skView = (SKView *)self.view;
GameScene *scene = (GameScene *)skView.scene;
for(SKNode * child in scene.children)
{
[child removeAllActions];
}
[scene removeAllChildren];
[scene removeAllActions];
[skView presentScene:nil];
Note Normally you don't have to remove everything from the SKScene if your memory is managed right just call [skView presentScene:nil]; method and ARC will take care of it.
Apparently you had something inside the SKScene that retained it.
So by removing everything from it, we eliminated the retain cycle.
This solution will not always work, it will work only if one of the SKActions or SKNodes are retaining the SKScene which were the issue in your case, However your SKScene could be retained from somewhere else and this answer wouldn't really help you
This the code block I'm having trouble with.It gives me error because of 'presentViewController'
func authenticateLocalPlayer(){
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
I know it's because SKScene has already has a UIViewController, but I don't know how else to represent it.
There is simple way to deal with it within the scene. Try it and let us know. I don't disagree with answer above completely, but they should have guided you better and given the right answer. Yes You have to call presentViewController on a UIViewController. Since your SKScene is using SKView which is subclass of View but not UIView at all, so calling presentViewController from self means you are asking SKView object to present a UIViewController which SKView cannot. But here is a simple solution, as SKView is subclass of UIView itself, so ask SKView's root view controller to do this for you like this.
Your call will be like this (I am writing it in objective C as I do not code in swift but same is true for both languages)
[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];
As you see instead of asking 'self', you have to ask 'self.view.window.rootViewController'. And you can do it right inside your scene. There you go.
You can't call presentViewController from within your SKScene, you need to call it on a UIViewController.
Therefore you want to find the parent view controller that contains your Sprite Kit content and call the function there.
Hello I have code set up that should correctly segue from GameScene to another view controller, mainMenuViewController. The code I have set up to achieve this is
var viewController: GameViewController!
func segue() {
viewController.dismissViewControllerAnimated(true, completion: nil)
SettingsViewController.delete(self)
}
In GameViewController
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
let scene = GameScene(size: skView.bounds.size)
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = false
//skView.showsPhysics = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
scene.viewController = self
}
}
which is called when a SKLabelNode is tapped. I received advice to use this since the mainMenu is the scene that is first loaded when the player starts the game and they segue to gameScene so I was told to dismiss GameScene instead of creating a new segue every time. I get the error 'fatal error: unexpectedly found nil while unwrapping an Optional value' and a crash whenever the button is tapped. I assume it is talking about the viewController. Thank you for your help!
If understand correctly your problem, you are trying to dismiss GameViewController. But method dismissViewControllerAnimated only dismisses controller that you are currently presenting. So as your game view controller is not presenting anything it can't dismiss it. As you say from code to GameViewController dismiss controller that was presented by him, it tries to do as you want so he gets his property of presented view controller and try to dismiss it, but that property is nil so such error gets. To fix this problem you should call viewController.presentingViewController.dismissViewControllerAnimated(true, completion: nil) .
Property presentingViewController returns controller that presents you, in your case controller that present GameViewController. As you get this controller you can dismiss controller that was presented by him(in you case presented controller is your GameViewController). So logic is to get as to say "parent" controller that has permissions to dismiss yourself(GameViewController)
I need to look to your code. It seams now that you try to call method delete to view controller, but as I know view controller doesn't have such. So think that is other bug in your program, and mainly you are setting Noble_Ninja.SettingsViewController to other object that expect to have such method. That is my prediction I can't say anything clearly because i only has exception description. Try to find where you calling this method in your code , than put brakepoints there and when program stops on your brakepoint write in your console(log) - (po NAME_OF_INSTANCE_THAT_CALLS_SUCH_METHOD) -, it will show real instance type, so with this info you can detect where is real problem. Good luck
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.
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