Reputation: 87
I am creating a random item spinner for my iOS App in Swift using SpriteKit, but currently my method is not very efficient, and I am almost certain it cannot be the best way of achieving what I am aiming for. The process I am currently following is essentially.
- On scene load, loop through a list of 13 different items (stored in JSON)
- Create a group of nodes showing the relevant data
- Add each group of nodes to a second group of nodes, moving each one along the x axis slightly, creating a long line of SKNode's (the items for the spinner)
- Moving that group along the x-axis, to give the impression of it spinning through the items
But this method takes about 6 seconds to even load the scene (and delay is on adding the nodes to the much larger node: group.addChild(spinnerItem)
and as I am only new to Swift I am sure there is a better way of me doing this, so any help/advice appreciate to improve this code cause it's in serious need of efficiency improvements!
Here is the didMove function...
override func didMove(to view: SKView) {
var xPos = CGFloat(self.frame.width + 150)
var eventWeapon = weapon()
for n in 0...13{
eventWeapon = getWeapon(caseName: "chromaCase", weaponID: n)
print(eventWeapon)
let texture = createSpinnerItem(wName: "\(eventWeapon.name)", wSkin: "\(eventWeapon.skin)", wColor: "\(eventWeapon.color)")
let spinnerItem = SKSpriteNode(texture: texture)
spinnerItem.position = CGPoint(x: xPos, y: self.frame.height / 2)
group.addChild(spinnerItem)
xPos = xPos + 300 * 1.2
}
self.addChild(group)
group.run(SKAction.moveBy(x: -5000, y: 0, duration: 2))
}
and the createSpinnerItem
function used within that...
func createSpinnerItem(wName: String, wSkin: String, wColor: String) -> SKTexture {
let object = SKNode()
let bGround = SKShapeNode(rectOf: CGSize(width: 300, height: 300))
bGround.fillColor = color.offWhite
bGround.strokeColor = color.gray
bGround.lineWidth = 5
object.addChild(bGround)
let titleBG = SKShapeNode(rectOf: CGSize(width: 300, height: 100))
if wColor == "blue"{ titleBG.fillColor = color.CSGOblue }
if wColor == "red"{ titleBG.fillColor = color.CSGOred }
if wColor == "pink"{ titleBG.fillColor = color.CSGOpink }
if wColor == "purple"{ titleBG.fillColor = color.CSGOpurple }
titleBG.strokeColor = color.gray
titleBG.lineWidth = 5
titleBG.position = CGPoint(x: 0, y: -150 + 50)
object.addChild(titleBG)
let weaponName = SKLabelNode()
weaponName.text = wName
weaponName.fontColor = color.white
weaponName.fontSize = 40
weaponName.fontName = "Avenir-Regular"
weaponName.verticalAlignmentMode = .center
weaponName.position = CGPoint(x: 0, y: -150 + 70)
object.addChild(weaponName)
let weaponSkin = SKLabelNode()
weaponSkin.text = wSkin
weaponSkin.fontColor = color.white
weaponSkin.fontSize = 20
weaponSkin.fontName = "Avenir-Regular"
weaponSkin.verticalAlignmentMode = .center
weaponSkin.position = CGPoint(x: 0, y: -150 + 30)
object.addChild(weaponSkin)
return object
}
Upvotes: 4
Views: 111
Reputation: 7331
One of the first things you want to do is to determine if your "perceived" delay is real or not versus just the overhead of the app being launched. 6 sec is a long period of time, so without measurements, one doesn't know if you're just exaggerating or understanding the true delay. I will get into what I mean by perceived in a few. You should do as KnightOfDragon suggests and actually measure the time.
I do see one issue with the code right now, and it is not uncommon for what I see with people's code using SK on SO. And this goes into the perceived notion mentioned above. The actual CPU usage required to process your work may not be large, however what you experience during run time may not match that actual expected CPU loading. Why? You are probably doing a lot of work on the main thread. From loading the JSON to potentially creating the textures. As such, you will find that by starving the main thread, you can see slow downs you would not otherwise see. The generalized problem, app or game, is that I see many people try and literally load everything in their didMove
or if an app viewDidLoad
. What you really want to do is treat that more like a bootstrapping start point. Do the minimal amount of work there to setup, and then asynchronously dispatch the time consuming stuff using your favorite method. This will alleviate you locking up the main thread while you do stuff like file I/O.
Yes, this does complicate your code a bit to be able to handle this, but this is approach is not atypical. Most engines have loading systems to help load items in the background and notify when they are done. While the loading occurs you usually see a loading screen or some other indicator.
Just keep in mind that when you modify the SKNode
hierarchy you'll need to make sure you do it on the right thread (for example when you addChild
to the active scene). You can do it either via an SKAction
or on the main thread. Your app can crash otherwise.
Upvotes: 2