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

Godot 4 源码分析 - 碰撞 在真实场景中,A、B都占据相应的空间位置(3D)或平面位置(2D),在运行过程中,A、B至少有一个能动,它们的相对位置可能会变化,在某个时刻会有交叠。具体而言,一个节点的Layer值必须包含在另一个节点的Mask值中,同时另一个节点的Layer值必须包含在该节点的Mask值中。Layer与Mask应该都是32位整数,对象A有Layer与Mask属性,对象B也有Layer与Mask属性。对于敌人对象之间,可将它们分配到相同的碰撞图层并设置相应的碰撞掩码,以确保它们不会互相碰撞。果然,与猜测的一致。 阅读详情

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 pointer
              uint8_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.h
          if (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 here
          if (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 = false
          pending_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官网的架构图是比较老的版本的,因此有的模块已经不存在或者名字发生了改变。
Godot 4 源码分析 - 增加管道通信 学习研究Godot 4,很爽,虽然很庞杂,但相对于自己的水平来说,很强大,尤其是vulkan这块直接打包可用,省得自己从头琢磨。一点一点地消化、优化与完善,最终才能成为自己的。这段时间就在Godot的基础上,增加管道通信,实现Godot与本机已有程序进行通信,以备后续的无缝集成整合。其实,Godot支持各种网络通信,支持UDP、TCP等。为什么非要实现管道通信,本质上还是想看看改造效果。最终目标是实现Godot软件与自己的DrGraph软件的管道通信。 阅读详情

相关推荐

godot引擎c++源码深度解析系列一

许久没有使用c++开发过项目了,如果按照此时单位的入职要求,必须拥有项目经验的话,那我就得回到十多年前,大学的时代,哪个时候真好,电脑没有这么普及,手机没有这么智能,网络没有这么发达,信息传播没有此时的快,哪个年代,5毛钱一份的报纸或许真的很好。入职it这个行业以来,想必很多的同行,前辈们,都知道,软件开发唯一的要求,实践能力必须很强,不亲自实操,你永远不知道代码里有多少个坑,同样的一段代码,在A电脑能运行,在B电脑就运行不了,这就是环境对此的影响。

温情亿度网络科技 2842

Godot 4 源码分析 - 获取属性信息

在管道通信基础上,可进行宿主程序与Godot的双向通信。先拿属性信息试试手。

drgraph的博客 1107

Godot 4 源码分析 - 初探

准备研究GoDot 4源码。

drgraph的博客 3668

Godot 4 源码分析 - 练手 - 和谐共生

今天看到一个微信视频,和谐共生,大概效果如下研究这么长时间的Godot,今天试试能否实现上述效果粗看一下,这个效果实现分几步:1. 画圆,并确定多个圆的位置规律2. 动点,并确定各动点的运动规律3. 综合调试。

drgraph的博客 1432

godot engine 源码类图

Godot游戏引擎在国外与unity,Unreal几乎并列。而且完全开源,没有license fee。 个人最关注其editor自身也是使用引擎的ui 编写(可以看作引擎的一个开源应用),本身也完全开源(cocos creator 的editor代码不开源)。 初步浏览了开源游戏引擎godot,准备对其源码进行深入学习。 下面首先从其官方文档中提取了代码架构及主要代码的类继承图,方便对引擎代码的整体了解。 Godot Architecture diagram(Godot架构图) The fo.

vidar_li的专栏 2502

Godot 4 源码分析 - 动态导入图片文件

用Godot 4尝试编一个电子书软件,初步效果已经出来,并且通过管道通信接口可以获取、设置属性、调用函数,貌似能处理各种事宜了。其实不然,外因通过内因起作用,如果没把里面搞明白,功能没有开放出来,则有些需求就不能实现。比如,现在想动态加载新的图书,这就是一个实际需求。如果每一本电子书,都需要导出一次,那这个软件就太不通用了。直接加载另一图片,结果不成功这就得研究一下了。

drgraph的博客 2761

Godot 4 源码分析 - 命令行参数

粗看Godot 4的源码,稍微调试一下,发现一大堆的命令行参数。在widechar_main中Main::setup中,各命令行参数加入到List<Stirng> args中,并通过OS::get_singleton()->get_cmdline_platform_args()取得平台相关命令行参数,然后args逐项处理。

drgraph的博客 2107

开源游戏引擎源码阅读(一)

开发一个大型项目诸如游戏引擎之前,都会借鉴已有的开源模型。先尝试修改一些代码并重新编译,这对学习和理解一个大型项目的整体流程和细节实现是非常有益的。这里我们先大致浏览一下最近很火的Godot的源码一级目录然后我们就可以根据具体需求,进入相应的目录进行阅读。

qq_73990157的博客 1110

Material Maker 的 Normal Map 节点:从高度图生成法线贴图,并理解 Material 专属法线格式

本文基于 [Normal Map 节点官方文档](https://link.gitcode.com/i/4f5957ebaf2b94f2476160ed973eb732) 与节点定义文件 [normal_map.mmg](https://link.gitcode.com/i/3150335d929412b414a7e67dc57d4047),讲解 Material Maker 中 **Normal

gitblog_00852的博客 151

Godot 4 源码分析 - 获取脚本

继续测试自定义结构发送Book.script.TAutoTurn,结果返回为对象: <GDScript#-9223372010833313372>279. 16:18:07:517 > 【主线程】 > [Pipe.发送] > 发送数据中内容[DrGraph.87: Request - wait 1000 ms]:[int]类型 > 值 = 2[UnicodeString]类型 > 值 = Book.script[UnicodeString]类型 > 值 = TAutoTurn。

drgraph的博客 1525

Godot 源码分析(二):Vulkan 渲染后端支持全景

Godot 4.0 起把图形 API 从 OpenGL ES 3.0 升级为,并保留了对三个后端。在深入 Godot 源码之前,先把这四个 API 放在一起做一个系统对比,搞清楚"为什么 Vulkan 是第一选择",而不是其他三个。

大坡3D软件开发 317

godot引擎c++源码深度解析系列二

就这样就实现了文本框,输入框和按钮的实现,以及对应的事件,后面还有很多的功能,都需要慢慢的研究。这个里面需要研究以下c++的控件页面的开发和熟悉,毕竟好久没有使用c++了,先来看以下代码吧。记录每次研究源码的突破,今天已经将打字练习的功能完成了一个基本模型,先来看下运行效果。下一步开始研究加工车间的面板,虽有难度,但也有挑战。

温情亿度网络科技 1149

Godot节点详解[项目源码]

本文详细介绍了Godot引擎中的多种节点类型及其功能,包括RigidBody2D、Button、CanvasItem、Node2D、Sprite2D、AnimatedSprite2D、Body2D类节点、Area2D、RayCast2D、ShapeCast2D、TileMap、Control节点、Container节点以及常用Control控件等。内容涵盖了节点的继承关系、功能描述、初学者需要掌握的知识点以及实际应用示例。此外,还补充了Timer、AnimationPlayer和CanvasLayer三种节点的使用方法。文章适合Godot初学者和游戏开发者参考,帮助理解和使用Godot引擎中的各种节点。

Godot 4 源码分析 - Project Manager

我之前一直用RAD开发Windows程序,哪里还见过这种自己从头搭起来的,比如create_project_item_control处理各工程项。_open_selected_projects_ask,其实最终调用_open_selected_projects。除去界面各控件外,就是加载工程项_load_recent_projects(),直接处理。至于其中的循环,因为在ProjectManager构造函数中,已设置。当然,还有ENTER键会直接调用_open_selected_projects_ask。

drgraph的博客 2940

别再问“这游戏啥引擎做的”了,手把手教你用SteamDB一键查询(附实战案例)

本文详细介绍了如何使用SteamDB一键查询游戏引擎信息,包括Unity 3D、Unreal Engine等热门引擎的识别方法。通过实战案例和高级查询技巧,帮助玩家快速获取游戏技术底细,优化游戏体验和兼容性分析。

weixin_31412781的博客 819

工业组态软件Intouch(单机版)入门{第一篇}

通俗来讲Intouch就是一个能将PLC里的信号显示在画面上的软件。

weixin_41571357的博客 1万+

Godot引擎C#开发学习笔记(三)源码结构

代码版本4.1.0。

Jsy000的专栏 1700

电子技术——共栅和共源共栅放大器的高频响应

我们在之前学过无论是是CS放大器还是CE放大器,都可以看做是一个带通(IC低通)滤波器。在高频处的响应收到输入电容 $C_{in}$ 的限制(主要是米勒效应)。因此,若想扩大放大器的带宽,我们必须减小米勒效应,一种方案就是共栅放大器。

jiahonghao2002的博客 4183

Blender Datasmith导出插件:3步实现Blender到虚幻引擎的无缝转换

还在为Blender到虚幻引擎的模型转换而烦恼?材质丢失、模型变形、光照错位等问题让无数3D创作者头疼不已。Blender Datasmith导出插件正是解决这一痛点的完美方案,让您的创意在不同平台间自由流动,实现真正的无缝创作体验。 ## 🚀 为什么选择Datasmith导出插件? | 传统转换痛点 | Datasmith插件优势 | |--------------|-----------

gitblog_00406的博客 669

echarts实现3D地图——map3D

【代码】echarts实现3D地图——map3D。

xiaoququ的博客 7322

时间序列:R语言ARMA-GARCH模型

ARMA: #读入数据,并绘制时序图 d<-read.table("C:/Users/haha/Desktop/R/zuoye/1.txt") x<-ts(log(d),start = 1) 1: x的时间序列图: x<-ts(log(d),start = 1) plot(x) 2: 从上图可以看出x.dif序列值在0的附近波动,没...

1万+

Godot:10万星开源游戏引擎的硬核解析

本文分享了作者从Java后端转向Godot游戏引擎的开发体验。作为一款C++编写的开源引擎,Godot以其基于节点的场景系统和分层架构设计打动开发者,既保证性能又提供灵活性。文章通过安装方式、Hello World示例和角色移动代码,展示了Godot可视化与脚本融合的特点,以及GDScript语言的易用性。同时分析了其2D/3D差异化渲染策略,指出Godot特别适合独立游戏开发和教育用途,但也存在3D性能和团队协作的局限。作者认为Godot体现了开源工具降低创造力门槛的理念,鼓励开发者尝试实现游戏创意。

90程序员说科技的博客 1582

【PT+Arduino+OneNET基础教程1】PacketTracer中MCU芯片编程教程(零基础入门)

PacketTracer软件内MCU芯片编程入门 零基础

ChloeMax_的博客 9454

3个最致命的Godot内存泄漏陷阱:从引擎源码到修复实践

Godot Engine 作为一款功能丰富的跨平台2D和3D游戏引擎,深受开发者喜爱。然而在游戏开发过程中,内存泄漏问题常常困扰着开发者,导致游戏运行卡顿、崩溃等严重问题。本文将深入剖析Godot引擎中3个最致命的内存泄漏陷阱,并结合引擎源码给出实用的修复实践,帮助开发者避开这些"雷区"。 [![Godot Engine](https://raw.gitcode.com/GitHub_Trend

gitblog_00993的博客 1208

Python爬虫实战:全网政府招标信息采集与整合

本文详细介绍了如何使用Python构建一个完整的政府招标信息爬虫系统,涵盖了从数据采集、解析、存储到质量监控的全流程。多源采集:支持多个地方政府网站的同时采集智能解析:自动适应不同网站结构,智能提取关键信息异步高效:使用异步编程提高采集效率反爬应对:内置多种反爬虫应对策略数据质量:完善的数据清洗和质量监控机制易于扩展:模块化设计,便于添加新的数据源。

2201_76125261的博客 1380

【Codecs系列】x265编码器(十二):子像素运动搜索

在基于块运动补偿的视频编码框架中,运动搜索是最为重要的环节之一,同时也是编码端最为耗时的模块。运动搜索包括整像素运动搜索和子像素运动搜索,其中整像素运动搜索已经有很多快速算法,比如经典的三步搜索法、菱形搜索、六边形搜索以及TZSearch等等;但子像素搜索的快速算法却比较少,本文主要讲解x265编码器中的子像素搜索方法以及相关的快速搜索方法。

优快云明星博主,认证博客专家,视频、Matlab领域优质创作者。 748
上一篇: C/C++程序员如何理解Godot的场景式游戏开发逻辑的?
慷仔
博客等级 码龄9年 88粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值