Skip to content

Latest commit

 

History

History
180 lines (133 loc) · 5.25 KB

File metadata and controls

180 lines (133 loc) · 5.25 KB

Custom Layers

At some point a modder may want to create a custom layer for their mod, for one reason or another.

Creating a new scene is easy. You must create a new class extending cocos2d:::CCLayer, and add additional UI (such as buttons, popups, or even a level) by overriding the the *::init function.

class MyVeryOriginalLayer : public CCLayer {
protected:
    bool init() override {

        if (!CCLayer::init()) {
            // Something very bad happened
            return false;
        }

        log::info("Hi from my very original layer");
        return true;
    }

public:
    static MyVeryOriginalLayer* create() {
        auto ret = new MyVeryOriginalLayer;
        if (ret->init()) {
            ret->autorelease();
            return ret;
        }
        delete ret;
        return nullptr;
    }
}

This code will create a new layer called MyVeryOriginalLayer. When we start up the game, we will not see the layer as we do transition to it. Calling MyVeryOriginalLayer::create() will not transition to the layer, as it only creates it, not replaces the current layer. To be able to transition to the layer, we can use switchToScene(layer). We can create a static function to easily create and switch to the scene:

static MyVeryOriginalLayer* scene() {
    auto layer = MyVeryOriginalLayer::create();
    switchToScene(layer);
    return layer;
}

UI

Running this code and calling MyVeryOriginalLayer::scene() will transition the current scene to MyVeryOriginalLayer, however it is currently very barren. Geode provides utility functions to create background and side art.

#include <Geode/ui/General.hpp>

bool init() override {
    log::info("Hi from my very original layer");

    // Create a new menu. UI Buttons should be added to here.
    auto menu = CCMenu::create();

    // Using geode's built in utils for creating side art and background makes it easier for other mods to modify & change them.
    // It is recommended to use these instead of manually adding them some other way.

    // Add side art to the layer
    geode::addSideArt(this, SideArt::All, SideArtStyle::Layer);

    // And a background to the layer
    auto background = geode::createLayerBG();
    background->setID("background");
    this->addChild(background);	
    return true;
}

The rest of the buttons and UI can be created the same way you would in a hook.

⚠️ Button elements must be in CCMenu object!

Back button

Now the biggest problem with this layer is that you are stuck in it. To go back you would want to create a button whose callback transitions to another scene.

bool init() override {
    // Create a back button with the back button sprites
    auto backBtn = CCMenuItemSpriteExtra::create(
        CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"),
        this,
        menu_selector(MyVeryOriginalLayer::onBack)
    );

    // Not adding this function will disable keyBackClicked from being called.
    // This makes it impossible to exit levels with the backspace key.
    this->setKeypadEnabled(true);

    // Add a back button the the top-left corner of the screen with a small offset.
    menu->addChildAtPosition(backBtn, Anchor::TopLeft, {25, -25});
    this->addChild(menu);
    return true;
}

// This function is called when the escape key is pressed!
void keyBackClicked() override {
    this->onBack(nullptr);
}

void onBack(CCObject* sender) {
    CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene()));
}

ℹ️ You can also create a back button with GameToolbox::addBackButton

⚠️ Pressing escape will not transition the layer back unless you override keyBackClicked()!

Example

This code will transition to the MyVeryOriginalLayer when clicking the on more games button.

#include <Geode/Geode.hpp>
#include <Geode/ui/General.hpp>
#include <Geode/modify/MenuLayer.hpp>
using namespace geode::prelude;

class MyVeryOriginalLayer : public CCLayer {
protected:
    bool init() override {
        log::info("Hi from my very original layer");
        
        // Create a new menu. UI elemnts should be added to here!
        menu = CCMenu::create();
        
        // Add side art to the layer
        addSideArt(this, SideArt::All, SideArtStyle::Layer);
        
        // And a background to the layer
        auto background = createLayerBG();
        background->setID("background");
        this->addChild(background);	
    return true;
    }

    // This function is called when the escape key is pressed!
    void keyBackClicked() override {
        this->onBack(nullptr);
    }

public:
    static MyVeryOriginalLayer* create() {
        auto ret = new MyVeryOriginalLayer;
        if (ret->init()) {
            ret->autorelease();
            return ret;
        }
        CC_SAFE_DELETE(ret);
        return nullptr;
    }

    static MyVeryOriginalLayer* MyVeryOriginalLayer::scene() {
        auto layer = MyVeryOriginalLayer::create();
        switchToScene(layer);
        return layer;
    }


    void onBack(CCObject* sender) {
        CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene()));
    }

}

class $modify(MenuLayer) {
    void onMoreGames(CCObject* target) {
        MyVeryOriginalLayer::scene();
    }
};