Godot的几个附加脚本和进行继承时比较特别的特性

这篇具有很好参考价值的文章主要介绍了Godot的几个附加脚本和进行继承时比较特别的特性。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注: 这是在Godot4.0中总结出的内容,并且语言是C#。
特别的,下面有的特性和C#关系比较大。

基本特性

在Godot中,为某个节点编写特别的代码时,需要为节点新建脚本,或引用已有脚本。

引用脚本时,填入脚本路径即可,相当于是复用代码了。

新建脚本时,一般做法是新建一个自定义类型,并且这个类型继承自原有节点的类型。

其实,你也可以不继承自原有节点的那个类型。下面的各小节文章均是针对这个情况的。

在选择继承的目标时,你可以选择的范围有:(最常规的)继承自原有类型、继承自自定义类型、继承自"中间"类型。

继承自自定义类型

继承自自定义类型,一般来说是为了满足这个需求的:

用户为某节点编写了一个自定义了类型后,在新的情境下,需要扩充这个类型,让它有新的功能,并且旧的不能变。
此时,程序员一般第一个想到的就是继承。Godot顺理成章地允许用户这样进行继承。

想要进行这样的继承时,为节点新建脚本时必须先选择已有类型,若直接填入想继承的类型,Godot不允许这样做。

Godot的几个附加脚本和进行继承时比较特别的特性

创建完成后,用户可以打开脚本文件,手动修改继承类型。

虽然看上去就像作弊,但是Godot方面认可这种做法,也有人建议在建立脚本时,"继承"内容框可以选择自定义类型进行继承,但是Godot的开发者们暂时并没有这么做。

需要注意的是,这种做法对此脚本附加到的节点有要求。

  • 首先,你在编写一系列一层一层继承起来的类时,你建立起来的最底层的那个自定义类肯定是继承自"原生类型"的
    • "原生类型"就是新建节点时,你能在面板里选到的类型(没错,这里找不到你自定义的类型,它们100%是Godot内置的!)
  • 要将这一系列自定义类中的任何一个附加到一个目标节点时,这个目标节点在编辑器中体现出来的类型必须能够兼容自定义类最底层的"原生类型",和它相同,或是继承自它,都可以。
    (注:如果不兼容,运行时会报错。)

继承自"中间"类型

读了上面的内容时,你也许会意识到,其实任何一个自定义类型底层的"原生类型",可以是它附加的节点的继承树中大于等于Node的类型之中的任何一个类型。

我称这种做法为"继承自中间类型"。




事实上,也许需要调整一下观念。大家一开始似乎会认为,节点附加了一个自定义类型后,节点就是自定义类型的实例了。

实际情况似乎要稍微割裂一点。因为继承自中间类型后,你会发现,这个自定义类型无法完全描述这个节点。请看接下来的例子。

这里,我给一个精灵Sprite2d挂上这样一个自定义类型,它继承自Node。

public partial class TNode : Node
{
}

Godot的几个附加脚本和进行继承时比较特别的特性

我想知道,这个节点从C#继承体系的角度看,还是不是"精灵(Sprite2D)"了

让我们在根节点中写一点代码,试图了解该节点的类型。

public partial class AskForClass : Node2D
{
    public override void _Ready()
    {
        var t1node = GetNode("TNode");

        //方法1 打印继承树
        Type tobj;
        tobj = t1node.GetType();
        while (tobj != null)
        {
            GD.Print(tobj.Name);
            tobj = tobj.BaseType;
        }
        GD.Print("以上是继承树。");

        //方法2 类型转换。转换失败的话就是null。
        var t2node = t1node as Sprite2D;
        GD.Print(t2node);

        //方法3 我发现Godot有一个IsClass()方法
        GD.Print("is sprite2D class?" + t1node.IsClass("Sprite2D"));

    }
}

(小提示:Godot的_Ready()函数被执行顺序是先子节点,再父节点,这样嵌套的,所以父节点访问子节点总是万无一失的,当然,这个示例就算顺序不是这样也不存在问题)

