当前位置: 首页 > news >正文

Godot4.x的整体架构图解析-源码阅读

Godot整体架构图解析

阅读背景

Godot的架构图,官网中自有记载,比如4.x版本的Godot的架构图,如下所示:

上述这个构架图初次看的时候是感觉有些混乱,因为按照Godot开发文档来看,有些箭头是代表调用,有些代表继承,有些又代表组合…但是图中却都用箭头代表了,让人很容易混淆。

为了更好的理解Godot开发,利于自己理解Godot的类,特别是那些常见的类,比如Node、Node2D等,这个文章将参考Godot的开发文档绘制出Godot架构的UML类图。

Godot架构的UML类图

在这里插入图片描述

特殊关系的说明

从Godot编辑器上,有时很难获取这些类之间的关系,十分容易搞乱之间的对象关系。

因此下述将基于Godot4.4.1-stable的github源码以及个人理解,阐述其中一些容易混淆的关系。

Variant与Object:关联
  • 首先查看core\variant\variant.h头文件
    • 该头文件主要定义了Variant类声明,关键代码如下所示

      class Variant {// 其他
      private:// Variant takes 24 bytes when real_t is float, and 40 bytes if double.// It only allocates extra memory for AABB/Transform2D (24, 48 if double),// Basis/Transform3D (48, 96 if double), Projection (64, 128 if double),// and PackedArray/Array/Dictionary (platform-dependent).Type type = NIL;union {bool _bool;int64_t _int;double _float;Transform2D *_transform2d;::AABB *_aabb;Basis *_basis;Transform3D *_transform3d;Projection *_projection;PackedArrayRefBase *packed_array;void *_ptr; //generic pointeruint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]{ 0 };} _data alignas(8);// 其他struct ObjData {ObjectID id;Object *obj = nullptr;void ref(const ObjData &p_from);void ref_pointer(Object *p_object);void ref_pointer(RefCounted *p_object);void unref();template <typename T>_ALWAYS_INLINE_ void ref(const Ref<T> &p_from) {if (p_from.is_valid()) {ref(ObjData{ p_from->get_instance_id(), p_from.ptr() });} else {unref();}}};
      }
      
    • 回答疑问:Godot编辑器中对Variant的介绍是20字节的空间占用,那么实际上是多少呢?

      • 回答:Variant的内存占用是sizeof(Variant)=(8+4*sizeof(real_t)),因此如果real_t是float,那么Variant内存占用是24字节
        • Type type: 4bytes
        • 补齐8字节的空间: 4bytes
        • _data空间: 16bytes
    • 这里可以看出:Variant就是一个可以代表/指代Godot用到的所有数据类型的一个通用对象,那么Object在哪儿呢?

  • 再来看看core\variant\variant.cpp源文件
    • 重点关注Variant(Object* )初始化实现:
      Variant::Variant(const Object *p_object) :type(OBJECT) {_get_obj() = ObjData();_get_obj().ref_pointer(const_cast<Object *>(p_object));
      }
      Variant::ObjData &Variant::_get_obj() {// _data._mem就是包含了Object对象指针的结构体return *reinterpret_cast<ObjData *>(&_data._mem[0]);
      }
      void Variant::ObjData::ref_pointer(Object *p_object) {// Mirrors Ref::ref_pointer in refcounted.hif (p_object == obj) {return;}ObjData cleanup_ref = *this;if (p_object) {*this = ObjData{ p_object->get_instance_id(), p_object };if (p_object->is_ref_counted()) {RefCounted *reference = static_cast<RefCounted *>(p_object);if (!reference->init_ref()) {*this = ObjData();}}} else {*this = ObjData();}cleanup_ref.unref();
      }
    • 因此,很容易看出_data._mem就是包含了Object对象指针的结构体,因此Variant关联了Object。
