【Godot4.2】GDScript数组分类及类型化数组和紧缩数组概述

概述

GDScript的数组是一种很常用的数据类型。本文主要阐述一下GDScript数组分类,以及官方文档和大多数视频或教程较少提及的类型化数组和紧缩数组。

GDScript数组分类

通过反复查阅GDScript内置文档并进行细节比较,发现GDScript的数组,可以划分为三类

  • 普通数组Array,不限定元素的类型,同一个数组可以存储不同类型的数据元素。
  • 类型化数组Array[type],在Array的基础上限定只能存储一种类型的数据元素。
  • 紧缩数组Packed*Array,数据紧密存放,在数组比较大时可以节省内存。包括:PackedInt32ArrayPackedInt64ArrayPackedFloat32ArrayPackedFloat64ArrayPackedStringArrayPackedVector2ArrayPackedVector3ArrayPackedColorArrayPackedByteArray。其中PackedByteArray代表二进制的字节数组,与其他紧缩数组在代表的意义和所提供的方法方面是完全不同的。

关于数组分类总结如下表:

分组中文名称类型(typeof)备注
普通数组Array普通数组TYPE_ARRAY元素类型可不一致
类型化数组Array[type]类型化数组TYPE_ARRAY元素类型必须一致
紧缩数组PackedByteArray字节紧缩数组TYPE_PACKED_BYTE_ARRAY音频、图片等可能会以此形式存储
PackedInt32Array32位整数紧缩数组TYPE_PACKED_INT32_ARRAY紧缩数组中比较特殊的一位
PackedInt64Array64位整数紧缩数组TYPE_PACKED_INT64_ARRAY方法完全一样,但参数不一样
PackedFloat32Array32位浮点数紧缩数组TYPE_PACKED_FLOAT32_ARRAY
PackedFloat64Array64位浮点数紧缩数组TYPE_PACKED_FLOAT64_ARRAY
PackedStringArray字符串紧缩数组TYPE_PACKED_STRING_ARRAY
PackedVector2ArrayVector2紧缩数组TYPE_PACKED_VECTOR2_ARRAY
PackedVector3ArrayVector3紧缩数组TYPE_PACKED_VECTOR3_ARRAY
PackedColorArrayColor紧缩数组TYPE_PACKED_COLOR_ARRAY

普通数组

GDScript普通数组的使用方法,请查阅:
【Godot4.2】普通数组Array使用全解析 一文。

类型化数组

  • 类型化数组是在普通数组之上添加了一层限定,即限定了所存储的元素类型
  • 形式为Array[type],其中type可以是基础数据类型或者Object及其子类型(包括各种NodeResource等)。

申明与创建

可以用如下形式创建类型化数组:

var arr1:Array[int]          # 申明一个元素都是int类型的数组
var arr2:Array[String]       # 申明一个元素都是String类型的数组
var arr3:Array[Button]       # 申明一个元素都是Button控件的数组
var arr4:Array[PackedScene]  # 申明一个元素都是PackedScene的数组

可以看到,只需要对申明的数组变量用Array[type]形式显式申明其类型即可。
其他的操作与普通Array没有区别。

同时Array提供了一个构造函数,可以用构造函数形式创建类型化数组。其形式如下:

Array(base:Array,type:int,class_name:StringName,script:Variant)

其中:

  • base:是要被类型化的Array数组,可以传入一个空数组。
  • type:指定元素的类型,基础数据类型intfloatString等,以及内置或自定义的NodeResource
  • class_name:是具体的类名,比如ButtonPackedScene等。
  • script:自定义节点类型或资源类型的脚本?(尚有疑问,谨待确认)

比如,申明一个PackedScene类型作为元素的类型化数组,我们可以用常用形式:

var arr:Array[PackedScene]     # 形式1

也可以用构造函数形式:

var arr = Array([],TYPE_OBJECT,"PackedScene",null)   # 形式2

两者申明的类型化数组没有本质上的区别,只是后者提供了一种字符串参数形式创建的类型化数组的方法,在某些场景下可能用得到。

数组的类型化判断以及元素类型信息获取

