Skip to content

SpriteKit to Axmol

Dani Alias edited this page Mar 15, 2024 · 33 revisions

Converting SpriteKit games to Axmol Engine

For the main part, SpriteKit and Axmol Engine are almost identical, so a game conversion from iOS to Android is not a hard task. Please mind there are some names changes (i.e. alpha -> opacity, zPosition -> zOrder, etc.), and also take in account the following indications.

Important: Add your code to the Source folder and your assets to the Content folder. Do not forget to update CMakeLists.txt when adding new classes. All the code in this file are shown with USING_NS_AX active. auto will choose the correct variable or pointer type for you.

Sprites and positions

  • Similarly to SpriteKit, setting your screen resolution and your ResolutionPolicy inside AppDelegate is the first step you should take.

  • SpriteKit counts in points, Axmol in pixels. Convert your position and size numbers for Axmol based on your AppDelegate resolutions. In SpriteKit, depending on the scaling ratio, 1 point correspond to 1 pixel on non-retina screens, to 2 pixels on screens with a 2x scaling, and to 3 pixels in screens with 3x scaling.

  • In Axmol Engine, when setting a children sprite in a parent sprite, it will appear by default to the bottom left corner instead to the anchor point (usually the center of the sprite). If you don’t want to modify the anchor points, use the the following code in order to find the parent center to replicate the SpriteKit behaviour.

    parent->getContentSize().width / 2
    parent->getContentSize().height / 2
    
  • zPosition in SpriteKit is always relative to the parent. In Axmol, the default z-ordering is also relative to the parent (local Z ordering), and can be either set when adding a node to a parent through Node::addChild methods, or explicitly set on the child node via Node::setLocalZOrder. Axmol also supports global Z ordering for nodes, which dictates the Z position in the entire scene. Global Z order can only be set on a node via Node::setGlobalZOrder.

  • SpriteKit counts angles in counter-clockwise radians and Axmol in clockwise degrees. You can use AX_RADIANS_TO_DEGREES() (also AX_DEGREES_TO_RADIANS()), and don’t forget to invert the signs.

  • centerRect in SpriteKit doesn’t work with Sprite nodes in Axmol. You will need to set a ui::Scale9Sprite and setCapInsets (being careful with the points to pixel conversions).

Actions

  • In SpriteKit, easings are modifiers of certain actions. In Axmol Engine, easings have their own actions. First create the action, and then the easing for that action. It will create a new action.

    auto rotateLeft = RotateTo::create(6.0f, 25.0f);  // Action to ease
    auto easeRotateLeft = EaseInOut::create(rotateLeft, 3.0f);  // Easing
    
  • The equivalent SpriteKit runBlock action in Axmol is CallFunc:

    auto runBlockEquivalent = CallFunc::create([=](){
      // Do something
    });
    
  • For opacity fading actions (FadeIn, FadeOut, FadeTo) to affect the children of a node, you will need to set setCascadeOpacityEnabled(true).

  • Is not possible to use the same action with several nodes. You will have to duplicate it with another name, or use clone().

Assets

  • There is no .xcassets folder in Axmol. For setting paths for your folders inside the Contents folder, please use:

    FileUtils::getInstance()->addSearchPath(“folder”);

  • For the same reason, be careful with the extensions of the files. You will need to explicitely indicate them.

  • For preloading heavy fonts (i.e. Japanese), you can use:

    Label::createWithTTF("", “fontName.ttf”, 24);
    
  • For preloading sound effects, you can use:

    AudioEngine::preload(“sound.wav", [](bool success){
       AXLOG("Audio preloaded");
    });
    

Touch

  • SpriteKit will respond to any touch from any node in the screen. In Axmol Engine you will have to set a callback for all the nodes you want to react to the touch. For example, if you set a callback to this, it will react to touch, but other nodes will not. In order to do that, you will have to set a new callback for them, in the same way than you did for this.

  • Be aware that a lot of UI items in Axmol have a callback option incorporated that may make your life easier.

  • There is no nodesAtPoint function in Axmol Engine. This code works in an equivalent way to SpriteKit nodesAtPoint, but you can use any solution of your own:

    Node *parentNode = event->getCurrentTarget();
    Point touchPosition = parentNode->convertTouchToNodeSpace(touches.at(0));
    for(const auto& node : parentNode->getChildren()) {
       if (node->getBoundingBox().containsPoint(touchPosition)) {
           if (node->getName() == “My node name”)
           {
            // Do something
           }
        }
     }
    

Data & others

  • enumerateChildren behavior is different to SpriteKit's enumerateChildNodesWithName. To make operations over groups of children, it's recommended to get them in a std::vector with utils::findChildren and then do the operations.

  • UserDefaults is almost identical to NSUserDefaults, but it's updated with flush().

  • Reading .plist files is not officially supported by Axmol Engine, but you can do it anyways with FileUtils and getValueMapFromFile.

  • For concatenating strings, fmt::format is the most similar to NSString stringWithFormat.

  • NSLocalizedString doesn’t exist in Axmol. You can program your own solution, but checking our Made in Axmol page for user created solutions may be a good idea. It may help for rendering Arabic text as well, for example.

  • If you are converting your app to Android, in order to access the device capabilities and libraries you will have to use JNI. This includes vibration, in-app purchases and any other library specific for Android. Again, Made in Axmol page may help.

Memory management


This list is not comprehensive by any means, but it may be a good start point. If you have more questions, please check our FAQ, our Tutorials page and GitHub discussions.