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

推荐订阅源

V
V2EX
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
Engineering at Meta
Engineering at Meta
美团技术团队
N
Netflix TechBlog - Medium
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
MyScale Blog
MyScale Blog
aimingoo的专栏
aimingoo的专栏
Last Week in AI
Last Week in AI
The Cloudflare Blog
量子位
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
DataBreaches.Net
H
Hackread – Cybersecurity News, Data Breaches, AI and More

机核

游戏性能旗舰最强之选,一加 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”非对称双通道应用实测
C# with Godot:变量和类型
cameLcAsE · 2025-07-21 · via 机核

我们不会立即转到Godot中编写C#脚本,因为如果没有一些知识的铺垫,各种语法结构也会让你觉得一头雾水。当积累了足够的基础知识后,我们再边写Godot脚本边学习C#。因此建议先准备好一个C#控制台应用项目作为实验环境。

注释

先介绍如何在C#中写注释,养成好习惯。

C#和很多C-like语言一样,单行注释用双斜杠表示:

var s = "pain" // Bread in French

多行注释是这种形式:

/* A method which does nothing */ void Slack(){}

但实际上很少用。因为这个玩意儿的格式很难调整得好看,所以有些工具会直接用多行//开头写多行注释。

C#中的print

任何编程语言的学习过程初期,我们都希望有个什么方法可以验证结果并输出到控制台。正如上一篇文章中了解到的,这个东西在C#中叫Console.WriteLine。所有东西都可以丢给它然后变成字符串输出到控制台。只不过它不像print那样可以直接丢给它任意多个参数。

在你的IDE或者VS Code中,输入cw然后按下tab可以快速输入Console.WriteLine。也有可能自动插入的是System.Console.WriteLine,但是效果是一样的。这个长一点的名字是它的全名。

指明类型

GDScript中有各种不同的类型,这些类型可以体现变量(的值)到底是个什么东西。

类型标注在GDScript中是可选的:

var a = 1 a = "Hello"

上述代码在GDScript中是合法的。

但是类似的代码在C#中是行不通的。

变量声明

在C#中声明一个变量时,需要写出变量类型,再写名字:

int i = 3;

这样就定义了一个名叫iint类型变量,初始化为3。在C#中int也是整数类型。

var声明

在C#中亦可使用var关键字进行变量声明。但是,可以使用var声明的前提是,等号右侧的表达式的类型是可以推断出来的:

var a; // 错误,未初始化,无明确类型 var b = "abc"; // 正确,b类型为string var o = new Player(); // 正确。使用new关键字和Player类型的构造函数构造对象。o的类型为Player // 类似于GDScript中的Player.new()

和GDScript不一样,GDScript总是使用var关键字,无论你标不标类型都用var。

静态类型

C#的类型系统决定了它的一个变量一旦声明为某种类型,它一辈子就只能作为这个类型的值(准确地说是和这个类型兼容的类型的值)的名字。下面的代码在GDScript中是合法的:

var a = 2 a = "2"

但是在C#中,类似的代码会报错。因为a被定为int类型,所以无论你怎么修改它指代的值,也只能是某个int类型的值。这种行为是静态类型语言的特点之一。

数值类型

GDScript中的基本类型在C#同样有对应的类型。但是C#的类型会分得更细。

short、int、long

三种常用有符号整数类型。

其中最常用的还是int,即32位有符号整数。C#中的int不等价于GDScript中的int。GDScript中的int实质上是64位有符号整数,取值范围是-2^63 to 2^63-1 即-9223372036854775808到9223372036854775807。因此,C#的int的取值范围是落在GDScript的int中的。

相应地,short是16位,long是64位(对应GDScript的int)。

无符号整数类型

和short、int、long对应的还有ushortuintulong,u代表unsigned,即无符号。无符号整数类型的取值范围更大,因为容纳负数的部分全部变成更大的正整数了。

整数字面量

单纯的整数字面量只要int能装下就会被推断为int。如果int装不下就会尝试long甚至ulong

var n = 100; // n为int var np = 100_0000_0000; // long var l = 10L; // 小写l也可以,但是容易看错 var ul = 100UL;

也可以选择使用l后缀指明这是longul表示ulong。整数字面量还可以在各位之间插入下划线来增加可读性。

C#也支持用二进制、十六进制字面量来表示整数:

var h = 0x2E; var b = 0b101;