Array类型提供了几个方法用于判断数组是否是类型化数组,以及获取元素类信息等。

  • is_typed():判断一个数组是否是类型化的。
    注意Packed*Array不算在Array或者类型化数组范畴,也就没有is_typed()等方法,所以不能用is_typed()判断其是否类型化。
var arr1:Array[PackedScene]
var arr2 = []

print(arr1.is_typed()) # true
print(arr2.is_typed()) # flase
  • is_same_typed():判断两个类型化数组的类型是否相同。
var arr1:Array[PackedScene]
var arr2:Array[PackedScene]
var arr3:Array[int]

print(arr1.is_same_typed(arr2)) # true
print(arr1.is_same_typed(arr3)) # flase
  • get_typed_builtin():返回类型化的数组的内置类型(Variant.Type),如果是内置数据类型,返回相应的类型常量,如果是节点或资源类型,统一返回TYPE_OBJECT (数值24)
var arr1:Array[int]
var arr2:Array[Button]
var arr3:Array[PackedScene]

print(arr1.get_typed_builtin()) # 2 = TYPE_INT
print(arr2.get_typed_builtin()) # 24 = TYPE_OBJECT
print(arr3.get_typed_builtin()) # 24 = TYPE_OBJECT
  • get_typed_class_name()返回类型化数组具体的元素类型名称,基础数据类型返回空字符串,节点或资源类型返回具体类名。
var arr1:Array[int]
var arr2:Array[Button]
var arr3:Array[PackedScene]

print(arr1.get_typed_class_name()) # ""
print(arr2.get_typed_class_name()) # "Button"
print(arr3.get_typed_class_name()) # "PackedScene"
  • get_typed_script():如果是自定义节点或资源类型,可以返回其脚本对象,内置数据类型或内置节点、资源类型,则返回<Object#null>
var arr:Array[PackedScene]
print(arr.get_typed_builtin())     # 24 = TYPE_OBJECT
print(arr.get_typed_class_name())  # "PackedScene"
print(arr.get_typed_script())      # <Object#null>

紧缩数组

Packed*Array形式的数组类型被称为“紧缩数组”类型。包括:

中文名称类型(typeof)
PackedByteArray字节紧缩数组TYPE_PACKED_BYTE_ARRAY
PackedInt32Array32位整数紧缩数组TYPE_PACKED_INT32_ARRAY
PackedInt64Array64位整数紧缩数组TYPE_PACKED_INT64_ARRAY
PackedFloat32Array32位浮点数紧缩数组TYPE_PACKED_FLOAT32_ARRAY
PackedFloat64Array64位浮点数紧缩数组TYPE_PACKED_FLOAT64_ARRAY
PackedStringArray字符串紧缩数组TYPE_PACKED_STRING_ARRAY
PackedVector2ArrayVector2紧缩数组TYPE_PACKED_VECTOR2_ARRAY
PackedVector3ArrayVector3紧缩数组TYPE_PACKED_VECTOR3_ARRAY
PackedColorArrayColor紧缩数组TYPE_PACKED_COLOR_ARRAY

紧缩数组类型与普通数组、类型化数组的关系

  • ArrayPacked*Array在内存中都是连续存放的,但是前者存放的是Variant类型, Variant类型固定占20字节,并且可以在其中存储几乎任何引擎数据类型。
  • 类型化数组是限定Array只能存储一种类型的数据元素,也就是将Variant限定为了具体的数据类型(比如说int),但其Array的本质和用Variant类型存储数据元素的本质没有变化。
  • 而具体的Packed*Array,则使用相应的具体类型,而不是Variant类型存储元素数据,所以相比类型化数组更加紧凑,所以相对普通Array和类型化数组Array[type]被称为紧缩数组

在这里插入图片描述

字节紧缩数组(PackedByteArray)

字节紧缩数组PackedByteArray算是比较特殊的一种紧缩数组,它的API和其他几种紧缩数组的不同,用途也不同

数组和紧缩数组间的转化关系

  • 普通数组Array(包括类型化数组Array[type])可以通过Packed*Array(Array)形式也就是相应的紧缩数组的构造函数形式转化为紧缩数组,其过程会对元素类型进行强制转换;