上面用了3种方式试图确认我们的t1node有没有Sprite2D的成分,以及Sprite2D的成分通过哪种方式能查到,猜猜看?

结论是:

TNode
Node
GodotObject
Object
以上是继承树。
null
is sprite2D class?True

除非使用Godot提供的函数IsClass(), 光靠C#的继承体系,查不到Sprite2D的成分, 而且实例无法转换成Sprite2D类型,这样就不能以C#通常的方式操作Sprite2D特有的函数和变量了。

在C#内,虽然它"放弃了作为Sprite2D的身份",但我们的节点在运行时仍然做着一个"精灵"会做的事情,比如我在编辑器里对它的位置和旋转进行了变更,这些变更都没有丢失。
个人推测,此时需要使用GetIndexed()SetIndexed()等方法来操作那些无法直接访问的东西。

Godot的几个附加脚本和进行继承时比较特别的特性



这个实例和实际存在于Godot运行时的节点竟然有这样的不同。

以后也许时不时需要想起来这样一件事——C#实例和Godot内的节点只是连在一起,有一个映射的关系罢了,并不100%是那个节点本身。

节点除了有C#能提供给它的函数和字段外,还可以拥有相当突出的Godot赋予它的不同类型的功能,即各种类型的"原生节点"的各种各样的功能。


阅读文档后,大概可以这样理解,Godot运行时维护的节点身上的函数和变量的表现更符合动态语言的特征,而不是静态类型语言。
不论是C#脚本、Godot脚本、还是"原生类型"的节点,行为都是将自己的各种功能附加或覆盖到了节点身上。

Godot is very dynamic. An object's script, and therefore its properties, methods and signals, can be changed at run-time. Because of this, there can be occasions where, for example, a property required by a method may not exist. To prevent run-time errors, see methods such as set, get, call, has_method, has_signal, etc. Note that these methods are much slower than direct references.
Godot很是动态。对象的脚本及其属性、方法和信号可以在运行时更改。因此,在某些情况下,例如,方法所需的属性可能不存在。若要防止运行时错误,请参阅设置、获取、调用、has_method、has_signal等方法。请注意,这些方法比直接引用慢得多。

继承自中间类型后可能遇到的坑

上述特性可能会引发一个问题,当你需要用C#找到场景中的所有某一原生类型的节点时,从"中间"继承的节点被获取后,由于一些身份被放弃了,有可能被漏掉!

也就是说,在上面的案例中,想找Sprite2D时,用下面的方法,挂载了TNode脚本的精灵将被跳过,尽管它这么大一个放在屏幕上。

List<Sprite2D> lst = new List<Sprite2D>();
var children = FindChildren("*");
foreach (var chi in children)
{
    if (chi is Sprite2D sp)
    {
        lst.Add(sp);
        GD.Print("这个是精灵" + chi.Name);
    }
    else
    {
        GD.Print("这个不是精灵" + chi.Name);
    }
}

Godot的几个附加脚本和进行继承时比较特别的特性

我没有测试GDScript,不知道是否情况会不同。也许它支持多重继承?

综上所述,个人建议尽量避免附加脚本时从中间继承

实在有这样的需求,要么避免一个类型的每一个身份都需要被C#直接操作,要么用IsClass()配合GetIndexed()SetIndexed()等方法处理该对象。

参考:
https://godotengine.org/qa/141137/best-way-to-add-a-node-that-extends-a-custom-class
https://docs.godotengine.org/en/latest/classes/class_object.html文章来源地址https://www.toymoban.com/news/detail-470024.html

