中文文档
https://docs.godotengine.org/zh_CN/latest/about/introduction.html
基础类
register_core_types 先调用,主要进行setup函数
1, Object类
#define memnew(m_class) _post_initialize(new ("") m_class)
注意,重载void *operator new(size_t p_size, const char *p_description) 第一个参数是固定的,
Object类, Object对象提供反射和可编辑的属性,
CustomObject* pobj = memnew(CustomObject);
调用Object构造函数,加入 ObjectDB::add_instance当中去
然后调用_postinitialize
1) 绑定一个函数
ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &CustomObject::set_volume_db);
调用 call("set_volume_db",344.3);
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
不知道这样有什么好处?
2)类似信号信号槽
ADD_SIGNAL(MethodInfo("been_killed")); 后面带参数
执行
emit_signal(SNAME("been_killed"));
另一个类
pobj->connect("been_killed", callable_mp(this, &OtherObject::_bus_layout_changed));
还要自己写一个干嘛,不是有现存的吗
ObjectDB一个静态类
MethodBind抽像类,主要成员:
int method_id;
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
StringName name;
StringName instance_class;
Vector<Variant> default_arguments;
int default_argument_count = 0;
int argument_count = 0;
抽像方法:
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) = 0;
virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) = 0;
class MethodBindT : public MethodBind 一个实现
void (MB_T::*method)(P...); 一个函数指针
看其构造函数:主要是指导函数指针保存
MethodBindT(void (MB_T::*p_method)(P...)) {
method = p_method;
#ifdef DEBUG_METHODS_ENABLED
_generate_argument_types(sizeof...(P));
#endif
set_argument_count(sizeof...(P));
}
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error)实现主要是用函数指针执行
创建MethodBind的一个工厂函数:
template <class T, class... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
#else
MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method)));
#endif
a->set_instance_class(T::get_class_static());
return a;
}
用MethodBindT去创建一个对象
template <class N, class M>
static MethodBind *bind_method(N p_method_name, M p_method) {
MethodBind *bind = create_method_bind(p_method);
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, nullptr, 0); //use static function, much smaller binary usage
}
N 一般为MethodDefinition,M为函数指针
看一下MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount)
直接返回p_bind对象,主要是设置一些属性
2, RefCounted类
两个成员:
SafeRefCount refcount;
SafeRefCount refcount_init; 这个干什么用?
Ref<>自动进行计数计算
WeakRef : public RefCounted
SceneTreeTimer : public RefCounted
有一个timeout的信号绑定
3,
Node : public Object 所有的基类 场景 物体
这意味着将节点添加到场景树时,回调将使用以下顺序: _enter_tree 父母的, _enter_tree 孩子们, _ready 孩子们,最后 _ready 父级的(对于整个场景树递归)。
Viewport : public Node
Window : public Viewport
4,Resource : public RefCounted
Script : public Resource,不能实例化
Theme : public Resource
用于剥皮控件的主题。控件可以单独剥皮,但对于复杂的应用程序,只创建定义所有内容的全局主题更为实际。此主题可应用于任何 Control ;控件及其子控件将自动使用它。
主题资源也可以通过在 .theme 文件,
StyleBox : public Resource 用于为UI绘制样式化的框,主要成员 float margin[4]; 框内容的下边距,左边距,上边距
StyleBoxEmpty : public StyleBox 空样式框(不显示任何内容)
StyleBoxTexture : public StyleBox
基于纹理的九片 StyleBox ,以类似于 NinePatchRect . 这个样式框执行纹理的3×3缩放,其中只有中心单元格被完全拉伸。
StyleBoxFlat : public StyleBox
这个样式框可以用来实现各种外观,而不需要纹理。这些属性是可自定义的:
颜色
边框宽度(每个边框的单独宽度)
圆角(每个角的单独半径)
阴影
bg_color 样式框的背景色
border_blend 设置边框混合(值)
border_color 设置边框的颜色
border_width_bottom 设置边框宽度(值)
corner_detail 设置用于每个角点的顶点数量。值越大,角越圆,但需要更多的处理能力来计算,对于小于10的角半径,4-5应该足够。对于小于30的角半径,8-12应该足够
shadow_color 阴影的颜色
StyleBoxLine : public StyleBox 仅画一条直线,分垂直和水平,可指定颜色
String ResourceFormatLoaderText::get_resource_type(const String &p_path) const
5,消息循环
MainLoop类,管理成员 Ref<Script> initialize_script; 游戏主循环的抽象基类。
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
先找到类名,然后把字符串与数值放到一个map中
bool _idle ( float delta ) virtual
以自上次空闲帧以来的时间作为参数调用每个空闲帧(秒)。
如果实现,该方法必须返回布尔值。 true 结束主循环,而 false 让它进入下一帧。
SceneTree : public MainLoop 真正工作类
debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42)); 项目设置
bool debug_collisions_hint 设置调试冲突提示(值)
MultiplayerAPI multiplayer 设置多人游戏(值)
bool multiplayer_poll 设置多人投票(值)
NetworkedMultiplayerPeer network_peer 设置网络对等(值)
int get_frame ( ) const 返回当前帧号,即自应用程序启动以来的总帧计数。
6 setup 对系统进行了参数解析并初始化操作, 包括引擎内部对象的创建,根据参数判断是需要启动 “项目管理器”,“编辑器”,“游戏”,“场景”,“脚本”等
setup 之后,osx/win/x11 平台还有 需要执行 Main::setup2 这里初始化了音频/AR
消息处理函数
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
对于项目管理器:
Engine::get_singleton()->set_editor_hint(true);
ProjectManager *pmanager = memnew(ProjectManager);
ProgressDialog *progress_dialog = memnew(ProgressDialog);
pmanager->add_child(progress_dialog);
sml->get_root()->add_child(pmanager);
DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN);
Main::iteration()中
主要是 SceneTree::physics_process(double p_time) 看_quit变量
bool SceneTree::process(double p_time) 看_quit变量
7,对Timer分析一下
class Timer : public Node {
GDCLASS(Timer, Node);
double wait_time = 1.0;
bool one_shot = false;
bool autostart = false;
bool processing = false;
bool paused = false;
double time_left = -1.0;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
enum TimerProcessCallback {
TIMER_PROCESS_PHYSICS,
TIMER_PROCESS_IDLE,
};
void set_wait_time(double p_time);
double get_wait_time() const;
void set_one_shot(bool p_one_shot);
bool is_one_shot() const;
void set_autostart(bool p_start);
bool has_autostart() const;
void start(double p_time = -1);
void stop();
void set_paused(bool p_paused);
bool is_paused() const;
bool is_stopped() const;
double get_time_left() const;
void set_timer_process_callback(TimerProcessCallback p_callback);
TimerProcessCallback get_timer_process_callback() const;
Timer();
private:
TimerProcessCallback timer_process_callback = TIMER_PROCESS_IDLE;
void _set_process(bool p_process, bool p_force = false);
};
VARIANT_ENUM_CAST(Timer::TimerProcessCallback);
宏#define GDCLASS(m_class, m_inherits)
主要是实现mutable StringName _class_name;
String get_class()
String get_class_static()
String get_parent_class_static()
static void initialize_class()
virtual void _notificationv(int p_notification, bool p_reversed) override
#define VARIANT_ENUM_CAST(m_enum)
定义几个静态函数,cast,convert,encode
实现main\timer.cpp
void Timer::_bind_methods() { 静态函数
ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);
ClassDB::bind_method(D_METHOD("get_wait_time"), &Timer::get_wait_time);
ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Timer::set_one_shot);
ClassDB::bind_method(D_METHOD("is_one_shot"), &Timer::is_one_shot);
ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &Timer::set_autostart);
ClassDB::bind_method(D_METHOD("has_autostart"), &Timer::has_autostart);
ClassDB::bind_method(D_METHOD("start", "time_sec"), &Timer::start, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("stop"), &Timer::stop);
ClassDB::bind_method(D_METHOD("set_paused", "paused"), &Timer::set_paused);
ClassDB::bind_method(D_METHOD("is_paused"), &Timer::is_paused);
ClassDB::bind_method(D_METHOD("is_stopped"), &Timer::is_stopped);
ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left);
ClassDB::bind_method(D_METHOD("set_timer_process_callback", "callback"), &Timer::set_timer_process_callback);
ClassDB::bind_method(D_METHOD("get_timer_process_callback"), &Timer::get_timer_process_callback);
ADD_SIGNAL(MethodInfo("timeout"));
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_RANGE, "0.001,4096,0.001,or_greater,exp"), "set_wait_time", "get_wait_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paused", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_time_left");
BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
}
D_METHOD是一组函数,主要是MethodDefinition md对象
ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);这样做的目的后就可以这样调用
pobj->call("set_wait_time", 344.3);
真正执行的,是这样的
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
if (method) {
ret = method->call(this, p_args, p_argcount, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}
ADD_SIGNAL(MethodInfo("timeout")); 本类中增加一个信号
执行这个信号:emit_signal(SNAME("timeout"));
这样做相当Timer类提供一个timeout的抽像反接口,使用者只需要这样做
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
就可以收到Timer的timeout事件消息,通过信号的方式可以解耦,就类与类之间的通信方式之一。
这里说明:接口一般是被调用的,是一种被动的;反接口可以通知消息一种,是主动的消息,如果Timer内部自己调用信号
信号定义与执行在同一个类中?
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback");
这个控件的属性信息,可以通过面板来设置,或绑定
注意,函数一定要在前面通过ClassDB::bind_method绑定,不然没有效果
后面调用可以是这样:
StringName strName("autostart");
pobj->set(strName, Variant(1));
Variant value = pobj->get(strName);
BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
常量与字符串的对应关系
8,增加脚本数据类型
参考ClassDB::bind_method(D_METHOD("get_ids"), &RDUniform::get_ids);
static const _bit _type_list[]
void register_variant_methods()
method_ptrcall.h这个文件看看
是Object只需要registryclass
如果是自定义类型就要在这里加
9,消息循环
函数GetMessage不一样的是,GetMessage:从系统获取消息,将消息从系统中移除,属于阻塞函数。当系统无消息时,GetMessage会等待下一条消息。
函数PeekMesssge是以查看的方式从系统中获取消息,可以不将消息从系统中移除,是非阻塞函数;当系统无消息时,返回FALSE,继续执行后续代码。
常见消息循环
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
godot的消息循环
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
窗口函数
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
如处理WM_CHAR,会记录下来
key_event_buffer[key_event_pos++] = ke;
在函数DisplayServerWindows::_process_key_events() 处理
生成InputEventKey对象,交给Input::get_singleton()->parse_input_event(k);
真正工作函数:
Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated)
交给
if (event_dispatch_function) {
event_dispatch_function(p_event);
}
实际上:
DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
然后给:
void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error)
Viewport::_gui_input_event(Ref<InputEvent> p_event)
if (mb->is_pressed(){
找到控件
gui.mouse_focus = gui_find_control(pos);
}else
{
//按下鼠标松开的时候,触发 事件,
}
鼠标事件;
Input::get_singleton()->parse_input_event(mb);
bool Main::iteration()函数
11,配置定义
ProjectSettings : public Object
globals = memnew(ProjectSettings);
ProjectSettings::ProjectSettings() {
singleton = this;
}
static ProjectSettings *get_singleton();
这种方式访问
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed
12,第三方库说明:
BulletPhysics是一个跨平台的开源物理引擎,也是三大主流3D物理引擎之一,支持三维碰撞检测、柔体动力学和刚体动力学,多用于游戏开发和电影制作中。
embree光线追踪
enet网络库
etc2comp 图像压缩工具
freetype可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,
glad
jpeg-compressor 图像压缩和转换为JPEG格式
libogg 是一个 C++ 库,用来处理 Ogg 多流传输格式。它被设计为独立的解码器,是一个线程安全的解码器。
libpng
libOpus是一款完全开放、免版税、功能多样的音频编解码器
zstd是Facebook在2016年开源的新无损压缩算法,优点是压缩率和压缩/解压缩性能都很突出。
Xattlas是一个小型C++11库,没有外部依赖项,可以生成适合烘焙光照贴图或纹理绘制的唯一纹理坐标。
Wslay 是一个用 C 语言实现的 WebSocket 开发库。
vhacd 将 3D 曲面分解为一组"靠近"凸部件
tinyexr, 小型OpenEXR图像加载程序/保护程序库 小型OpenEXR图像库。 tinyexr 是只加载和保存 OpenEXR(.exr) 映像的小型头文件库
RecastNavigation是一款非常强大的寻路系统,被广泛的应用于各大游戏引擎中
pvrtccompressor 压缩器
PCRE(Perl Compatible Regular Expressions)是一个Perl库,使用boost::regex编译时需要3秒,而使用pcre不到1秒,PCRE是用C语言实现的,其C++实现版本是PCRE++
godot开发 QQ 35484348