Assigning another variable from a different class in an #IBAction? - ios

In my GameScene.swift file, I have the following member variable "chosenBall" that I want to assign in another file called ChooseBall.swift.
class GameScene: SKScene, SKPhysicsContactDelegate {
internal var chosenBall: BallType!
}
My ChooseBall.swift file looks like this.
class ChooseBall: UIViewController {
#IBAction func chooseBeachBall(sender: UIButton) {
chosenBall = BallType.BeachBall
}
}
I am getting a compiler error saying:
Use of unresolved identifier 'chosenBall'
How can I fix it ?

I haven't used SpriteKit so I do not know the basics on where and when to instantiate Scenes.
However, the error you are getting is because you have not created an instance of GameScene and made that accessible from your view controller.
A possible solution could be the following code, but again, I'm not sure when or where the scene should be instantiated.
class ChooseBall: UIViewController {
var scene = GameScene()
#IBAction func chooseBeachBall(sender: UIButton) {
scene.chosenBall = BallType.BeachBall
}
}

Related

Pass data from View Controller to Class?

First, I'm not pass data between view controllers. I need pass data from a View Controller to another class.
Situation likes this:
I have one View Controller, it has slider, then I have a Camera class. I defined a camera the Scene Class, once I change the slider, the value of the camera in the Scene class needs to be changed.
VC:
class ViewController: {
#IBAction func moveSlider(_ sender: NSSlider) {
// here I want to pass the sender.value to the Camera class
}
}
Camera class:
class Camera {
var cameraLocationX ; // I want this value updated once the the slider moved, however the camera instance is defined in the Scene
}
However, this Camera class are not defined in the VC. So I can't use the static var method...
class Scene {
let camera = Camera()
..
camera.cameraLocationX; // here it needs to be updated.
}
How to achieve this? I Googled it seemed that I should use delegate or notification , but can someone give me a little more instructions?
Use the delegation pattern. This is a core concept described https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
If you want to update property of class then you can set new value from your VC:
class ViewController: {
let camera = Camera()
#IBAction func moveSlider(_ sender: NSSlider) {
// here I want to pass the sender.value to the Camera class
camera.cameraLocationX = sender.value
}
}

What's the cleanest way to call a method from one SKScene to another in Swift?

So I got in my game 3 different scenes: MenuScene, GameScene and GameOverScene.
I would like to know how I can get the score variable located in GameScene from GameOverScene so I can show it up there after the player loses.
So in GameScene, I created this simple getter:
func getScore() -> Int {
return self.score
}
But if I try to do GameScene.getScore() from a different Scene I get an error.
Tried using "class" before func
class func getScore() -> Int {
return self.score
}
But that also gives me an error from GameScene saying:
"Instance member 'score' cannot be used on type GameScene"
So how's the best way to do it? I don't want to create a global variable for this, it would be ugly.
This is quite easy actually. When you segue to the new scene, you can also pass in a variable with it... Here is an example.
GameOverScene.swift
var score:Int = 0
GameScene.swift
var score:Int = THE USERS SCORE
func segue(){
let gameScene = GameOverScene(size: self.size)
gameScene.score = score
let transition = SKTransition.doorsCloseHorizontalWithDuration(0.5)
gameScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view?.presentScene(gameScene, transition: transition)
}
You need to keep an instance of GameScene in your MenuScene class (recommended). Alternatively, you can store the score in a global storage medium.
To enter the game scene, you need to create it first, right?
let scene = SKScene(fileNamed: "blah blah blah")
view.presentScene(scene)
Now instead of creating the scene and assigning it to a local variable, you assign it to a class level variable.
var gameScene: GameScene?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (...) {
gameScene = SKScene(fileNamed: "blah blah blah")
view.presentScene(gameScene!)
}
}
Then, when appropriate, you can access the score like this:
gameScene.getScore()
Another way is to use NSUserDefaults, but you don't seem to like it.
The final way that I can think of is to use static variables. You put all the stuff that you need to pass between the two scenes in a class as static variables. The disadvantage of this is that unless you declare the class private and put both scenes and the class in the same file, others classes can access and change the variables. This reduces maintainability.
Explicit getters are not needed in Swift, btw.
There are many ways to achieve what do you want to do. You could use a manager class , a shared instance to maintain your game variables.
Why this choice?
Because you will want to save your values or your profile or you will want to reset all the game progress, because you will want to select the old 2nd level when you have unlocked the 18th level, or repeat a failed level without accumulating values. It's fast to do it and you can handle separately your common game variables (it seems that I'm selling pots in an advertisement..)
class Settings: NSObject { // NSCoding in case you want to save your data
var score: Int = 0
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(score, forKey: "score")
}
init(coder aDecoder: NSCoder!) {
score = aDecoder. decodeIntegerForKey("score")
}
override init() {
super.init()
// do whatever you want to initializing your settings
}
}
class GameManager: NSObject {
static let sharedInstance = GameManager()
var settings : Settings! = Settings()
}
class MenuScene: SKScene {
let gameManager = GameManager.sharedInstance
override func didMoveToView(view: SKView) {
print("the current score is \(self.gameManager.settings.score)")
}
}
class GameScene: SKScene {
let gameManager = GameManager.sharedInstance
override func didMoveToView(view: SKView) {
print("the current score is \(self.gameManager.settings.score)")
}
}
class GameOverScene: SKScene {
let gameManager = GameManager.sharedInstance
override func didMoveToView(view: SKView) {
print("the current score is \(self.gameManager.settings.score)")
}
}

