惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
罗磊的独立博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LINUX DO - 最新话题
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
The GitHub Blog
The GitHub Blog
V
V2EX
SecWiki News
SecWiki News
P
Privacy & Cybersecurity Law Blog
Forbes - Security
Forbes - Security
T
Troy Hunt's Blog
S
Security @ Cisco Blogs
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
A
Arctic Wolf
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Register - Security
The Register - Security
Blog — PlanetScale
Blog — PlanetScale
The Last Watchdog
The Last Watchdog
T
Tor Project blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
P
Proofpoint News Feed
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
小众软件
小众软件
雷峰网
雷峰网
H
Heimdal Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
Engineering at Meta
Engineering at Meta
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
C
Cyber Attacks, Cyber Crime and Cyber Security
Webroot Blog
Webroot Blog
C
Check Point Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
人人都是产品经理
人人都是产品经理
Hacker News: Ask HN
Hacker News: Ask HN
The Hacker News
The Hacker News
V
Vulnerabilities – Threatpost
Microsoft Security Blog
Microsoft Security Blog

机核

游戏性能旗舰最强之选,一加 Ace 6 至尊版国补到手价2999元起 6元钱自己更换电动车刹车线 《生化危机9:安魂曲》编剧Haris Orkin专访 摸金游戏?音乐游戏!暗区新赛季这把能弹的琴有何来历? 好评国产武侠SRPG《息风谷战略》免费DLC现已推出 | 机核 GCORES 碎片 《生化危机:安魂曲》将于5月实装首个免费更新内容 | 机核 GCORES 新锐东方游戏,谱写世界新章! 沉浸式恋爱视觉小说游戏《心象演算》免费试玩版现已正式上线 | 机核 GCORES 互动影游《代号三国:龙起》上线!穿越三国与曹操并肩、与佳人同行、与权谋博弈! 《老头收集梦想生活》,游戏酒桌会6,录音笔VOL.689 | 机核 GCORES 破界·共生——《白日梦:无限世界》五大核心游戏特点解析 价格已到史低,锐龙5 9600X/锐龙7 9700X正适合抄底 时间循环之旅即刻启程!《归环》一周目测试今日开启 热门在线韩游变魂游,洛奇衍生作能否打破“花瓶”魔咒? LG UltraGear evo 全新高端显示器系列:当“5K”遇见“AI”,不止强大,更懂热爱 反套路三国互动影游《代号三国:龙起》今日上线! 愿望单登记人数突破10万!备受瞩目的“女儿养成游戏” 《梦幻魔法公主》今日于Steam平台上线!限时八折优惠中 《黑神话:悟空》全球音乐会2026巡演将于4月29日12时开票 | 机核 GCORES “Snowguelike”生存肉鸽挖矿新作《蛙穿雪境》公布发售日期,5月7日正式上线 | 机核 GCORES 重塑移动办公、AI创作新境!全新华硕灵耀Air系列、ProArt 骁龙版震撼首发,创芯未来 均分88:《Saros》媒体评分汇总 | 机核 GCORES 上海烛龙公布合作遗迹探险游戏《吉时已到》首支预告片 | 机核 GCORES 首个独立游戏《萝薇日记》已上线Steam! 烛龙新IP《吉时已到》首曝,打造国内首款中式合作遗迹探险游戏 喜加一:《暗黑破坏神Ⅳ》国服现已开启限时免费领取本体活动 | 机核 GCORES 新版《生化危机》电影定于9月18日上映,官方网站现已上线 | 机核 GCORES 《冲就完事模拟器2》“星球大战”联动DLC正式宣布 | 机核 GCORES SteamController将于5月4日发售,售价99美元 | 机核 GCORES 事已至此,内存这么用也算省钱了,“2+1”非对称双通道应用实测 505游戏母公司现已收购《明末:渊虚之羽》IP | 机核 GCORES 基石 手动杂谈12|格斗游戏也能讲好故事 | 机核 GCORES I Love You Mr Snowball 我的向日葵小姐 会比GTA6先发售吗?最硬核的生存游戏《DAYZ》要推新DLC了 周记02:在2026遇到新怪谈 什么硬件,能让游戏Loading界面快速消失? | 机核 GCORES GadioSpec《百年风云世界杯》免费试听集 | 机核 GCORES 百年风云世界杯Vol.1丨足球崛起 | 机核 GCORES 100年前,一群人提前替我们经历了AI恐惧 | 机核 GCORES 《呼啸山庄》2026 ——一辆当代艺术的大卡车冲撞了我的大脑 手游《天穗之咲稻姬:日之香巡灵传》宣布将于7月27日停服 | 机核 GCORES 集结梦之队,征战世界杯,《最佳球会ONLINE》上线Steam 山水绝景随心拼 休闲建造游戏《千里山河录》Steam商店页公开 巫师帽、法袍、魔杖,为什么它们是影视、游戏里的法师必备三件套? 《无鞘信使》-第一章 复古风自动战斗肉鸽《终结之终结》Steam商店页面现已上线 电脑里有一款不破不立的MMO,录音笔VOL.688 | 机核 GCORES 《生化危机》30周年纪念周边发售,这次是真的“保护伞” 可靠耐用+AI全能,惠普战66 2025锐龙版深度体验 《时之书:无尽终章》关卡“大航海时代”全球首次公开 经典名作《乌龙派出所》改编经营模拟游戏《乌龙派出所~阿两的商店街物语~》正式宣布支持简体中文 明日开冲,解锁反套路三国互动影游《代号三国:龙起》即将上线 独立游戏《这是我的宝藏!》已发售~ 降低难度不是唯一解,无压力死亡也是好体验 Netflix官宣新片《普通人》:讲述韩国现代史上的权力风暴 《生化危机:安魂曲》全球销量现已突破700万份 《绝地鸭卫》PC版5月15日正式发售 亡妻回忆录?女性向情感叙事游戏《S-mail》现已正式发售 全新酷黑风格,酷睿Ultra 200S PLUS的高性价比搭档!七彩虹BATTLE-AX B860M-PLUS S WIFI7 V20 超级黑刃主板测评 胖狗 索尼发布了港台地区PS5产品价格调整公告,将于5月1日起实施 二次元怪猎+性感美女!《碧蓝幻想:无尽黄昏》开启Beta公测 这款怪谈类型中式恐怖游戏居然更新了?! 《百日战纪 -最终防卫学园-》改编漫画将于今年冬季开启连载 《如被附身,请致电我们》:匈牙利黑色幽默恐怖小说 《竹屿山房杂部卷五》(译文) 大树 超越引擎 摄影分享丨四月 碎片杂记vol.72 当老式FPS与老式动画技术碰撞出新时代的火花—《神探杰克鼠》 想做独游,如何避免首个项目就褒姒? 在线多人动作游戏《OCTOPinbs》将于5月12日上线Steam! 《酒鬼女神的酒诡》确定将于2026年登陆Steam 《CRYMELIGHT》将于11月5日(周四)正式发售!4月25日开始预购! 钢铁国度MKI部落Evolution,蛮兵部分 【钢铁国度】部落-Primal MK I,蛮兵部分 这是一个高中生用ai跑出来的作品,我自称他为物理神话 钢铁国度MKI部落Metamorphosis,蛮兵部分上 钢铁国度MKI部落Metamorphosis,蛮兵部分下 INDIE Live Expo于4月25日举办:首发9款新作,超200款独立游戏亮相 暗黑卡牌策略新作《魔忌:穷鼠啮狸》发布全新中文试玩版和发售预告片,4月30日正式上线在即 战锤40K长篇小说:变节者・苦难主宰(三)(全书完) 战锤40K长篇小说:变节者・苦难主宰(二) 战锤40K长篇小说:变节者・苦难主宰(一) 英语语言学习丨短语专题1:短语的特点 唯一的EVE战争 【少前同人】【M200】战术人形会梦见音乐会吗 【昏迷3】即将发售,前作主角悉数到场!“恶灵”宋老师化身可操控角色 业内人士:游戏公司“十有八九”使用生成式AI,包括卡普空 欢庆一周年:《光与影:33号远征队》全新纪念艺术图、超值折扣与免费更新同步上线 才刚刚开始呢 【抽奖】《星际卡车司机》推出免费大型更新,四折平史低折扣进行中 四人合作FPS游戏《佣兵猎手》抢先体验重大更新 1 现已上线 Raw Fury新作《深馅地牢 Deep Dish Dungeon》将于今秋加入 XGP 塔防幸存者游戏《魔怪来袭》推出首个 DLC 《饿狼传说:群狼之城》1周年纪念!新DLC“沃尔夫冈·克劳萨”今日参战 猫狗相伴 欢乐闯关 双人合作平台跳跃游戏《猫狗同行》上线Steam商店页 《同行:月球逃脱》(Together: Moon Escape)上线将于明日上线Steam
C# with Godot:祖传秘方
cameLcAsE · 2025-08-02 · via 机核

