You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Godot C++ GDExtension:实现仅在游戏运行时执行_process/_ready中的打印逻辑

Godot C++ GDExtension:实现仅在游戏运行时执行_process/_ready中的打印逻辑

嗨,我完全懂你的困扰——每次写_ready或者_process都要手动加编辑器环境判断,确实有点繁琐。这里有两个更优雅的解决方案,帮你摆脱重复代码的烦恼:

方案1:封装一个带编辑器判断的通用基类

最一劳永逸的办法是创建一个基类,把is_editor_hint()的判断逻辑封装进去,之后所有自定义节点都继承这个基类,就不用每次重复写判断了。

首先创建基类的头文件EditorSafeNode.h

#ifndef EDITOR_SAFE_NODE_H
#define EDITOR_SAFE_NODE_H

#include <godot_cpp/classes/character_body2d.hpp>
#include <godot_cpp/classes/engine.hpp>

namespace godot {

class EditorSafeNode : public CharacterBody2D {
    GDCLASS(EditorSafeNode, CharacterBody2D);

protected:
    static void _bind_methods() {}

    // 子类只需要重写这两个方法,代替原来的_ready和_process
    virtual void _ready_runtime() {}
    virtual void _process_runtime(double delta) {}

public:
    EditorSafeNode() = default;
    ~EditorSafeNode() = default;

    void _ready() override {
        if (!Engine::get_singleton()->is_editor_hint()) {
            _ready_runtime();
        }
    }

    void _process(double delta) override {
        if (!Engine::get_singleton()->is_editor_hint()) {
            _process_runtime(delta);
        }
    }
};

} // namespace godot

#endif

接下来修改你的Personnage类,让它继承这个基类,并重写对应的_runtime方法:

Personnage.h修改后:

#ifndef PERSONNAGE_H
#define PERSONNAGE_H

#include "EditorSafeNode.h" // 引入封装好的基类

namespace godot {

    class Personnage : public EditorSafeNode { // 替换原来的CharacterBody2D继承
        GDCLASS(Personnage, EditorSafeNode);
    
    protected:
        static void _bind_methods() {}

        // 重写基类的运行时专属方法
        void _ready_runtime() override;
        void _process_runtime(double delta) override;
    
    public:
        Personnage();
        ~Personnage();
    };

}

#endif

Personnage.cpp修改后:

#include "Personnage.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

using namespace godot;

Personnage::Personnage() {
    UtilityFunctions::print("Bonjour depuis GDExtension avec C++ !");
}

Personnage::~Personnage() {}

void Personnage::_ready_runtime() { // 代替原来的_ready方法
    UtilityFunctions::print("fonction Start()");
}

void Personnage::_process_runtime(double delta) { // 代替原来的_process方法
    UtilityFunctions::print("fonction Update()");
}

这样以后所有需要避免编辑器执行逻辑的节点,都可以直接继承EditorSafeNode,重写对应的_runtime方法就行,再也不用写重复的判断代码了。

方案2:用宏定义简化判断逻辑

如果你不想重构基类,也可以定义一个宏,把判断逻辑包装起来,写代码时会简洁很多:

你可以把这个宏放在项目的公共头文件里(比如一个Common.h),方便所有文件引用:

#define RUN_IN_RUNTIME(code) if (!Engine::get_singleton()->is_editor_hint()) { code; }

然后在你的方法里直接使用这个宏:

void Personnage::_ready(){
    RUN_IN_RUNTIME(
        UtilityFunctions::print("fonction Start()");
        // 这里可以添加其他仅在运行时执行的代码
    )
}

void Personnage::_process(double delta) {
    RUN_IN_RUNTIME(
        UtilityFunctions::print("fonction Update()");
    )
}

这个方案不用改变类的继承关系,适合快速简化现有代码的场景。

小补充:为什么编辑器会执行这些方法?

其实这是Godot的正常行为——编辑器在预览节点、刷新场景时,会实例化节点并调用_ready等生命周期方法,所以你的代码会在编辑器环境下被触发。用is_editor_hint()区分环境也是官方推荐的标准做法哦。

备注:内容来源于stack exchange,提问作者Firrow

火山引擎 最新活动