十六进制用0x开头,二进制用0b开头。

字节类型

字节就是8位整数。这个类型很有用但没有那么常用,因为通常是在处理二进制数据的时候用得比较多。C#中的字节类型是bytesbytes是signed(有符号)。

浮点数类型

GDScript只有一种浮点数类型即float,它代表64位双精度浮点数。

而在C#中主要有floatdouble两种。float为32位单精度浮点数类型,double顾名思义为64位双精度浮点数类型。

浮点数字面量和很多语言类似:

var d = 1.2; // 默认为double类型 var f = 1.2f; // 指定为float类型 var dp = 1.2d; // 指定为double类型,但没必要

不过非常常用的向量类型的分量虽然在GDScript中也以float类型暴露,但是在它的实现中却是用的32位单精度表示。我们在后面会看到,Vector2的分量在C#中也表现为float类型,这是相匹配的。

此外C#实际上还有一种浮点数类型叫decimal,是所谓货币类型,精度更高。

数值类型的转换

C#的数值类型涉及不同宽度,从取值范围较窄的值到取值范围较大的值会发生隐式转换,不需要特殊的语法:

short s = 12; int i = s; long l = i;

但是,由于实际的值可能会超出类型取值范围,反过来则需要显式地转换:

short sp = (short)i;

显式转换意味着在对应的表达式前用括号把目标类型括起来。

从浮点数到整数也需要显式转换(反过来不需要),因为这会把小数部分直接砍掉。

上面介绍过,浮点数字面量不加后缀默认为double类型。如果你需要给一个显式声明为float的变量初始化的话,要么写上后缀f,要么直接转换:

float f = 1.2f; // 正确 float fp = 1.2; // 错误,double无法隐式转换为float float fpp = (float)1.2; // 正确,但是懒得写

此外,涉及到除法时,C#的行为和很多编程语言一样:

int i = 3 / 2; // 结果为1 var d = 3.0 / 2; // d为double类型! var f = 3 / 2.0f; // f为float var fp = 3d / 2f; // fp为double

如果除号两边都是整数,结果如果不是整数那么就会把小数部分砍掉。如果参与除法的操作数有一个或以上浮点数,那么结果也是浮点数。结果的类型总是会往精度的类型走。

布尔类型

C#中的布尔类型也叫bool,两个取值也是truefalse

C#中也有andornot这类关键字,但是它们不能用于布尔运算。对布尔表达式进行逻辑运算只能用&&==||,以及不那么常用的异或^

数组

数组亦是C#的基本类型。但是它和GDScript的Array等价。

GDScript中的Array是一个长度可变的、可以保存任意类型的值的数据结构。而Array[T]类型表示对元素类型的限定。

C#中的数组是一种长度固定的序列型数据结构。在构造数组时必须确定数组的长度:

int[] ns = new int[3]{1, 2, 3}; // 历史悠久的写法 int[] nsp = new int[]{1, 2, 3, 4}; // 省略长度4,自动推断长度 int[] nspp = {1, 2, 3, 4}; // 茴香豆的茴 int[] nsppp = [3, 4, 5]; // 新写法

数组类型以T[]的形式表示。其中T是元素的类型。构造数组时,最复杂、历史最悠久的写法是,首先用new关键字开头,然后写出数组类型,方括号中写入数组长度。最后在一对花括号中写出逗号分隔的各元素(类似于C++的初始化列表)。这种写法要求用于初始化的元素必须和前面方括号中的长度匹配。

在较新的C#版本中亦引入了集合表达式语法,也就是类似于GDScript和Python等语言的语法。如果类型确定,可以直接用方括号加值列表的语法写出数组的内容。因为这种语法实际上各种集合类型甚至于自定义类型都可以使用,所以使用这种语法的时候变量类型必须指明。

访问数组的元素时,也和很多语言类似:

int[] ns = [1,2,3,4,5]; int two = ns[1]; // 索引从0开始 int last = ns[^1]; // 倒数第一个

GDScript的数组和Python中的列表一样可以用负整数索引表示从右往左第几个。C#的数组不支持负整数索引。在C#要从右往左访问第n个元素的话需要用array[^n]这种写法。^符号是Shift+数字键6。

现代C#同样支持Python那样的切片(slicing):

var firstTwo = ns[..2]; // 等价于ns[0..2]

..叫范围运算符,左右的整数表达式代表范围的边界。左开右闭,即包含起始位置的元素,但不包含结束位置的元素。切片的返回值类型亦为数组。