到了这里,关于Godot的几个附加脚本和进行继承时比较特别的特性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ARFoundation多图识别的一个脚本

    使用ARFoundation的图像识别发布出来的安卓应用存在一个令初学者挠头的问题——模型始终是背对用户的,虽然可以在3ds Max等软件中调整其轴心,终归是麻烦。受汪祥春老师《AR开发权威指南基于AR Foundation》一书的启发,编写如下MultiImageTracking脚本: 用法: 为参考图像库添加

    2024年02月11日
    浏览(32)
  • 赋的几个发展阶段

    赋,起源于战国,形成于汉代,是由楚辞衍化出来的 ,也继承了《诗经》讽刺的传统。关于诗和赋的区别,晋代文学家陆机在《文赋》里曾说: 诗缘情而绮靡,赋体物而浏亮。 也就是说,诗是用来抒发主观感情的,要写得华丽而细腻;赋是用来描绘客观事物的,要写得爽朗而

    2024年02月07日
    浏览(63)
  • IO的几个模型

    说到I/O模型,都会牵扯到同步、异步、阻塞、非阻塞这几个词,以下讲解这几个词的概念。 阻塞和非阻塞 阻塞和非阻塞指的是一直等还是可以去做其他事。 阻塞(一直等水烧开)(blocking): 调用结果返回之前,调用者被挂起(当前线程进入非可执行状态,在这个状态,CPU不

    2024年02月12日
    浏览(45)
  • SQL中的几个区别

    1:几种JOIN连接方式的区别? 2:几种排序窗口函数的区别? 3:on和where的区别? 4:having和where的区别? 5:union和union all的区别? 6:in和exists的区别? 7:数据库中空字符串、0和NULL的区别? 8:count(1)、count(*)和count(列名)的区别? 1- 几种JOIN连接方式的区别? INNER JOIN(内连

    2024年01月19日
    浏览(34)
  • C++代码重用:继承与组合的比较

      目录 一、简介 继承 组合 二、继承 三、组合 四、案例说明 4.1一个电子商务系统 4.1.1继承方式 在上述代码中,Order类继承自User类。通过继承,Order类获得了User类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayInfo()函数,以便在Order类中显示订单相关信

    2024年01月22日
    浏览(59)
  • 关于中断的几个小问题

    1. intel 8259芯片中的IRQ2和int2的区别是什么? 答曰:IRQ2是芯片上的引脚,而int2是中断向量表的第2项,两者有很大区别。 Intel8259A芯片的中断引脚分别为: 主片: 0:8254时钟 1:键盘 2: 从片 3: com2 4:com1 5:声卡 6:软盘 7: lpt打印机 从片: 0:cmos时钟 1:到主片IRQ2的引脚 2:网

    2024年02月07日
    浏览(39)
  • 求数组长度的几个函数

    纯纯小白,有错请指出,谢谢。 1、sizeof函数 对于一个给定数组,如:int arr[]={1,2,3,4,5} , 可以利用 sizeof(arr)/sizeof(arr[0]) 的方式来求字符串长度 , 需要注意的是,sizeof 计算出的字符串长度包括了本身隐含的‘\\0’;对于一个自定义输入的数组,如:int arr[10] , 同样的方法并不能

    2024年02月16日
    浏览(47)
  • 动态规划的几个经典问题

    矩阵链加括号问题 【问题描述】 给定 n 个矩阵 A1, A2 ,…, An,  其中 Ai 与 Ai+1 是可乘的 ,  计算这 n 个矩阵的连乘积 A1A2…An 。 用加括号的方法表示矩阵连乘的次序。 【输入形式】 输入有2行,第1行输入一个整数n,第2行输入n个矩阵的维度值p0,p1,...,pn 【输出形式】 输出分3部

    2024年04月10日
    浏览(79)
  • confluence的几个高危漏洞复现

    本次复现涉及了好几个confluence的相关漏洞,从复现利用到提权,有兴趣的可以自行搭建环境测试。 在某些情况下,远程攻击者在经过身份验证或在特定环境下未经身份验证的情况下,通过构造恶意数据执行 OGNL 表达式进行注入攻击,实现在 Confluence Server 或 Data Center 上执行任

    2023年04月08日
    浏览(44)
  • SQL调优的几个方法

    1.为什么调优,好处是什么?  SQL语句在编写之后,对于数据量较少的表基本没有什么性能上的需求,但是如果考虑到性能方面的话,SQL语句优化就是必须的。 2.如何调优?调有点方法有哪些?   1、对查询进行优化,应尽量避免全表扫描,首先考虑在where及order by上建立索引

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包