how to present a uiviewcontroller over a spritekit scene - ios

Hi I have seen many questions about this topic but none seem to solve my situation. I want to present a UIView controller over an SKScene when the user win/dies. I created a PresentWinLoseViewController : UIViewController subclass and connected it in story board. I created a segue from GameViewController to PresentWinLoseViewController in storyboard plus two exit segues from PresentWinLoseViewController back to GameViewController.
Here is how I am calling these. In my SKScene when I win/lose
func win() {
let gameVC = GameViewController()
gameVC.performSegueWithIdentifier("tryAgain", sender: self)
}
and my exit segues from PresentWinLoseViewController
#IBAction func tryAgainButtonPressed(segue:UIStoryboardSegue) {
self.performSegueWithIdentifier("unwindTryAgain", sender: self)
}
but I cant even get that far bc the first segue never works. I keep getting
Receiver (<SpriteLevelBuilder.GameViewController: 0x7ff2b5e49210>) has no segue with identifier 'tryAgain''
what am i doing wrong?

For starters, GameViewController should already be initialized, there is no need to let gameVC = GameViewController()
This is because your SKScene is actually presented by your GameViewController. Go look in your GameViewController and you should see the initialization process of SKScene in the viewDidLoad().
Since the GameViewController is already initialized, all you need to do is directly call performSegueWithIdentifier on the GameViewController from your SKScene.
I just did a quick search and this answer seems to apply to your situation: How to call method from ViewController in GameScene

I would do this by placing the elements that you would like to come on over top your scene in the same view controller just on a level above the one with your scene. Using a UIImage View is a great way to make the background for the new elements. Then just create a function for showing the elements and one for hiding them. For all UI elements .hidden = true would be the way to hide the elements and .hidden = false would be the way to show the elements. Here is an example of some code in one of my apps.
//this is the function that hides the settings menu
func hideSettingsMenu() {
settingsCoverImage.hidden = true
settingsTitle.hidden = true
watchButton.hidden = true
fitBitButton.hidden = true
backButton.hidden = true
classesButton.hidden = true
settingsTopBackground.hidden = true
}
//this is the function that shows the settings menu
func showSettingsMenu() {
settingsCoverImage.hidden = false
settingsTitle.hidden = false
watchButton.hidden = false
fitBitButton.hidden = false
backButton.hidden = false
classesButton.hidden = false
settingsTopBackground.hidden = false
}
By calling those functions It simply shows or hides the elements for that page. I am currently working on animating the transitions between pages. Doing it this was also gives you the option to add transparency, giving your app good looks ;)

Related

TableView and Collection view Layout in same view controller

I have two UIViewControllers, When I click on a button of first UIViewController then tableView(Of Second UIViewController) should open, and when I click on another button of First UIViewController then Collection view(Of Second UIViewController) should open.
I mean When Table View will open Collection view will be hidden and Vice versa, both I want in a single View controller.
In image you can see that TableView open with images, but when I will click on first cell the collection view should open in same layout.I mean it has to show like this.
I am new in UI.
So How can I implement the UI.
Thanks.
Thanks for asking question.
I am assuming you are doing in this way:
First put a global Bool Variable called: flagIsShowTableView
Now on your FirstViewController when you click on buttonTable for table:
you have to set Bool: flagIsShowTableView = true
Now when you click on buttonCollection:
you have to set Bool: flagIsShowTableView = false
Now on SecondViewController:
in ViewWillAppear: you have to manage in this way:
if(flagIsShowTableView) {
tblView.hidden = false
colView.hidden = true
} else {
colView.hidden = false
tblView.hidden = true
}
I am sure that you have set and manage all the delegate and datasources methods.

Swift: How to handle view controllers for my game

