Cocos2d to Spritekit

Hey all!


I'm porting one of my old games from Cocos2d 2.2 to Spritekit. It has roughly 10k lines of code in the main play scene so it's a pretty daunting task.


Anyways, most of the objects in Cocos2d have obious equivalents in Spritekit, such as CCSprite as an SKSpriteNode and such. But there are a few things that I'm having a rough time "translating," so to speak.


CCSpriteBatchNode *whole;
[s_getTextureSprite setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"rocketFire_1.png"]];


I can't figure out what these are in SK, although I'm pretty certain that CCSpriteBatchNode is an SKNode. I'm pretty sure CCSpriteFrameCache is a form of caching that is no longer necesary in SK. What do you think?


Thanks!

-X

Answered by Pintxo Creative in 222527022

Good luck with the porting. Cocos2D 2.2 I remember is a pretty old build, so definitely it's going to be an interesting undertaking. But anyway, you're right, most of the general structure and the way things are done are the same, so not super-difficult to convert. That said, though, 10k lines in one scene sounds pretty nuts. Maybe you might think of separating all that, if not into separate scenes, then into object classes. This porting work might be a fantastic opportunity to reorganize stuff in a more object-oriented way.


In terms of the SpriteFrameCache and SpriteBatchNode, I don't expect you'll need these anymore. First, you should have your images in an asset catalog in Xcode, which then offers the ability to batch images together without going into code. It seems you're trying to put up an image in expectation of a frame animation. What you should do is just create the SKSpriteNode with the first frame as its SKTexture, then gather all of the frames into a SKTexture array, which you then run on the SKSpriteNode using SKActions. No caching or batching needed.


Example:

//Add images into the asset catalog and possibly bundle them as a sprite atlas.

let rocketFireFrameAmount = 24
let rocketFireFrameRate = 30

let rocketFire = SKSpriteNode(imageNamed: "rocketFire_1.png")
addChild(rocketFire)

var rocketFireFrames = [SKTexture]()

for frameIndex in 1...rocketFireFrameAmount {
        let frame = SKTexture(imageNamed: "rocketFire_\(frameIndex).png")

        rocketFireFrames.append(frame)
}


rocketFire.run(SKAction.animate(with: rocketFireFrames, timePerFrame: 1.0 / Double(rocketFireFrameRate)))
Accepted Answer

Good luck with the porting. Cocos2D 2.2 I remember is a pretty old build, so definitely it's going to be an interesting undertaking. But anyway, you're right, most of the general structure and the way things are done are the same, so not super-difficult to convert. That said, though, 10k lines in one scene sounds pretty nuts. Maybe you might think of separating all that, if not into separate scenes, then into object classes. This porting work might be a fantastic opportunity to reorganize stuff in a more object-oriented way.


In terms of the SpriteFrameCache and SpriteBatchNode, I don't expect you'll need these anymore. First, you should have your images in an asset catalog in Xcode, which then offers the ability to batch images together without going into code. It seems you're trying to put up an image in expectation of a frame animation. What you should do is just create the SKSpriteNode with the first frame as its SKTexture, then gather all of the frames into a SKTexture array, which you then run on the SKSpriteNode using SKActions. No caching or batching needed.


Example:

//Add images into the asset catalog and possibly bundle them as a sprite atlas.

let rocketFireFrameAmount = 24
let rocketFireFrameRate = 30

let rocketFire = SKSpriteNode(imageNamed: "rocketFire_1.png")
addChild(rocketFire)

var rocketFireFrames = [SKTexture]()

for frameIndex in 1...rocketFireFrameAmount {
        let frame = SKTexture(imageNamed: "rocketFire_\(frameIndex).png")

        rocketFireFrames.append(frame)
}


rocketFire.run(SKAction.animate(with: rocketFireFrames, timePerFrame: 1.0 / Double(rocketFireFrameRate)))

Thanks!


Yeah, the app is definitely an older one. It actually was number one back in 2011, and it hasn't been updated very much since. I'm working on reviving it, so wish me luck 🙂. I'm curious, I already moved all of the images into an asset catalogue and I mostly use [skspritenode imagewithname:@""]. It's working pretty well with the new system.


Anyways, thanks again!

Sounds great! Good luck 🙂.


The asset catalog is just fantastic, in my opinion. I put all my visual assets in there without fail. And referencing them normally as SKTextures works fine, as well. If you want to compile frame sheets of specific animations, you can put all the included frames into a sprite atlas folder in the asset catalog and Xcode will automatically optimize loading for them. I've had issues with sprite atlases unwantedly slicing my frames into smaller parts by their transparency, which screws up the centering of each frame, so I don't personally use them.


