Skip to content

算术运算符一览,按优先级排序:

表达式说明
x ** y幂(乘方), 表示 xy 次方
+x -x取同取负(相反数)
x * y x / y x % y乘法除法取模(求余)/ 格式化字符串这三者相同优先级
x + y x - y加法 / 连接字符串减法这两者相同优先级
x = y x += y x -= y x *= y x /= y x **= y x %= y 赋值运算,优先级最低x += y 等效于 x = x + y,其他同理
  • 如果进行整数除法,则结果将会自动“向下取整”截断小数

    print(5 / 2) # 输出2,而不是2.5

    要解决这一问题,只需要将其中一个整数转化为浮点数即可,比如转换类型,乘以1.0,如果是常量则在其后方加上.0

    • 5.0 / 2

    • float(5) / 2

    • 5 * 1.0 / 2

  • 取模运算符%只能用在整数上,如果要对小数进行求余,可以使用数学函数fmod()

  • 对于负值,取模运算符和数学函数fmod()的结果并非数学意义上的余数,因为会使用截断小数位,而非向负无穷大舍入,此时的余数会带有符号(如 -5 % 2 = -1,而不是预期的 1),如果想要得到数学意义上的余数(非负,且小于除数的绝对值)应改用posmod()fposmod()

  • 可以使用括号()来改变表达式的运算优先级

1 + 2 * 3 = 7

(1 + 2) * 3 = 9

常用数学函数

点击对应函数将自动跳转到官方文档

二进制运算符