i have a general question about view controllers and how to handle them in a clean way when i develop a SpriteKit based game.
What i did so far:
Use storyboard only for defining view controllers
SKScene's are presented in each view controller (Home, LevelSelection, Game) by presentScene
in each view controller i call performSegueWithIdentifier with the identifier i defined in the storyboard between the view controllers
all the content i show programmatically using SKSpritenode etc. on the SKScene's
on the storyboard i only have view controllers with segue relations and identifiers defined
all the stuff i do in viewDidDisappear is because it seems to be the only way to get my SKScene deinited correctly
My problems are:
everytime i segue to another view, my memory raises, because the view controller is re-initialized, the old one keeps staying in the stack
it is not clear for me how to handle the segue's between the view controllers, on some tutorial pages i see people using the navigation controller, others are using strong references of some view controllers and using the singleton pattern for the view controller in order to decide either to init the view controller or just show it
my view controllers are not deiniting, i understand my home view can't because it is the initial one, but since ios is reiniting it anyways, why then not unloading it?
What is the correct way for a Swift based game using SpriteKit to handle the view controller? Below you can see my initial view controller (Home) showing an SKScene with a simple play button which calls the play() function to segue to the levelselection
import UIKit
import SpriteKit
class Home : UIViewController {
private var scene : HomeScene!
override func viewDidLoad() {
print(self)
super.viewDidLoad()
self.scene = HomeScene(size: view.bounds.size)
self.scene.scaleMode = .ResizeFill
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(play), name: Constants.Events.Home.play, object: nil)
skView.presentScene(self.scene)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
let v = view as! SKView
self.scene.dispose()
v.presentScene(nil)
NSNotificationCenter.defaultCenter().removeObserver(self)
self.scene = nil
self.view = nil
print("home did disappear")
}
func play() {
self.performSegueWithIdentifier("home_to_levelselection", sender: nil)
}
deinit {
print("Home_VC deinit")
}
}
Your way seems very complicated to essentially present 3 scenes. Its not what you are supposed to do for SpriteKit games, you only really need 1 view controller (GameViewController).
Load your first scene from GameViewController (e.g HomeScene) and nothing else.
Create your playButton and other UI directly in HomeScene. Use SpriteKit APIs for your UI (SKLabelNodes, SKNodes, SKSpriteNodes etc).
You should never really use UIKit (UIButtons, UILabels) in SpriteKit. There are some exceptions to this, like maybe using UICollectionViews for massive level select menus, but basic UI should be done with SpriteKit APIs.
There is plenty tutorials to google on how to create sprite kit buttons, how to use SKLabelNodes etc. Xcode has a SpriteKit level editor so you can do all that visually similar to storyboards.
Than from HomeScene transition to the LevelSelect Scene and than to the GameScene and vice versa. Its super easy to do.
/// Home Scene
class HomeScene: SKScene {
...
func loadLevelSelectScene() {
// Way 1
// code only, no XCode/SpriteKit visual level editor used
let scene = LevelSelectScene(size: self.size) // same size as current scene
// Way 2
// with xCode/SpriteKit visual level editor
// fileNamed is the LevelSelectScene.sks you need to create that goes with your LevelSelectScene class.
guard let scene = LevelSelectScene(fileNamed: "LevelSelectScene") else { return }
let transition = SKTransition.SomeTransitionYouLike
view?.presentScene(scene, withTransition: transition)
}
}
/// Level Select Scene
class LevelSelectScene: SKScene {
....
func loadGameScene() {
// Way 1
// code only, no XCode/SpriteKit visual level editor used
let scene = GameScene(size: self.size) // same size as current scene
// Way 2
// with xCode/SpriteKit visual level editor
// fileNamed is the GameScene.sks you need to create that goes with your GameScene class.
guard let scene = GameScene(fileNamed: "GameScene") else { return }
let transition = SKTransition.SomeTransitionYouLike
view?.presentScene(scene, withTransition: transition)
}
}
/// Game Scene
class GameScene: SKScene {
....
}
I strongly recommend you scratch your storyboard and ViewController approach, and just use different SKScenes and 1 GameViewController.
Hope this helps
Go to the segues and use Show Detail Segues anywhere that you don't want the previous view controller to be kept in the stack. Keep in mind that you will have to reinitialize everything appropriately in those view controllers whenever you do return to them.
If you pay attention, viewDidAppear loads every time that you see the view appear, while with your current setup, viewDidLoad would only be called initially and if you returned to the viewController, only viewDidAppear would be called.
When you use a segue to transition out of a viewController, prepareForSegue is called, but deinit() is only called when you use a show detail segue (or custom segue with those specific properties about it), because the view, like you said, is loaded into memory so it can be retrieved easier.

Xcode with swift: Is it possible to show a view controller upon another without resetting the first?

