How to present UIAlertController from SKScene
Asked Answered
R

3

2

I'm working in Spritekit and I'm trying to present a UIAlertController from my SKScene, but I am having trouble doing it. I've watched several tutorials but none of the UIAlertController tutorials have been specific to Spritekit. I keep seeing this code below, but it has not been effective since SKScene is not a UIViewController.

[self presentViewController:self animated:YES completion:nil];      

I have the rest of the relative code below. Can anybody please help me present my UIAlerController on my SKScene.

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"You Lose!" message:@"Do You Want To Beat This Level?" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *CancelButton = [UIAlertAction actionWithTitle:@"GiveUp" style:UIAlertControllerStyleAlert handler:<#^(UIAlertAction *action)handler#>]
Renettarenew answered 1/7, 2015 at 4:36 Comment(0)
P
1

The SKScene instance can't invoke presentViewController(_:animated:completion) because it is not a subclass of UIViewController. However, if you rewrite as such, your alert will launch:

self.view?.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)

ps: there will be a warning though that Attempt to present <UIAlertController: 0x7fc31eb32e50> on <Sample_Game.GameViewController: 0x7fc31bd9b4f0> which is already presenting. If anyone knows how to eradicate this warning, that will be great.


[Updated 11 August 2016]

To eradicate the aforementioned warning, check if the rootViewController has presented a view controller:

 let vc = self.view?.window?.rootViewController
 if vc.presentedViewController == nil {
    vc.presentViewController(alert, animated: true, completion: nil)
 }
Pinhead answered 17/8, 2015 at 4:39 Comment(0)
R
3

SKScene shouldn't be the one presenting the UIAlertController, but rather a UIViewController such as your initial GameViewController. Above code works fine when called from a UIViewController.

You could use NSNotificationCenter to help you call your view controller.

Add this to your view controller's viewDidLoad method,

[[NSNotificationCenter defaultCenter] addObserver:self                                          
                                         selector:@selector(playerLost:) 
                                             name:@"PlayerLostNotification" 
                                           object:nil];   

and you will need to define this method too.

- (void)playerLost:(NSNotification*) notification {
   UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"You Lose!" 
                                         message:@"Do You Want To Beat This Level?" 
                                  preferredStyle:UIAlertControllerStyleAlert];

   UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"GiveUp"
                         style:UIAlertActionStyleDefault
                       handler:^(UIAlertAction * action) {
                          [alert dismissViewControllerAnimated:YES completion:nil];
                       }];
   [alert addAction:cancel];
   [self presentViewController:alert animated:YES completion:nil];
}                             

In your SKScene when the player loses,

[[NSNotificationCenter defaultCenter] postNotificationName:@"PlayerLostNotification" object:self];
Rattletrap answered 1/7, 2015 at 8:6 Comment(3)
But in the context of my game, when the player loses, I use the UIAlertController to give the user the option to play the level again or give up and go to the menu (I was using UIAlertView previously). How can I perform that from the SKScene?Renettarenew
Right on. Essentially you would need to relay a message back to the view controller. You could keep a reference to the view controller in SKScene, make a delegate, or use NSNotificationCenter. Essentially you want to call the view controller when it is time to show the alert.Rattletrap
Would you mind writing an example in code of how I would do this?Renettarenew
P
1

The SKScene instance can't invoke presentViewController(_:animated:completion) because it is not a subclass of UIViewController. However, if you rewrite as such, your alert will launch:

self.view?.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)

ps: there will be a warning though that Attempt to present <UIAlertController: 0x7fc31eb32e50> on <Sample_Game.GameViewController: 0x7fc31bd9b4f0> which is already presenting. If anyone knows how to eradicate this warning, that will be great.


[Updated 11 August 2016]

To eradicate the aforementioned warning, check if the rootViewController has presented a view controller:

 let vc = self.view?.window?.rootViewController
 if vc.presentedViewController == nil {
    vc.presentViewController(alert, animated: true, completion: nil)
 }
Pinhead answered 17/8, 2015 at 4:39 Comment(0)
M
0

Just set a pointer to your viewController when you create your scene. Then you can call it like this: [self.viewController presentViewController:alert animated:YES completion:nil];

In your ViewController:

// Create and configure the scene.
GameScene *scene = [GameScene sceneWithSize:viewSize];
SKView * skView = (SKView *)self.view;
scene.viewController = self;

// Present the scene.
[skView presentScene:scene];
Mottled answered 15/3, 2016 at 18:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.