Use a boolean value from another scene in SpriteKit - Swift

I am trying to use a variable from my GameScene.swift file on my GameViewController.swift file to time my interstitial ads appropriately. It's a boolean value that determines if my player is dead or not.
var died = Bool()
That's all I did to create the variable in my GameScene.
When died == true in my GameScene, I want to send that to my GameViewController and then show an interstitial ad. I really just need to know how to pass a boolean between scenes. Thanks in advanced for your help.
You can follow these steps.
Do this in your GameScene:
protocol PlayerDeadDelegate {
func didPlayerDeath(player:SKSpriteNode)
}
class GameScene: SKScene {
var playerDeadDelegate:PlayerDeadDelegate?
...
// during your game flow the player dead and you do:
playerDeadDelegate.didPlayerDeath(player)
...
}
In the GameViewController you do:
class GameViewController: UIViewController,PlayerDeadDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
...
scene.playerDeadDelegate = self
}
}
func didPlayerDeath(player:SKSpriteNode) {
print("GameViewController: the player is dead now!!!")
// do whatever you want with the property player..
}
}
Your GameScene should have a reference object as delegate (e.g conforms to GameSceneDelegate protocol) which is actually pointing to GameViewController object. Then when died becomes true, inform your delegate object (GameViewController object) about this event via a delegate-method and implement that method by conforming to the above protocol in your GameViewController class.

How to set UIView delegate?

I have an UIViewController
class WelcomeViewController: UIViewController
and an UIView
class SignUpView: UIView
Now I want to set in my WelcomeViewController delegate of SignUpView:
protocol SegueDelegate {
func runSegue(identifier: String)
}
class SignUpView: UIView { ... }
and connect it in
class WelcomeViewController: UIViewController, SegueDelegate {
how can I set in my WelcomeViiewController those delegate? When I'm trying to set:
override func viewDidLoad() {
SignUpView.delegate = self
}
it returns me
Instance member 'delegate' cannot be used on type 'SignUpView'
how can I find a solution?
You are trying to set delegate to a class. It should be an instance of the class i.e
let signUpView = SignUpView()
signUpView.delegate = self
What would be the point in doing that? If you want to navigate from one View to another, just add that Segue in Storyboard with an Identifier, so you can call self.performSegueWithIdentifier("IdentifierOfSegue", sender: self)
Create a weak property in SignUpView of that delegate(protocol) and name it other than delegate
then you can set and use it.
I agree with the developers saying "you can just do that via segue" but
the problem is you didn't declare a delegate var in the SignUpView class
so you can implement it in the signIn , if you declared it please write the line of code for me in a comment to check it
for now ...
I can suggest that you make a subview to be a parent class then override
which method you want to call
and you need to declare the delegate var as an optional (so you won't have
a memory cycle) like the following line ...
var delegate: SegueDelegate?
Let's solve this for people in need whom could need a solution when reading this issue:
In your UIView:
class SignUpView: UIView
you need to add:
var delegate : SegueDelegate?
Now, still in your class SignUpView, you need to add the function you want to delegate, just like this:
func runSegue(identifier: String) {
delegate?.runSegue(identifier)
}
This will call your delegate:
protocol SegueDelegate {
func runSegue(identifier: String)
}
Now, in your ViewController, you should have your SignUpView somewhere (created programmatically or linked through Storyboard / XIB).
In your viewDidLoadfunction, add: signUpView.delegate = self.
Don't forget to add SegueDelegatein your class heritage.

Swift - Missing argument for parameter "coder" in call

Im am trying to pause or stop an SKAction that is being repeated forever which should happen when the user presses the pause button. I have found a way to stop the music but i cant call the function it is in because of this error. It says exactly: Missing argument for parameter 'coder' in call.
Class GameViewController: UIViewController, SwiftrisDelegate, UIGestureRecognizerDelegate {
#IBAction func didPause(sender: UIButton) {
if self.scene.paused == false{
self.scene.stopTicking()
self.scene.paused = true
GameScene().stopGameMusic() //error on this line
}
}
}
class GameScene: SKScene {
runAction(SKAction.playSoundFileNamed("theme.mp3", waitForCompletion: true), withKey:("themeSong"))
func stopGameMusic() {
removeActionForKey("themeSong")
}
}
There is no initializer for GameScene that takes no arguments - you haven't defined one nor is one inherited from SKScene. If you intend to create a GameScene each time 'pause' is pushed, which is a questionable approach in itself, then you'll need to call an existing initializer or to create an initializer w/o any arguments.
It looks like the designated initializer for SKScene is init(size: CGSize). So instead of simply calling GameScene() call GameScene(size: ...) or, in the class GameScene define
class GameScene : SKScene {
// ...
init () {
super.init (size: ...)
}
}

Resources