谈了类,就肯定要谈继承。毕竟GDScript脚本在很多时候也会继承一个节点类。

继承一个类

在GDScript中,我们在脚本文件的开头写上extends Node这样的语句来表示此脚本(类)的基类是谁。

在C#中定义一个类时,在类名后面加上一个冒号,再写上另一个类名就表示此类继承了后者:

class Item { public int Id {set; get;} public string Name {set; get;} } ​ class Weapon : Item { public int Atk { set; get; } }

一般来说,基类是更抽象的概念,而子类是更具体的概念。

protected级别

除了之前提到的public和private,还有一个常用的访问级别是protected。

标注为protected的成员除了在定义它的类中访问之外,还可以在由它派生出来(继承它)的类中访问。在同一个继承链条上的类都可以访问,即子类、子类的子类都可以访问它。

“继承的”级别

如果你是C++程序员,你可能发现C#的继承语法和C++几乎一样,但是C#在继承类时不区分public、protected、private。C#的继承就相当于public继承,父类中的成员在子类中的访问级别不会发生变化。

类型兼容

子类的实例可以放到需要一个基类类型的值的地方:

Item i = new (); Weapon w = new Weapon(); i = w; F(w); ​ void F(Item i){}

这些行为是合情合理的,因为我们在继承时就是为了表达“is-a”关系。WeaponItem的子类,就意味着所有的Weapon都也应该是Item。所有需要Item的地方放入一个类型实为Weapon的实例也是没有问题的。

