Where should I put my functions? - swift

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.

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.

Unity - Game modes as state machine?

I am making a quiz game in Unity and I've come across architectural problem.
I want the game to have few game modes, like standard, faster answer - more points, etc. Each of which will behave in its own specific way but some things will be very similar like answering questions, starting timer, etc.
Currently its structured based on this. There is a QuizSystem that holds reference to QuestionDatabase, UIReferences(buttons,score text, etc) and GameSettings (questions per game/per mode etc).
To start the game you need to call QuizSystem.Start() and it starts its current GameMode which derives from abstract StateMachine and is a monobehaviour (dont know if neccesary). I also have abstract State class from which different game states will derive from. It has a constructor with (GameMode owner) as paramenter and 3 functions: Start(), Tick(), End().
So, this way I can have Standard game mode which will instatiate lets say StandardPreparationState, which on end will call StandardAnswerState which will start the timer and wait for user input and again call StandardPreparationState. Cycle will repeat until questions per mode amount is reached and then delegate next action to QuizSystem.
The advantage of this approach is that every mode can behave in its own way like add additional steps in between but it kinda limits reusability. What I mean by that is if some OtherMode would have the same preparation functionality but different action afterwards, it wouldn't work beacause
StandardPreparationState would transition to StandardAnswerState.
I could add another parameter such as (GameMode owner, State transitionTo) to the State constructor but that somehow seems wrong I don't know why xD
What I want to know is how do you guys implement different game modes for your games? Do you make each mode as separate scene? Or maybe use States Machine pattern and have Manager class that takes care of starting/swaping modes?
I know that each game is different but are there maybe some common approaches for that?
Thanks in advance!
This question is quite open and opinion-based. However there are few "common" approaches, one of the most important is to make game "data-driven".
What? Why? How?
Imagine you are having space shooter, where you have your ship flying around and picking guns. Each time you add new gun, you will have to code its damage, kind of projectiles and how many of them you shoot, their color, in what pattern they spawn, speed, size, ...
Everytime you would want to add a new gun, you would need to enter the code and change it there, compile, ... Lot of work.
Instead people thought, "why don't we create simple class that holds all the parameters? We will make it editable from Unity, instatiate it in the project and we won't need to code that much."
This is when Unity brought Scriptable objects.
Scriptable objects
A ScriptableObject is a data container that you can use to save large amounts of data, independent of class instances. One of the main use cases for ScriptableObjects is to reduce your Project’s memory usage by avoiding copies of values.
The idea is to create scriptable object for your mode and set up multiple kinds of modifiers that will the mode use. Folder structure might look like:
> ScriptableObjects
| |--> Modes
| |-> NormalSO (instance)
| |-> HardWithLotOfExpSO (instance)
| |-> EasyWithLowerExpSO (instance)
> Script
|--> ScriptableObjects
|-> ModeSO
ScriptableObject is class that doesn't really have the logic inside, just creates "structure" for keeping data. Example of such class would be:
public class ModeSO : ScriptableObject
{
public string modeName;
public float scoreMultiplier;
public int numberOfEnemiesMaxAlive;
public int numberOfEnemiesTotal;
public Vector3[] spawnPoints;
}
In the Unity itself you would then create instance of such objects. And what about interaction with other classes? Well, they would just work as:
Game manager hold single instance of active mode
Class that would be handling score (e.g. player / scoreboard) or Enemy would ask GameManager what is current multiplier for score
WorldSpawner would ask GameManager how many enemies should he spawn, where, and when to spawn next ones
At the beginning of the game you would be able to select difficulty by its name
Example of one of the classes (Scoreboard):
public class ScoreBoard: MonoBehavior
{
GameManager manager;
private float totalScore;
OnEnemyDestroyed(float scoreForEnemy)
{
totalScore += scoreForEnemy * (manager?.activeMode?.modifier ?? 1);
}
}
And the best is, whenever you will change some data, you will just modify the existing instance in the Unity. No need to go into code. No need to recompile whole game.
I think having different scenes for each game mode, especially if the modes are very similar save for a few settings, is unnecessary. I'd have to see more of your design to know how your game logic is being handled (is it all managed in one GameManager script? Or are there multiple scripts in the scene that take values from this manager script to handle game mechanics?)
One way I've handled different game modes before is to use a public int value in the GameManager that represents the different modes (i.e 1 = easy, 2 = medium, 3 = hard). I would then use a switch statement in any scripts whose behavior/values depend on this mode and reference that public int to determine game settings.
Game Manager:
public class GameManager: MonoBehavior
{
public int gameMode = 0; //set to 1,2, or 3 by UI
[...] //rest of game manager code
}
Example Behavior Script:
public class EnemySpawn: MonoBehavior
{
public GameObject enemy;
GameManager gm;
private float spawnRate;
Start()
{
switch(gm.gameMode)
{
case 1:
spawnRate = 15f;
break;
case 2:
spawnRate = 10f;
break;
case 3:
spawnRate = 5f;
break;
default:
spawnRate = 10000f;
Debug.log("invalid mode");
break;
}
}
Awake()
{
InvokeRepeating("SpawnEnemy", spawnRate, 0f);
}
[...] //rest of EnemySpawn code, including a SpawnEnemy() function.
}
This example would reference the GameManager's gameMode int to determine what speed to spawn enemies at, assuming there is a SpawnEnemy() function somewhere down in the code. I can't verify if this example is syntactically correct, but it's just to show one way to handle game modes.

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

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

Modifying reference type parameters in Swift; are changes immediately visible outside?

I have a Swift playground that contains several classes in the source folder. These classes have tick() functions that are called as fast as possible with a while true { }. I am using a parallel thread to do this, to stop Xcode from locking up, with this code:
DispatchQueue.global(qos: .background).async {
BackgroundThread.startMainLoop(scene: scene)
}
// other file
public struct BackgroundThread {
public static func startMainLoop (scene: SKScene) {
let songController = SongController()
let uiManager = UIManager(scene: scene)
// The UIManager is going to modify this scene.
// Will the changes be available to BackgroundThread and/or the main file?
while true {
songController.tick()
uiManager.tick()
}
}
}
Because the main playground script is very slow, I have moved the repeating loop to a compiled class in the Sources folder.
I am passing an SKScene object to a UIManager compiled class, which I will need to update the UI in this (relatively complicated) scene faster than the main playground script can manage.
The main playground script calls a startMainLoop() function in the parallel thread. It passes in the SKScene object. This function never returns, since it contains a never-ending loop. Is there a way I can modify the passed object in a manner that modifies the scene displayed on the screen, live, without the function ever having to return (which means that inout is not an option), assuming this does not happen by default?
Reference type means the value is a reference -- i.e. a pointer to an object. When you pass or assign a reference, you get a copy of the reference (it is pass-by-value without inout), but multiple copies of the reference point to the same object, and modifications to the object through any reference that points to it is visible through any other reference that points to it.

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.