How do I access variables in Swift contained in a custom class on a SpriteKit Scene Editor Reference node? - swift

First I would like to say that I am completely self taught following as many tutorials on the internet that I can find, so apologies in advance if there are certain concepts Im not too familiar with.
Alright with that out of the way I'd like to ask help on something that's been stumping me for days.
I have a reference node(referenceNode) in a SpriteKit Scene(GameScene),
That reference node references another SpriteKit Scene( referenceScene),
and this scene has a Custom class(referenceClass.swift).
I have a boolean variable in referenceClass.swift called trueOrFalse, and I want to be able to change the vale from my code in gameScene.swift.
I have tried casting from the SceneEditor to my code by creating instances as you would do SKSpriteNode's and SKLableNodes but this does not seem to be working
class GameScene: SKScene
{
var referenceNode: SKReferenceNode! //link to SceneEditor Reference Node
override func didMove(to view: SKView)
{
referenceNode = self.childNode(withName: "referenceNode") as! SKReferenceNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
referenceNode.trueOrFalse = false
}
}
this is my custom class
import UIKit
import SpriteKit
class referenceClass: SKScene
{
var trueorfalse:Bool = true
func oneFunction()
{
}
}
This is just a small example project that I made so I could get my head around the concept trying the different solutions I could find but with no success.
I realise I could create global variables but I am trying to keep my code Clean as In all functionality related to this node to be kept in this referenceClass. Also I've been told its not good programming?
Any help would be greatly appreciated :)
Barney

First of all I would check whether the search is done properly -
https://developer.apple.com/documentation/spritekit/sknode/searching_the_node_tree
For instance, in the template SpriteKit project nodes are being searched with // prefix, i.e. //referenceNode in your case.
Secondly, do not force-cast it to SKReferenceNode immediately, first check what kind of object is returned (if any).

Related

How do you update your UI when using a state machine

I'm using swifts stateMachine from gamePlayKit. It works great, but there is one thing I don't understand: The stateMachineseems to be its own isolated island; from what I can tell there is no way to pass in arguments or get callbacks. And this raises questions like, how do I update the UI?
Lets say I enter combat state:
stateMachine.enter(CombatState.self)
There's no way to pass in an argument. Ok, fine. But then CombatState does its thing and when it's done it goes into another state. BUT, before that I need a callback to the view so that I can remove the units from the board lost in combat like so:
self.removeChildren(in: nodesOutOfAction)
But there's no way to send the nodes out of the stateMachine because there's no possible way to add a completion handler. So how do you work around this problem? To me the stateMacine is pointless as it canĀ“t update the UI.
Its possible to access properties of the state like so:
stateMachine.enter(CombatState.self)
self.removeChildren(in: combatState.nodesToRemove)
But that can't be safe, right? Still, as this is the only option that I know of, this is how I solve it.
I totally recommend you check the DemoBots project from Apple.
You should pass the entity reference on the State Initializer
For example
class CombatState: GKState {
unowned var gameScene: GameScene
required init(gameScene: GameScene) {
self.gameScene = gameScene
}
override func didEnter(from previousState: GKState?) {
gameScene.removeChildren(in: ...)
}
}
With this logic you can decouple a lot of logic inside to the states.

How can I use GameplayKit State Machine for sprite animation?

I have two animations for my player to run and jump. Can I control these animations using GameplayKit's state machines? If so, how? In this project, I use SpriteKit and GameplayKit for Entity-Component architecture and State Machine.
You need set first the StateMachine and fill with your custom classes
self.playerStateMachine = GKStateMachine(states: [
PlayerRunning(player),
PlayerJumping(player)
])
Then when you need to enter to state, can be with:
self.playerStateMachine?.enter(PlayerRunning.self)
On the state you can perform changes like:
override func didEnter(from previousState: GKState?) {
self.player?.run(runAnimation)
}
Example:
Please take a look of complete example here: https://github.com/Maetschl/SpriteKitExamples/blob/master/StateMachineAnimation/StateMachineAnimation/GameScene.swift

Custom knob NSSliderCell OS X Swift

Edit: I just read that cells are being deprecated post 10.10 (I guess I have to find an alternative method anyway)
I was wondering if someone could point me in the right direction for doing vector based (core animation/ graphics) custom controls in OS X using swift.
I have a NSSliderCell which I am trying to make look like this.
So far I have removed the bar by overriding the drawBar Method and leaving it empty.
And tried a bunch of different ways to draw the Knob (omitted from the code example) as a triangle. (its super simple but the documentation is really sparse.) but all so far have come with a mixed result of wrongness.
Could you point me towards good documentation for OS X or help me understand a little about the implementation please.
Kind Regards
Brian
class VolumeSliderCell: NSSliderCell {
override func drawBar(inside rect: NSRect, flipped: Bool) {
// NOTE: Deliberately left empty (Hides Bar!)
}
override func drawKnob(_ knobRect: NSRect) {
if(controlView?.lockFocusIfCanDraw())! {
// NOTE: What goes here?
}
}
}