var arr1:Array = [1,"张三",Button.new()]
var pk_arr1 = PackedInt32Array(arr1)
var pk_arr2 = PackedFloat32Array(arr1)
var pk_arr3 = PackedStringArray(arr1)
var pk_arr4 = PackedByteArray(arr1)

print(arr1)    # [1, "张三", <Button#7394641913158>]
print(pk_arr1) # [1, 0, 0]
print(pk_arr2) # [1, 0, 0]
print(pk_arr3) # ["1", "张三", "<Button#6977593879327>"]
print(pk_arr4) # [1, 0, 0]
var arr1:Array[Button] = [Button.new(),Button.new()]
var pk_arr1 = PackedInt32Array(arr1)
var pk_arr2 = PackedFloat32Array(arr1)
var pk_arr3 = PackedStringArray(arr1)
var pk_arr4 = PackedByteArray(arr1)

print(arr1)    # [<Button#8468215966358>, <Button#8468266298058>]
print(pk_arr1) # [0, 0]
print(pk_arr2) # [0, 0]
print(pk_arr3) # ["<Button#8468215966358>", "<Button#8468266298058>"]
print(pk_arr4) # [0, 0]
  • Packed*Array(Array)可以通过to_byte_array()方法转换为PackedByteArray
var arr1:PackedInt32Array = [1,2,4,5,6,7,8]
var bt_arr1 = arr1.to_byte_array()

print(bt_arr1 is PackedByteArray) # true
  • PackedByteArray则可以使用to_float32_array()to_float64_array()to_int32_array()to_int64_array()转化为PackedFloat32Array PackedFloat64Array PackedInt32Array PackedInt64Array

普通数组转字节紧缩数组

var arr = ["张三","李四","王五"]
	
print(PackedByteArray(arr)) # [0, 0, 0]
var arr:PackedStringArray = ["张三","李四","王五"]
	
print(arr.to_byte_array()) # [208, 234, 206, 112, 47, 1, 0, 0, 192, 232, 206, 112, 47, 1, 0, 0, 128, 233, 206, 112, 47, 1, 0, 0]

可以看到普通的字符串数组用PackedByteArray()构造函数直接转换是无效的。
而是应该将数组显示申明为PackedStringArray类型,再调用to_byte_array()方法转换为PackedByteArray

var arr = [1,2,3]
	
print(PackedByteArray(arr)) # [1,2,3]
var arr = [1.5,23.45,36]
	
print(PackedByteArray(arr)) # [1, 23, 36]

普通的纯数字数组通过PackedByteArray()构造函数直接转换有效,但浮点数会被自动转化为整数(向下取整)。


提示
直接用print()方式打印PackedByteArray其每个字节都显示为10进制数字,有时候不是太利于理解。
在《对数组的函数扩充》一文中,编写了相应的函数可以将10进制显示为2进制。下文中显示的二进制形式就是基于相应函数而来。


整形、浮点型紧缩数组转PackedByteArray

var arr1:PackedInt32Array = [1]
var arr2:PackedInt64Array = [1]
var arr3:PackedFloat32Array = [1.5]
var arr4:PackedFloat64Array = [1.5]

print(arr1.to_byte_array()) # [1, 0, 0, 0]
# [00000001,00000000,00000000,00000000]

print(arr2.to_byte_array()) # [1, 0, 0, 0, 0, 0, 0, 0]
# [00000001,00000000,00000000,00000000,00000000,00000000,00000000,00000000]

print(arr3.to_byte_array()) # [0, 0, 192, 63]
# [00000000,00000000,11000000,00111111]

print(arr4.to_byte_array()) # [0, 0, 0, 0, 0, 0, 248, 63]
# [00000000,00000000,00000000,00000000,00000000,00000000,11000000,00111111]

可以看到:

  • Int32Float32占4字节,Int64Float64占8字节。
  • 因此PackedInt32ArrayPackedFloat32Array的一个元素转为PackedByteArray的4个元素,分别对应4个字节
  • 反过来PackedByteArrayPackedInt32ArrayPackedFloat32Array时,是将4个元素转化为1个整数

下图表示一个包含2个元素的PackedInt32Array,在内存中的实际表示。而其每个字节组成的数组就可以看为其PackedByteArray形式。

