Search code examples
swiftfunctionclassobjectskscene

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!


Solution

  • 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.