I would also suggest you go directly into Swift as you're converting. It just doesn't make much sense at this point to be coding from scratch in Objective-C. I'm sure it's attractive to use the same language as you did in Cocos2D, but this might be a real opportunity to learn Swift super-fast as you're porting. Keep it in mind!

Hey!


I'm glad you like thr asset catalog. And you're right, I should be porting it to Swift while in the process of switching it to SpriteKit. Translating 10k+ lines will take ages, but Swift is obviously the better language. It would be great to hear if you know of any good Swift tutorials, expecially involving classes and object structure, as that's what I need to overhaul in the app.


Thanks again!

-X

Swift has been easily the best and most comfortable language I've known in my career, and it was a great benefit to really get into it just as it came out. At this point I've completely let go of Objective-C, which may still be slightly tricky as many companies do still want you to work in Objective-C often for legacy purposes. But I figured some time along the line when I get to the point that I have to look for more work, the tables will have turned. That stated, it remains a great time to get started with Swift.


Object and class structures really aren't that different in Swift. You'll still use the same common sense logic to separate segments of a scene into classes as you would in Objective-C. So if two separate areas or modalities can be separated in different SKScenes, do so. It'll cut down on the management of states of your game and interface. Next try to recognize any repeating elements of your game, functionalities that could be independent or things that would better serve as almost plug-and-play components, and separate those into classes with a healthy serving of common sense (you also don't want to overdo it). Remember to also think what your class will be subclassing - which in the case of SpriteKit would normally be SKNode.


Here's a super simple relationship between an SKScene and a custom class that subclasses SKNode. In this example MyScene has its own hardcoded property, which is passed to the MyObject object upon creation. MyObject then just takes that variable, passed along in a convenience initializer, and sets it as the value of its own property (which by the way is a implicitly unwrapped optional, with the exclamation point and all). Finally MyScene prints that variable directly from the object property.


MyScene.swift

import SpriteKit

class MyScene: SKScene {

    let sceneVariable = 1

    override func didMove(to view: SKView) {
        let object = MyObject(variable: sceneVariable)
        addChild(object)

        print(object.classVariable)
    }
}


MyObject.swift

import SpriteKit


class MyObject: SKNode {

    var classVariable: Int!

    convenience init(variable: Int) {
        self.init()

        classVariable = variable
    }

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}


There are some clear improvements that Swift + Xcode offer that should be stated here. First, there are no separate header .h and method .m files. Everything can be encapsulated into that one .swift file. Second, classes, variables and properties are automatically universally available within a project to whatever hierarchy level you declare them. So no more importing of class files, which is just such a hassle-saver. This also makes it really easy to have global variables without a singleton class. If you want to make variables private to wherever they are, you have to separately declare them as private. Third, connected to the previous points, there is no need to make properties and synthesize them. Instance variables of a class are completely straightforward.


To get started with the Swift language itself I would focus on the following things:


  • Understanding the use of var and let properties. It's very simple once you get it and Xcode will keep you in correct form anyway 🙂.
  • Letting Swift infer as much information as possible. Instead of overly defining property types and other stuff, it's good practice to let Swift infer everything it can, unless you specifically want something else. So you should prefer let variable = 4.0 over let variable: Double = 4.0, because both will end up as Double types.
  • Learning optionals and their different manifestations. This can be a bit of nut to crack, but when you start to understand it, handling optionals will become second nature. It's important to learn why they're so important, how to properly wrap and mostly unwrap them, what the implications are to having very secure code, taking responsibility of said security implications and other stuff. Important terms here would be optional binding, optional chaining, implicitly versus explicitly unwrapped optionals, etc.
  • The increased emphasis on structs as an alternative to classes. I'm not personally so into structs, but I guess they have their audience.
  • Verbosity in naming functions and properties. You'll be more respected the more readable and descriptive your code is. For example, you would prefer func runAirConditioner() over func runAC().
  • Designing smarter functions. In addition to verbosity, you will want to be more efficient with your function definitions. You should look into specifying argument labels for parameters, omitting argument labels, defining default values for parameters, and if you really want to geek out, find out about variadic and in-out parameters. For example, a traditional function like func moveBalloonWithDelay(balloonNumber: Int, balloonPosition: CGFloat, delay: Double) would turn into moveBalloon(_ number: Int, to position: CGFloat, with delay: Double = 2.0), where number is omitting the label, position and delay are specifying it and delay is establishing a default in case no value is given.


Anyway, that's probably enough to get you started 😀. I would really recommend checking out this WWDC talk: https://developer.apple.com/videos/play/wwdc2016/404/. It goes into great detail about how to approach Swift as a newcomer.

Cocos2d to Spritekit
 
 
Q