I'm creating a simple game with a pause button. I want to show another view controller with the pause screen without resetting the game view controller when i return. Every thing i have tried, has resulted in the game view controller being reset, when i press the resume button and return to the game.
Does anybody know how i can do this without resetting the game?
It's a sprite kit and swift iOS app in xcode.
You can show a pop-up based view. You can create .xib and design your pause view as you wish. Then you can resume the game without resetting anything.
Sample code:
// Set Pause Page
var pauseView = PauseView.loadFromNib() // need an extension
#IBAction func Pause(sender: UIButton) {
pauseView.btnResume.addTarget(self, action: #selector(resume(_:)), forControlEvents: .TouchUpInside)
// set place on view
view.addSubview(pauseView)
}
func resume(sender:UIButton) {
pauseView.removeFromSuperview()
}
I created a demo for you:
Full demo available on Github: Get Source Code
Create a variable in your original view controller:
var shouldReset = true
Then, when you perform a segue back, add this in your prepareForSegue:
let vc = destination as! //Your view controller
vc.shouldReset = false
In your viewDidLoad (or wherever you reset your data):
if shouldReset == true {
//Reset
}

PresentViewController presents compile error in static/class functions

I have a menu bar which I want to use on every page(UIViewController) in an app. So I figured I'd just write it once and use it on all the pages, instead of reproducing the same code on every page. To go about that, I created a new class which extends UIViewController(named it MenuBarViewController), with its own XIB file, created a function within that class which contains the code for generating the menubar, and just make a call to that function in any UIViewController where I want to place the menubar. Seems to work pretty seemlessly, but I run into problems when I tried to create some helper functions within the MenuBarViewController class, which trigger a navigation to another view, when one of the menu icons is tapped. I will include a simplified version of the code I'm working with below which illustrates the entirety of the problem.
class MenuBarViewController: UIViewController {
func menuBar(viewController:UIViewController){
let menuBar = UIView(frame:CGRectMake(0,0,100,20 ))
menuBar.backgroundColor = UIColor.blackColor()
viewController.view.addSubview(menuBar) //Add the newly created view to the main view(self)
//Add an icon view to the menubar
let iconView = UIImageView(frame: CGRectMake(5,0,5,5))
menuBar.addSubview(iconView)
//Add a gesture recognizer for the icon view
iconView.userInteractionEnabled = true
let tapHomeButton = UITapGestureRecognizer(target: self, action:#selector(MenuBarViewController.goToHomeView(_:)))
iconView.addGestureRecognizer(tapHomeButton)
//Add an icon to the icon view
let iconImageName = UIImage(named:"home.png")!
iconView.image = iconImageName
}
//Helper function to handle the gesture recognizer, helps transition to another view
func goToHomeView(sender: UIImageView!) {
appData.lastView = "GameViewController"
let settingsVC = SettingsViewController(nibName: "SettingsViewController", bundle: nil)
presentViewController(settingsVC, animated: true, completion: nil)
}
}
Now when I tap on the icon, there is no response. So I figured I'd declare the class functions(menuBar and goToHomeView) as either "class" or "static" funcs, and then call the menu bar directly with the class name. But then I get this compile error "extra argument 'animated' in call" on the this line:
presentViewController(settingsVC, animated: true, completion: nil)
So something must be wrong with the presentViewController method when it is declared within a static or class function because when I have the goToHomeView function just do something as simple as printing some text, it works fine. So I'm at a total loss at this point. What to do? Am I going about this the completely wrong way?

Showing keyboard on SKScene and performing action on a sprite node based on key tapped

I am trying to learn SpriteKit and play with some simple sample apps.
Currently I am trying to achieve below things:
Show keyboard over SKScene
If user taps 'A', perform some action on a sprite node, if user taps 'B' perform some other action on other sprite nodes
To achieve 1st requirement I tried below steps:
Step 1: In GameViewController.swift, added a reference to the view.
var keyView: KeyboardDummyView?
Step 2: In viewDidLoad(), created the view, assigned it to the ivar, and added it to the controller's view. Also assigned "self" to a backreference ivar in GameScene.
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// So scene can forward touch event back here.
scene.gvc = self
// Other config
keyView = KeyboardDummyView(frame: self.view.frame)
self.view.addSubview(keyView!)
}
}
Step 3: Added a function to handle a tap/touch.
func handleTap() {
// Show the keyboard
keyView!.becomeFirstResponder()
}
Step 4: In GameScene.swift added the reference to the controller.
var gvc: GameViewController?
Step 5: In touchesBegan handled tap.
gvc!.handleTap()
But for some reasons it is not showing the keyboard when screen is tapped :(
Here is the code base: KeyboardOverSKScene
Please suggest if I am doing any thing wrong?
Note: I am trying this in Xcode 6.0.1

Resources