multiple sks files, calling proper scene based on GVC in SpriteKit - iphone

I have five iPad scenes, and 5 iPhone Scenes in my GVC I have this, I can call the Welcome Scene and Hud Scene no problem, yet I can not replicate the same calls for the other scenes. I do not know if it is the curly braces, yet I can not seem to call the other iPad scenes it defaults to the iPhone scene. (trust me I was pretty excited when the HUD, showed up.) Can someone give some advice on the structure of my code. Please....
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
if let scene = WelcomeScene(fileNamed:"WelcomeScene") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
} else {
if let scene = WelcomeScenePad(fileNamed: "WelcomeScenePad") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
if let scene = HudScenePad(fileNamed: "HudScenePad") {
let skView = self.view as! SKView
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
} else if let scene = WelcomeScene(fileNamed:"WelcomeScene") {
let skView = self.view as! SKView
skView.showsFPS = GlobalData.Constant.DEV.DEBUG
skView.showsNodeCount = GlobalData.Constant.DEV.DEBUG
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
}
override func prefersStatusBarHidden() -> Bool {
return false
}
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.
}
}
This bit of code lets me know that the game scene is going to proper sks file, and prints the value in the editor, to verify, this is in my gameOver Function.
if (UIDevice.currentDevice().userInterfaceIdiom == .Pad ){
if let _ = SceneTypePad(rawValue: fullSKSNameToLoad + String("Pad")) {
fullSKSNameToLoad = "fileNamed" + "Pad"
goToScenePad(SceneTypePad.DebateScene1Pad)
print(("Went to DebateScenePad"))
_ = SKTransition.fadeWithDuration(3)
_ = DebateScene1Pad()
}
} else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone ){
goToScene(SceneType.DebateScene1)
(print("Went to DebateScenePhone"))
_ = SKTransition.fadeWithDuration(3)
_ = DebateScene1()
}
Three secs is too long to wait btw... :)

I needed to create a new static variable to call the SKs pad scene in my GlobalData/Base Scene file. Noob mistake. Word to the wise when duplicating code for the new files double check the variables, when duplicated swift files. Also, it is good to give the mind a break, individuals can not keep their attention span and be sharp after 14 hours of coding.... Take a walk, sort it out with a fresh mind. Deadlines are crucial in this business, yet sometimes pressure can bring about silly decisions that can be easily solved.
static var previousScenePad:SceneTypePad?
static var nextScenePad:SceneTypePad?
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
if (UIDevice.currentDevice().userInterfaceIdiom == .Pad ){
if let _ = SceneTypePad(rawValue: fullSKSNameToLoad + String("Pad")) {
fullSKSNameToLoad = "fileNamed" + "Pad"
}
} else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone ){
}
Does work in GVC when calling particular SKS files. Obviously it renders the proper view based upon using the correct fileName "" that is defined in the base class, yes I am aware, that there are better way to use one SKS files, and using camera nodes to adjust views. When it comes to content, and having more space it gives opportunity to create a different experience with more pixels, and more space. Assets are equally important, as in the beginning I was calling the wrong assets per device, I decided to hard code, the scale factors for my look without losing resolution. The end result will be a universal app that works cross platforms. If you optimize right, I was able to condense a 140mb app, to 76mb, even though I added 5 new scenes to my app bundle. Check your background music, check your sound effects, and PNG files. Limit emitters to the effect that looks good. You can always go back and find cleaner approach in the next update!!!

Related

Terminated due to memory issue - ViewControllers taking up memory

I'm developing a game using sprite kit and have various view controllers for different scenes. Like story mode, multiplayer etc...
I've noticed a problem where every time I open up a view controller with a SpriteKit scene, the memory usage for my app increases. And when the view is dismissed, that memory isn't allocated back?
Is there something I need to be doing in my code to return the memory the ViewController or SpriteKit scene used up upon loading?
EDIT: As requested, here is some code from when the VC loads up with a SpriteKit scene & the code used to dismiss the VC:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene.sks") {
scene.scaleMode = .aspectFill
view.presentScene(scene)
(scene as! GameScene).parentVC = self
}
}
}
For the view dismissal, I first present a loading screen over the UIApplication.shared.keyWindow and then dismiss:
dismiss(animated: true) {
LoadingScreen?.removeFromSuperview()
}
The loading screen class is handled in the AppDelegate.
I think it's an issue of retain cycles
1 if let view = self.view as! SKView? {
2 if let scene = SKScene(fileNamed: "GameScene.sks") {
3 scene.scaleMode = .aspectFill
4 view.presentScene(scene)
5 (scene as! GameScene).parentVC = self
}
}
if line 5, inside the closure, you're referencing self, so when the viewcontroller should be deallocated, the reference on line 5 is stopping the deallocation, Can you try this :
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene.sks") {
scene.scaleMode = .aspectFill
view.presentScene(scene)
guard let scene = scene as? GameScene else { return }
guard let scencePVC = scene.parentVC else { return }
scencePVC = self
}
}
I'm trying to fix the issue without knowing the object hierarchy but it's hard. Basically the issue is that you have 2 objects( viewcontrollers) referencing each other that would stop the deallocation.
You can read more about this issue here & here