Scene中的模块与Server中的模块:依赖
  • 我们以Sprite2D模块的绘图进行举例说明,首先追踪路径
    • 1、传入纹理
      void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {if (p_texture == texture) {return;}if (texture.is_valid()) {texture->disconnect_changed(callable_mp(this, &Sprite2D::_texture_changed));}texture = p_texture;if (texture.is_valid()) {texture->connect_changed(callable_mp(this, &Sprite2D::_texture_changed));}queue_redraw(); // 2、纹理改变,入队重绘命令emit_signal(SceneStringName(texture_changed));item_rect_changed();
      }
      
    • 2、纹理改变,入队重绘命令
      void CanvasItem::queue_redraw() {ERR_THREAD_GUARD; // Calling from thread is safe.if (!is_inside_tree()) {return;}if (pending_update) {return;}pending_update = true;callable_mp(this, &CanvasItem::_redraw_callback).call_deferred(); // 3、
      }
      
      • 3、进入画布基类的重绘命令
      void CanvasItem::_redraw_callback() {if (!is_inside_tree()) {pending_update = false;return;}RenderingServer::get_singleton()->canvas_item_clear(get_canvas_item());//todo updating = true - only allow drawing hereif (is_visible_in_tree()) {drawing = true;current_item_drawn = this;notification(NOTIFICATION_DRAW);emit_signal(SceneStringName(draw));GDVIRTUAL_CALL(_draw);current_item_drawn = nullptr;drawing = false;}//todo updating = falsepending_update = false; // don't change to false until finished drawing (avoid recursive update)
      }
      
      • 3.1: 调用了RenderingServer执行清楚老的纹理
        RenderingServer::get_singleton()->canvas_item_clear(get_canvas_item());
        
      • 3.2:发出NOTIFICATION_DRAW,执行Sprite2D的_notification
        void Sprite2D::_notification(int p_what) {switch (p_what) {case NOTIFICATION_DRAW: {if (texture.is_null()) {return;}RID ci = get_canvas_item();Rect2 src_rect, dst_rect;bool filter_clip_enabled;_get_rects(src_rect, dst_rect, filter_clip_enabled);texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip_enabled); // 下一步} break;}
        }
        
      • 3.3:Texture2D的绘制,调用了RenderingServer执行纹理的绘制
        void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {if (GDVIRTUAL_CALL(_draw_rect_region, p_canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv)) {return;}RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, p_clip_uv);
        }
        
  • 总结:因此我们可以看到Sprite2D模块跟RenderinngServer之间基本上是依赖关系,Sprite2D依赖RenderingServer进行纹理的绘制。

总结

  • 上述的架构图上没有包含所有的Class,只列举了主要的部分。
  • Godot官网的架构图是比较老的版本的,因此有的模块已经不存在或者名字发生了改变。
http://www.dtcms.com/a/513221.html

相关文章:

  • 广州短视频网站开发服装网站设计
  • 网站自动弹窗代码郑州做网页的公司
  • 做膜结构那个网站好网站切换
  • 怎么用自助网站宁波seo怎么推广
  • 网站排名alexa常用网站有哪些
  • 【DeepSeek新开源】DeepSeek-OCR如何用“视觉压缩”革新长文本处理
  • 反向代理应用:frp
  • SetConsoleCursorPosition函数的用法
  • 一个服务器可以放多少个网站个性化网站建设开发
  • 赣州建站服务山东省工程造价信息网官网
  • 重庆定制网站建设写一个app多少钱
  • 如何做公司宣传网站简单网页制作教程视频
  • @JvmStatic 的作用
  • 单位门户网站功能免费做网站怎么做网站
  • 黄石网站建设定做网站建设公司专业网站科技开发
  • FreeRTOS任务状态获取
  • 南城网站优化公司查询网站流量排名
  • 网站注册可以免费吗开发工具箱
  • 寮步镇网站建设网站版面设计流程包括哪些
  • 做海报用什么网站网络公司给销售公司做网站
  • EPLAN 保姆级入门教学
  • 动态规划经典问题学习笔记
  • java重构旧代码有哪些注意的点
  • 湛江廉江网站建设WordPress留言表单仿制
  • 如何优化一个网站案例网站模板_案例网
  • 青岛开发网站深圳福田区房子价格
  • JeecgBoot积木报表综合漏洞检测工具
  • 南召微网站开发免费开发游戏的软件
  • 寻找网站建设 网站外包wordpress评论页面美化
  • 营销网站建设企业筑人才官网