要获得数组的长度,我们不像在GDScript中那样有一个len函数,我们需要访问数组的Length属性。

常量

和很多语言类似,C#的常量也用const表示:

const float PI = 3.14;

枚举类型

C#也有枚举类型,也用enum关键字定义:

enum Direction { North, South, West, East, }

C#中的枚举类型实质上定义了一系列整数常量。但是枚举类型在C#中也是一个具体的类型,无法隐式转换。并且访问枚举的具体值时必须通过枚举类型和点语法来访问:

var d = Direction.North; int i = (int)Dirction.South; // 正确,显式转换 Direction direction = (Direction)1;

默认情况下,枚举可选值对应的整数从0开始,依定义中出现的顺序递增。也就是说上面的North为0,East为3。你也可以自行用等号指定取值:

enum StatusCode { Ok = 200, NotFound = 404, } ​ enum Week { Monday = 1, // ... } ​ enum TheEnum { A, // 0 B = 3, C, // 4 D = 1, E, // 2 }

如果你没有给每个可选值指定值,那么跟着有指定值后面的项目也就默认递增。但是一般不建议给不同的项目设置同一个值,因为这样不方便从整数转换回枚举类型的值。

另外你还可以给枚举类型指定要用哪个整数类型表示:

enum E : long {}

字符和字符串

字符串,字面上来说就是一串字符(仅限中文)。很多编程语言实际上不区分字符和字符串,因为“字符”也可以视作“长度为1的字符串”。而将字符和字符串视作两个类型的编程语言其实都是C-like的(rust除外)。比如如下的GDScript代码:

var s: string = "海内存知己" var c: string = s[2]

是合法的。但是类似的C#代码是错误的:

var s = "海内存知己"; string c = s[2]; // 类型应为char

因为通过下标(索引)语法从字符串中取到的结果在C#中为字符类型char

由于字符串和字符的区分,字面量也要做区分。包括GDScript和Python在内的不区分字符和字符串的语言中,大部分情况下双引号和单引号是一样的。但是在C#中需要用单引号表示字符,双引号表示字符串:

char c = '草'; string s = "草";

但是C#的char和它的前辈的char并不等价。如果你把鼠标放到你的IDE或者编辑器中的char上面,可以看到它的注释明确表示了char是用“UTF-16字符码位表示的字符”。因此,C#的char是可以存储包括汉字在内的各种Unicode字符的。而C、C++中的char本质上相当于“8位无符号整数”,因为它是用来表示ASCII字符的。

可能有点反直觉的是,字符用加号求得的结果并不是字符串,而是一个整数:

Console.WriteLine('草' + '草'); // 67218

这里的'草'被转换成了Unicode码点值,即一个整数。C#中的char虽然不等价于8位无符号整数,但是它可以隐式地转换为ushortintuintlongulong也就是对应的Unicode码点值。

字符串拼接和插值

和很多编程语言一样,C#的字符串也可以直接用加号连接。

如果要连接的东西较多,可以使用插值字符串语法类似于Python的f字符串:

int i = 10; var name = "John"; var s = $"Hello {name}, it's your {i}th time to log in";

插值字符串需要在双引号前加上一个$表示这是插值字符串。在双引号内部,花括号中间的表达式会被转换为字符串并作为整个字符串的一部分。

转换为字符串

C#中的所有类型的值都可以转换为字符串,因为它们身上都有一个叫ToString的方法。Console.WriteLIne本质上就利用了这个方法,在后面我们可以了解到,这个方法可以在不同的类型上有不同的行为,且可以有不同的参数列表。

什么都没有

和很多编程语言一样,C#也有表示什么都没有的null常量。但是,C#中不是所有东西都可以为null

一些类型的变量如果没有初始化,就默认为null。比如上面介绍过的数组和字符串都是这个范畴。

如果编译器可以分析出你在未给这类变量赋初值的情况下调用其方法会在编译时直接报错。

而上面介绍的所有数值类型都不能null。但是对于这类类型你不用担心在未初始化的情况下调用了它们的方法,因为它们有默认值。上述数值类型的默认值为0。

以上便是对C#中的变量声明、基本类型的一个介绍。从GDScript转到C#除了要记得写分号之外,就是要学会识别类型、选择类型。

也可以选择到知乎看我的文章,有代码语法高亮,好看一点。