不过,在通过类型为基类的变量、参数引用实为更具体的类的实例时,我们只能访问基类中定义的成员。

GDScript中也是类似的。但还是由于GDScript本质上是动态类型的语言,即使尝试在类型为基类的变量上访问子类中定义的成员,只要此成员存在,那么在运行时就不会报错:

class A: var n = 1 class B extends A: var m = 2 var a: A = B.new() print(a.m)

类似的代码在C#中编译时就会报错。当然你会发现,按照目前的Godot编辑器的行为来看,这里实际上无论把a标记成啥类型或者不标类型,编辑器都会识别到a拿到了一个类型为B的对象,然后在下面的代码中会自动提示B的成员。

万物之始——object

C#中所有的类都隐式地继承了object类——你可以随便找个对象然后用blahblah is object去试。“一切皆对象”那确实不是说着玩的。

前面提到,所有的类实际上都可以调用ToString方法转换为字符串,这个方法实际上就定义在object上。因此你定义的一个新类的实例也可以调用这个方法,只不过它不一定是你想要的效果,默认情况下它会直接输出你的类名。

在Godot中,也存在一个叫Object的类型,引擎中的所有“类”都继承了它。但实际上按照Godot的设计,并不是所有的东西都是一个类的实例。例如整数、信号这些内置类型都不属于Object类型。Godot中真正可以引用任意类型的值的类型实际上是Variant,如果你不给一个变量标注类型,就相当于它是Variant类型。本质上Godot将值的类型分成了Variant.Type中定义的这些类别

类型判别

你的教科书可能会讲,我们通过继承和派生来表达各个类之间、实例和类之间的is-a关系。你可以在C#中使用is关键字来判断某个对象是不是某个类型的:

object o = new Item(); Console.WriteLine(o is Weapon); if (o is Item i) { Console.WriteLine($"It's an item called {i.Name}"); }

这实际上是C#模式匹配语法的一部分,类型放在这里会作为所谓的类型模式,即当给定的对象属于某个类型时就会匹配成功。整个表达式的返回值是bool,所以你可以很自然地把它用到if的条件中。

o is Item i这种写法也很好用。它的意思就是如果o成功和Item类型匹配,那么就把它的值绑定到变量i。这样一来就可以在if后面的代码块中通过类型为Item的变量i来访问定义在Item上的成员了。

GDScript中也有is运算符,可以用类似的语法进行类型判别。

类型转换——casting

正如前面所说,我们可以通过一个类型为基类类型的变量去引用一个实为子类的对象,但是通过基类类型的变量只能访问基类中定义的成员。

没毛病,因为所有汉堡都是食物,但是并不是所有食物都是汉堡。我们不能假定一个食物可以提供和面包胚相关的属性。

但是有些时候我们可能比编译器知道得更多,我们可以断定某个通过基类类型变量引用的对象实际上属于某个子类:

Item i = new Weapon(); Console.WriteLine((i as Weapon).Atk);

as可以将一个类型的对象“转换”成另一个类型——大家都爱这么说,但是实际上什么转换都没有发生,对象本身并没有变。通过不同的(但兼容的)类型去引用某个对象,实际上只是观察角度的改变。

从基类类型转换为子类类型的过程叫downcast,即向下转换。由于这个过程可能失败,as转换失败时会返回null