Gamescene.swift and Gamescene.sks not working together

I am having a problem with my xCode project. I have a whole gamescene.swift file worth of code (600 lines). But the code will not run. When i run my game in simulator the simulator shows the standard gamescene.sks color, alongside with my ads, but it is not showing any of my code. I have already checked that the custom class in gamescene.sks is correct. Everything is working, expect for the gamescene.swift code, it will not run.
import UIKit
import SpriteKit
import GameplayKit
import GoogleMobileAds
class GameViewController: UIViewController {
#IBOutlet weak var GoogleBannerView: GADBannerView!
#IBOutlet weak var MainMenu: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
GoogleBannerView.adUnitID = "ca-app-pub-13***46014918193/236762****"
GoogleBannerView.rootViewController = self
GoogleBannerView.load(GADRequest())
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 = .resizeFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
view.showsPhysics = 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
}
}
i managed to fix the problem after countless hours of trying.
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .resizeFill
this is the working code. the problem was that instead of specifying what scene i was suppose to lead i had written
if let scene = SKScene(fileNamed: "GameScene")
the simple fix was changing the "SKScene" to my SKScene name.
if let scene = GameScene(Filenamed: "GameScene")
Hope this helps the countless other out there that are having trouble with this problem!
I've had similar problems to this on SOME of my projects but not all. Even on projects that were working and I duplicated the code and scene files for another project they would stop working. I discovered that if there are any spaces or special characters in the your project name the scene files and items in the sks files will not load unless you put in the "Module" name below the Custom Class type.
For me my project was named "Crag & Pig" before any of the sks file would register I had to enter "Crag_Pig" in the "Module" for all of the items in the sks file.
Interestingly, on any projects that didn't have spaces or special characters I didn't have to enter any thing for Module
Thanks. Even the default template in Xcode for SpriteKit Games has this very issue. That since the release of swift 4 + iOS 11.
I always thought it was me somehow, but never took the time to find why. Until now out of curiosity. I changed the line you wrote/fixed and voila.
Just changed the capitals in the parameter fileNamed: of your line
if let scene = GameScene(fileNamed: "GameScene")

Deleting the Gamescene.sks file raises CPU to 25% on device

I just created a brand new Xcode Game Project. I deleted the Gamescene.sks file. Ran it and the cpu instantly to 25-30%. I made another Xcode project just to see if I could replicate it. Ran it before deleting the file and cpu was basically 0%, but sure enough when I deleted the file and ran it again, the cpu jumped up to the same high numbers. My goal is to subclass skscene and use that without the Gamescene.sks file. Can someone explain why this happens?
I was able to replicate this behavior just deleting the .sks file.
The problem is GameViewController is looking for that file at first loading time, as you can see here:
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
}
}
So you need to initialize it another way. Just as an example, you could init an empty scene like this:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = SKScene(size: CGSize(width: 1000, height: 1000))
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
and you'll see 1% of CPU load.

GameScene misses initializers

I get an error that "Class 'GameScene' has no initializers" when I try to add a level selection to my game.
I present the scene in GameViewController.swift like this:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.level(1) {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsPhysics = 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
skView.presentScene(scene)
}
}
And in my GameScene.swift I wanted to handle the level selection like this (got this from Ray Wenderlich iOS Game Development Books)
class func level(levelNum: Int) -> GameScene? {
let scene = GameScene(fileNamed: "Level\(levelNum)")!
scene.currentLevel = levelNum
scene.scaleMode = .AspectFill
return scene
}
But then I get the error as I mentioned and I dont know how to fix this issue :-? Are there any other ways to make a level selection? Currently I have for each level one sks file, which is something I find really handy, since I enables me to lay out the levels visually.
Any recommendations and/or help?
Thanks in advance

How to accept Game Center invite in swift

I have some troubles to make the invite accept in swift.
could someone help me with the right coding? Here is mine
GKMatchmaker.sharedMatchmaker().matchForInvite(Invitation!, completionHandler = {(InvitedMatch:GKMatch!, error: NSError!) -> Void in
if InvitedMatch != nil {
myMatch=match
LocalGame=false
if let scene = GameScene.unarchiveFromFile(environment_Prefix!+"GameScene") as? 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 = .Fill
skView.presentScene(scene, transition: SKTransition.flipVerticalWithDuration(2.0))
}
}
})
Thanks
Finally I have figured out the solution which works. I had to implement the GKLocalPlayerListener like this and call the match for invite within the delegate function.
func player(player: GKPlayer!, didAcceptInvite invite: GKInvite!) {
GKMatchmaker.sharedMatchmaker().matchForInvite (invite, {(InvitedMatch, error) in
if InvitedMatch != nil {
myMatch=InvitedMatch
LocalGame=false
if let scene = GameScene.unarchiveFromFile(environment_Prefix!+"GameScene") as? 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 = .Fill
skView.presentScene(scene, transition: SKTransition.flipVerticalWithDuration(2.0))
}
}
})
}
To get the player function called I have to register the listener at the local player authenticated block like this:
localPlayer.registerListener(self)
Now game invite works perfectly.