Where should I put my functions?

I'm working on an app and I wrote a large part of an SKScene in a single class. It works great, but when I took a (java) course this past semester, it seems that accepted industry practice is to separate it into many classes.
More specifically, my (SpriteKit) app contains a cat and a mouse and after finishing said course, I decide that instead of containing all their info in the SKScene, I should separate some of it into multiple classes (a Player superclass with Cat and Mouse subclasses) each containing their relevant info (such as x and y position,) and functions (such as moveCat) with only Scene related functions and info in the Scene class.
The problem lies in the content of the functions.
Particularly one of the functions, pathBlocked(which checks if there are any barriers blocking the desired path of movement) uses a lot of info that wouldn't make sense to contain inside the Player object (such as all the info about the barriers on the board, and how much cheese was collected).
I can't just leave pathBlocked as a Scene function because there's a function that should belong to the cat (catAI) which uses pathBlocked to navigate. If it's a method of the scene, then it won't work. I'd need to instantiate a Scene object every time I wanted to call pathBlocked.
Should I just forget about making the Cat and Mouse Classes or should I fill the Player class with info that doesn't quite belong?
or is there a third option I'm not thinking of?
If you need a snippet of the code, I could include some of it.
Thanks!
Ok, so what you should do is
class Cat {
var sceneRef: GameScene? //or whatever scene is called
var xPos: CGFloat!
var yPos: CGFloat!
init(s: GameScene){//just example stuff
sceneRef = s
xPos = sceneRef!.childNodeWithName("cat").position.x
yPos = sceneRef!.childNodeWithName("cat").position.y //However, these variables will not stay up to date. If you need them current, you would have to do the same thing again, xPos = sceneRef!.childNode...etc.
}
func doStuff{
}
func createNewPath()
//create a new path
}
}
Then in the scene, you can do:
class GameScene: SKScene {
var cat: Cat?
override init(size: CGSize){
super.init(size: size)
cat = Cat(s: self)
func whatever() {
if (pathBlocked()){
cat!.createNewPath()
}
}
I think you will just have to unwrap it each time you use it, but XCode will tell you that.
^ credit for that should go to AMomchilov, I didn't know about weak references at all before this. It was a fun learning experience XD.
If you are looking to organize your code, another way you could do it is have an extension file for your scene, and throw all the low level function stuff in there, and keep all the high level stuff in the actual scene class. Make a new class, and call it SceneExtension or something:
import SpriteKit
//import whatever else you need
extension GameScene { //<- Or whatever your previous scene that you want to extend is called
func pathBlocked() {
//function code
}
//other functions
}
And just basically throw all the other functions that you don't want to look at and just take up space in the actual scene file. It acts like its in the same file, so you can call any of the functions in here, or use any variables from either class.

Need some general classes advice

I appreciate this is not Swift specific, but I am writing a small game in Swift thus I have tagged it with the relevant tag. I am new to the Swift language but picking it up quickly, and while not new to programming in general, do often question my approaches.
Here is my scenario:
I am writing a small 2D platform game with a player character and various obstacles. The player can have different textures but generally shares the same capabilities, such as jump and sprint. Likewise, the obstacles generally have different textures, but otherwise share the same capabilities.
Both the characters and obstacles also share common capabilities but not all, for example an obstacle can't jump. With this in mind, this is how I have written my classes...
class GameObject {
let node : SKSpriteNode!
}
Class GameObstacle: GameObject {
init() {
super.init()
}
func explode() {
// explode code
}
}
class GameCharacter: GameObject {
init() {
super.init()
}
func jump() {
// jump code
}
}
class GameCharacter_Sheep : GameCharacter {
init() {
super.init()
self.node = SKSpriteNode(namedFile: "sheep")
}
}
My logic behind this approach is that all of the common object functionality is included in the GameObject class, all of the common character functionality (such as jump) is included in the character class and the unique stuff, down at the class level.
One question I have, am I correct to initialize my node (defined in my GameObject class) in my GameCharacter_Sheep class? My rationale is that because the texture, and thus physics body will differ from character to character, that is the correct place to do the implementation?
Again, I appreciate that this may be basic OOP and not really Swift specific but I'm just looking for some guidance.
Many Thanks,
Jon
If all your game objects are going to have an instance of SKSpriteNode which is passed data from a named file, you can move it's creation into the base class, and just have the file named passed into the call to super.init().
More generally, inheritance isn't the only option for sharing functionality between different game objects. Don't forget about composition, which is often preferred when defining game objects to avoid deep, inflexible inheritance hierarchies which sometimes cannot model the desired behaviour. There are a whole bunch of ways to approach all the way through to a full blown game object component based system.