表达式含义示例效果说明
~x按位取反(NOT)~0000 00011111 1110把每一位都反过来(1变0,0变1)
x << y左移 y 位1 << 38(即 00011000相当于乘以 2 的 y 次方
x >> y右移 y 位8 >> 22(即 10000010相当于除以 2 的 y 次方(向下取整)
x & y按位与(AND)1100 & 10101000两位都为1才为1
x | y按位或(OR)0100 | 00110111有任意一位为1就为1
x ^ y按位异或(XOR)0110 ^ 00110101相同为0,不同为1
x &= y x |= y x ^= y x <<= y x >>= y二进制赋值运算符同上x &= y等效于 x = x & y其余同理

标志位(flag)

在GDScript中,有很多flag标志位

比如表示属性使用情况元数据的标志位PropertyUsageFlags

常见的PropertyUsageFlags标志位

标志名意义
PROPERTY_USAGE_SCRIPT_VARIABLE4096/ 0000 0001 0000 0000 0000表示这个属性是脚本中的变量
PROPERTY_USAGE_NIL_IS_VARIANT131072/0010 0000 0000 0000 0000属性类型是 Variant(动态类型)
PROPERTY_USAGE_NO_EDITOR2 / 0000 0000 0000 0000 0010不显示在编辑器中(即使是导出变量)
PROPERTY_USAGE_CLASS_IS_ENUM65536 / 0001 0000 0000 0000 0000属性是枚举类型变量
PROPERTY_USAGE_NONE0 / 0000 0000 0000 0000 0000属性不被存储,也不会显示在编辑器中(非导出属性的默认值)
PROPERTY_USAGE_STORAGE2 / 0000 0000 0000 0000 0010将属性序列化并保存到场景文件中(用于导出属性的默认值)
PROPERTY_USAGE_EDITOR4/ 0000 0000 0000 0000 0100属性会显示在检查器中(用于导出属性的默认值)

组合标志:按位或|

按位或 | 用于 组合多个标志

gdscript
print(PROPERTY_USAGE_SCRIPT_VARIABLE) # 输出 4096
print(PROPERTY_USAGE_NIL_IS_VARIANT) # 输出 131072

var usage = PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT
print(usage) # 输出 135168

这是说,“这个属性既是用户脚本变量也是类型为Variant的动态类型变量”,所以两个值加起来就是 4096 + 131072 = 135168,用按位或表示就是 :

    0010 0000 0000 0000 0000(131072)  
  | 0000 0001 0000 0000 0000(4096)
  = 0010 0001 0000 0000 0000 (135168)

结果就是同时拥有两个标志

gdscript
print(PROPERTY_USAGE_SCRIPT_VARIABLE) # 输出 4096
print(PROPERTY_USAGE_CLASS_IS_ENUM) # 输出 65536

var usage = PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT
print(usage) # 输出 69632

这是说,“这个属性既是用户脚本变量也是类型为枚举类型的变量”,用按位表示就是

  0000 0001 0000 0000 0000 
| 0001 0000 0000 0000 0000 
= 0001 0001 0000 0000 0000 (4096 | 65536 = 69632)

检查标志:按位与 &

你可以使用 按位与(&)判断某个标志是否存在

gdscript
if usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
    print("这个变量是用户脚本变量")
if usage & PROPERTY_USAGE_CLASS_IS_ENUM:
    print("这个属性被当做枚举了!")
if usage & PROPERTY_USAGE_STORAGE:
    print("这个属性会被存储到场景或资源文件里")
if usage & PROPERTY_USAGE_NO_EDITOR:
    print("这个属性不会显示在编辑器中(即使是导出变量)")

如果结果非零,就说明这个标志存在!

如果你想检查多个标志是否全部存在,可以这样:

gdscript
if (usage & (PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT)) == (PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT):
    print("两个标志都有设定喔~!")

比如说 :

usage = 0000 0001 0000 0000 0000(PROPERTY_USAGE_SCRIPT_VARIABLE)

我们想要检查PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT

  0000 0001 0000 0000 0000  (4096) PROPERTY_USAGE_SCRIPT_VARIABLE 
| 0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
= 0010 0001 0000 0000 0000 (135168)

然后来看

  usage & 135168 = 
    0000 0001 0000 0000 0000 (4096) PROPERTY_USAGE_SCRIPT_VARIABLE 
  & 0010 0001 0000 0000 0000  (135168)
  = 0000 0001 0000 0000 0000  (4096)

计算结果如上,转换为十进制就是4096,这表明它存在PROPERTY_USAGE_SCRIPT_VARIABLE标志位,但不存在PROPERTY_USAGE_NIL_IS_VARIANT

再比如:

usage = PROPERTY_USAGE_SCRIPT_VARIABLE     # 4096 -> 0000 0001 0000 0000 0000

我们要检查PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_CLASS_IS_ENUM

    0000 0000 0000 0000 0010  (2) PROPERTY_USAGE_NO_EDITOR 
  | 0001 0000 0000 0000 0000  (65536) PROPERTY_USAGE_CLASS_IS_ENUM
  = 0001 0000 0000 0000 0010  (65538)

然后来看:

  usage & 65538 = 
    0000 0001 0000 0000 0000 (4096) PROPERTY_USAGE_SCRIPT_VARIABLE     
  & 0001 0000 0000 0000 0010  (65538)
  = 0000 0000 0000 0000 0000 (0)

结果为0,说明usage 没有包含任何一个我们要检查的两个标志位

清除标志:按位取反 ~ + 按位与 &

比如我们不想要动态类型这个标志了:

gdscript
usage = usage & ~PROPERTY_USAGE_NIL_IS_VARIANT
usage &= ~PROPERTY_USAGE_NIL_IS_VARIANT

这就会把 131072usage 中移除:

  ~ 0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
  = 1101 1111 1111 1111 1111 (917503) 

    0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
  & 1101 1111 1111 1111 1111 (917503) 
  = 0000 0000 0000 0000 0000 (0)

清除一个不存在的标志什么也不会发生:

usage = PROPERTY_USAGE_SCRIPT_VARIABLE # 0000 0001 0000 0000 0000(4096)

我们试着清除PROPERTY_USAGE_NIL_IS_VARIANT

  ~ 0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
  = 1101 1111 1111 1111 1111 (917503) 

    0000 0001 0000 0000 0000(4096) PROPERTY_USAGE_SCRIPT_VARIABLE 
  & 1101 1111 1111 1111 1111 (917503)
  = 0000 0001 0000 0000 0000 (4096) PROPERTY_USAGE_SCRIPT_VARIABLE

翻转标志:按位异或 ^

如果我们想“切换”枚举标志的开启状态:

gdscript
usage = usage ^ PROPERTY_USAGE_CLASS_IS_ENUM
usage ^= PROPERTY_USAGE_CLASS_IS_ENUM

如果原本有这个标志,它就会被移除;

如果原本没有,它就会被加上!

以上面的代码为例,比如说usage现在是PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NIL_IS_VARIANT

    0000 0001 0000 0000 0000  (4096) PROPERTY_USAGE_SCRIPT_VARIABLE 
  | 0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
  = 0010 0001 0000 0000 0000 (135168) 

    0010 0001 0000 0000 0000 (135168) 
  ^ 0001 0000 0000 0000 0000 (65536)PROPERTY_USAGE_CLASS_IS_ENUM    
  = 0011 0001 0000 0000 0000 (200704)

然后用按位与检查一下

    0011 0001 0000 0000 0000 (200704)
  & 0001 0000 0000 0000 0000 (65536)
  = 0001 0000 0000 0000 0000 (65536)

不为 0,表示具有该标志

再检查一下是否同时具有三个标志

    0000 0001 0000 0000 0000  (4096) PROPERTY_USAGE_SCRIPT_VARIABLE 
  | 0010 0000 0000 0000 0000  (131072) PROPERTY_USAGE_NIL_IS_VARIANT
  | 0001 0000 0000 0000 0000 (65536)PROPERTY_USAGE_CLASS_IS_ENUM  
  = 0011 0001 0000 0000 0000 (200704)

     0011 0001 0000 0000 0000 (200704)
  &  0011 0001 0000 0000 0000 (200704)
  =  0011 0001 0000 0000 0000 (200704)

满足条件,(usage & (a | b | c)) == (a | b | c)因此同时具有三个标志。

我们再试着用一次异或,看看是不是真的能够移除

    0011 0001 0000 0000 0000 (200704)
  ^ 0001 0000 0000 0000 0000 (65536)PROPERTY_USAGE_CLASS_IS_ENUM  
  = 0010 0001 0000 0000 0000(135168)

135168也就是PROPERTY_USAGE_SCRIPT_VARIABLE|PROPERTY_USAGE_NIL_IS_VARIANT

所以,异或可以对标志进行开关

小练习

  1. 下面的代码会输出什么?为什么?
gdscript
print(100 / 2)
print(100 / 2.0)
print(float(100) / float(2))
  • 下面代码的输出结果是?
gdscript
print(-7 % 3)
print(posmod(-7, 3))
print(fmod(-7.5, 3.0))
  • 最终的计算结果是多少?
gdscript
var result = 2
result *= 3 + 1
  • 下面的代码会运行成功吗?如果不会,哪里错了?
gdscript
var a = 5
var b = a % 2.0
print(b)
  • 实践

    你正在制作一个房间温控系统。房间的初始温度是 15°C,每秒加热 2.5°C,最多升到 25°C 为止。

    使用下面的模板,写一段代码,模拟每秒之后的温度变化(共模拟10秒,即print10次),并在每秒输出当前温度。

    (提示:使用加法运算符和 min() 函数,防止超过最大温度)

    gdscript
    var last_time: float = 0
    
    func _process(delta: float) -> void:
        if Time.get_ticks_msec() / 1000.0 - last_time > 1.0:
        
            # 替换这里,这里的代码每一秒都会执行
            
            last_time = Time.get_ticks_msec() / 1000.0