object o = new Player(); Console.WriteLine(o as Weapon);

另一个方向的转换叫upcast,但是由于语言本身的设计,这种转换一般是不需要的。

GDScript中也存在as运算符,和C#中的as行为基本一致。

显式转换

对象也可以像数字那样用括号进行显式转换:

Item i = new Weapon(); Console.WriteLine((Weapon)(i).Atk);

和使用as的区别在于,显式转换在失败时会直接引发异常

虚方法和重写

当一个方法标记为virtual,就表明此方法可以在其派生类中被重写(override)。“可以”的意思是,你可以重写也可以保持原样。

恰好,ToString就是这样一个方法。其默认的行为在很多时候用起来在调试时并不方便,更别提真正地把一个对象转换成有用的字符串了。如果我们要重写一个方法,我们要这样写:

class Item { // 略去其它定义 public override string ToString() { return $"{Id} {Name}\nDescription: {Description}\n"; } }

和定义一般的方法唯一的区别在于多了个override关键字。这个关键字就表明这个方法的定义就是在重写一个基类中对应的方法。

重写方法时,方法的签名必须和基类的定义保持一致。即方法的名称、参数列表、返回值类型、访问级别都必须和基类中的定义保持一致。在实际编写代码的过程中,你也不用老老实实地从头打到尾。一般你写一个override之后,你的IDE和编辑器就会提示可以重写的方法。

属性重写

我们已经了解到,属性的定义在很大程度上也就是定义了对应存取的两个方法。属性也可以标记为virtual,也可以重写:

class A { protected int n; public virtual int N { protected set => n = value; get => n; } } ​ class B : A { public override int N { protected set { Console.WriteLine($"N set to {value}"); n = value; } get => n; } }

借用基类实现

如果你不需要完全覆盖虚方法在基类的实现中所做的工作,你也可以按需调用基类实现的版本:

// 继承Item的Weapon类 public override string ToString() { return $"{base.ToString()}Atk: {Atk}"; }

通过base关键字可以调用各种在基类中定义的成员。

GDScript中使用的是super关键字,作用类似。

多态

继承和重写方法的好处在于,我可以在有必要的时候忽略父类和子类的区别,又在有必要的时候让它们的成员自发地有不同的行为。

假设我把一系列道具放在一个数组(背包)里面。由于C#的数组要求保存的元素必须都属于同一个类型,所以我们只能把数组的元素类型定义为基类。但是,由于继承关系的存在,我们实际上可以放入从Item类派生出来的各个类型的实例:

Item i = new Item(); // 假设这些类存在且都继承了Item Weapon w = new Weapon(); SkillScroll s = new SkillScroll(); ​ Item[] items = [i, w, s];

很好,所有东西都一股脑地装进去了,数组也不管它们到底是啥,只要它们“是道具”就行了。

foreach(var i in items) { items.Use(); }

如果Use是定义在Item上的一个虚方法,且各个类都实现了自己的版本。那么在上面这样的代码中,在运行时它会“非常聪明地”调用具体的道具实例对应真正的类型上定义的具体的版本,而不是调用Item上的版本。

这就是所谓多态(polymorphism)的一种体现。

抽象基类

有些时候一个基类是真的很抽象,以至于没必要、甚至不应该直接构造基类的实例。

比如说“动物”。我们有很多种方式去定义动物的分类、去构造它的各种子类。食蚁兽、西伯利亚雪橇犬都是很具体的动物,但是并不存在一种动物就是“动物”。

这种基类可以定义为抽象类:

abstract class Animal { public stting Name {set; get;} }

使用关键字abstract指明一个类是抽象类。

抽象类不能被实例化,但是我们依然可以定义类型为抽象类的变量。正如我反复强调的,变量不是对象也不存储对象,它只是引用一个对象,并通过它的类型来观察这个对象。

抽象方法

抽象类中可以定义抽象方法。抽象方法不允许有方法主体,用传统一点的术语来说就是它只能有声明,不能有定义。抽象类中定义的抽象方法,就是要求子类在继承此类时必须实现此方法。一般适用于一些基类无法实现或者没什么意义的方法。

abstract class Animal { // ... public abstract void Bark(); } ​ class Dog : Animal { public override void Bark() { Console.WriteLine("Woof"); } } ​ class Husky : Dog { public override void Bark() { Console.WriteLine("Woooooooooo"); } }

在子类中,抽象方法的实现会用到和重写虚方法一样的语法即使用override关键字。

Dog类实现了Animal的抽象方法,Husky本身是不用重新实现的。但是如果有必要也可以进行重写,抽象方法天生就是virtual的。