PackedStringArray转PackedByteArray

var arr1:PackedStringArray = ["a"]
var arr2:PackedStringArray = ["啊"]
var arr3:PackedStringArray = ["a","b","c"]
var arr4:PackedStringArray = ["啊","你好","张三"]

print(arr1.to_byte_array()) # [16, 34, 29, 73, 196, 2, 0, 0]

print(arr2.to_byte_array()) # [80, 27, 29, 73, 196, 2, 0, 0]

print(arr3.to_byte_array()) 
# [16, 34, 29, 73, 196, 2, 0, 0, 144, 90, 29, 73, 196, 2, 0, 0, 208, 35, 29, 73, 196, 2, 0, 0]

print(arr4.to_byte_array()) 
# [80, 27, 29, 73, 196, 2, 0, 0, 128, 119, 41, 72, 196, 2, 0, 0, 0, 121, 41, 72, 196, 2, 0, 0]
print("a".to_ascii_buffer())   # [97]
print("a".to_utf8_buffer())	   # [97]
print("a".to_utf16_buffer())   # [97, 0]
print("a".to_utf32_buffer())   # [97, 0, 0, 0]
print("a".to_wchar_buffer())   # [97, 0]
var string = "张三"
var byte = string.to_utf8_buffer()
print(byte)	              # [229, 188, 160, 228, 184, 137]
print(slices_arr(byte,3)) # [[229, 188, 160], [228, 184, 137]]
print(show_byte_array_string(byte,3))
# ["11100101", "10111100", "10100000"],
# ["11100100", "10111000", "10001001"]

可以看到PackedStringArray转为PackedByteArray后,存储的并不是字符串本身的二进制编码形式,而是指向字符转在内存中的地址(地址占8个字节)。

PackedColorArray --> PackedByteArray

Color以RGBA形式构造,每一个分量为一个Float32,则在PackedByteArray中一个颜色是由四组四个字节的形式表示。

var arr:PackedColorArray = [Color.YELLOW]
var byte = arr.to_byte_array()

print(byte)	# [0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 128, 63]

print(slices_arr(byte,4)) 
# [[0, 0, 128, 63], [0, 0, 128, 63], [0, 0, 0, 0], [0, 0, 128, 63]]
# [r,g,b,a]

print(show_byte_array_string(byte,4))
# ["00000000", "00000000", "10000000", "00111111"],    # R
# ["00000000", "00000000", "10000000", "00111111"],    # G
# ["00000000", "00000000", "00000000", "00000000"],    # B
# ["00000000", "00000000", "10000000", "00111111"]     # A

PackedVector2Array/PackedVector3Array --> PackedByteArray

var arr:PackedVector2Array = [Vector2(100,100)]
	
var byte = arr.to_byte_array()
print(byte)	              # [0, 0, 200, 66, 0, 0, 200, 66]
print(slices_arr(byte,4)) # [[0, 0, 200, 66], [0, 0, 200, 66]]

print(show_byte_array_string(byte,4))
# ["00000000", "00000000", "11001000", "01000010"],   # X
# ["00000000", "00000000", "11001000", "01000010"]    # Y
var arr:PackedVector3Array = [Vector3(100,100,100)]
	
var byte = arr.to_byte_array()
print(byte)	              # [0, 0, 200, 66, 0, 0, 200, 66, 0, 0, 200, 66]
print(slices_arr(byte,4)) # [[0, 0, 200, 66], [0, 0, 200, 66], [0, 0, 200, 66]]

print(show_byte_array_string(byte,4))
# ["00000000", "00000000", "11001000", "01000010"],  # X
# ["00000000", "00000000", "11001000", "01000010"],  # Y
# ["00000000", "00000000", "11001000", "01000010"]   # Z

基础数据类型与二进制形式转换

字符串转二进制

print("a".to_ascii_buffer())   # [97]
print("a".to_utf8_buffer())	   # [97]
print("a".to_utf16_buffer())   # [97, 0]
print("a".to_utf32_buffer())   # [97, 0, 0, 0]
print("a".to_wchar_buffer())   # [97, 0]
  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巽星石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值