ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Godot Array 类型完全指南:动态数组、类型化数组与函数式操作实战(godot-docs)

Godot Array 类型完全指南:动态数组、类型化数组与函数式操作实战(godot-docs) 文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载Array 是 Godot 内置的核心容器类型用于保存任意 Variant 元素的序列。本文以 class_array.rst 官方类参考为骨架结合 GDScript 基础 与 C# 集合对照 等仓库资料系统讲解 Array 的构造、索引、全部 49 个方法、运算符语义、类型化数组与压缩数组的取舍以及遍历与复制时的注意事项帮助你写出正确、高效、可维护的数组代码。Array 是什么Array 是一种内置数据结构默认情况下可以容纳任意 Variant 类型的元素序列。通过创建typed array类型化数组可以将值约束为特定类型。元素通过从0开始的数值索引访问负索引从尾部倒数-1是最后一个元素-2是倒数第二个以此类推。var array [First, 2, 3, Last] print(array[0]) # Prints First print(array[2]) # Prints 3 print(array[-1]) # Prints Last array[1] Second print(array[1]) # Prints Second print(array[-3]) # Prints Second # 这个类型化数组只能包含整数。 # 尝试添加任何其他类型都会报错。 var typed_array: Array[int] [1, 2, 3]C# 中对应Godot.Collections.Array索引语义一致^1表示最后一个元素类型化数组写作Godot.Collections.ArrayintGodot.Collections.Array array [First, 2, 3, Last]; GD.Print(array[0]); // Prints First GD.Print(array[2]); // Prints 3 GD.Print(array[^1]); // Prints Last array[1] Second; GD.Print(array[1]); // Prints Second GD.Print(array[^3]); // Prints Second // 这个类型化数组只能包含整数。 Godot.Collections.Arrayint typedArray [1, 2, 3];三个必须牢记的核心语义1. 按引用传递Array 总是按引用reference传递。如果你希望获得一个可独立于原数组修改的副本必须使用duplicate()详见复制与切片一节。直接赋值var b a只是让b与a指向同一个底层结构。2. 迭代期间禁止删除元素在遍历数组的同时擦除erase元素是不被支持的会导致不可预测的行为。如果你需要在迭代中修改内容官方建议改用for i in array.size()配合索引赋值见 gdscript_basics.rst 的 for 循环说明。3. 布尔上下文中的求值规则在布尔上下文中空数组[]求值为false非空数组始终求值为true。这在编写if my_array:这类条件判断时需要留意——它判断的是是否为空而不是是否有某个元素。三种数组类型压缩数组、类型化数组、非类型化数组类型迭代/修改速度内存灵活性压缩数组Packed Array一般最快最小最低缺少map()等便捷方法类型化数组Typed Array较快中等中等元素类型受限非类型化数组Untyped Array较慢较大最高原文档明确指出压缩数组通常比同类型数组如 PackedInt64Array 对比Array[int]迭代和修改更快、占用内存更少其代价是灵活性低不提供map()这类便捷方法。类型化数组又比非类型化数组迭代和修改更快。gdscript_basics.rst 的 Packed arrays 小节 进一步补充了选型建议当数组足够大成千上万个元素且数据类型与某个Packed类型匹配时使用压缩数组可同时改善内存占用与迭代/修改性能若数组规模不大如远未达到数万元素常规或类型化数组提供的便捷方法更利于编写和维护数据是已知类型包括自定义类时优先使用类型化数组。类型化数组的 GDScript 语法为Array[Type]Type可以是任意 Variant 类型、原生类、用户类或枚举不支持嵌套数组类型如Array[Array[int]]。Array与Array[Variant]等价。类型化数组的类型是内存结构的一个属性因此不能把Array[Node2D]直接赋给Array[Node]变量即使 Node2D 是 Node 的子类需要转换时用assign()方法复制内容而非引用var a: Array[Node2D] [Node2D.new()] # (OK) Node2D 继承自 Node可以放入 Array[Node] var b: Array[Node] [a[0]] # (Error) 不能将 Array[Node2D] 赋给 Array[Node] 变量 # b a # (OK) 用 assign() 复制内容而不是引用 b.assign(a)唯一的例外是Array即Array[Variant]类型这是为兼容旧代码做的便利设计——但对非类型化数组的操作被视为不安全操作。另外注意类型化数组目前在可变参数variadic函数中不受支持无法写出...values: Array[int]。构造函数Array()构造空数组构造一个空的 Array。Array(base, type, class_name, script)从 base 构造类型化数组从base数组创建类型化数组。类型化数组只能包含给定类型的元素或继承自给定类的元素。参数含义type内置 Variant 类型取 Variant.Type 枚举常量之一class_name内置类名参见 Object.get_class()script关联的脚本必须是 Script 实例或null。如果type不是TYPE_OBJECT则class_name必须为空StringName、script必须为null。class_name Sword extends Node class Stats: pass func _ready(): var a Array([], TYPE_INT, , null) # Array[int] var b Array([], TYPE_OBJECT, Node, null) # Array[Node] var c Array([], TYPE_OBJECT, Node, Sword) # Array[Sword] var d Array([], TYPE_OBJECT, RefCounted, Stats) # Array[Stats]base数组的元素会在必要时进行转换。如果无法转换或base本身已是类型化数组则构造失败并返回空 Array。在 GDScript 中通常不需要这个构造函数静态类型即可创建类型化数组var numbers: Array[float] [] var children: Array[Node] [$Node, $Sprite2D, $RigidBody3D] # 浮点字面量会被转换为整数 var integers: Array[int] [0.2, 4.5, -2.0] print(integers) # Prints [0, 4, -2]Array(from: Array)返回同一数组返回与from相同的数组引用非副本。需要副本请用duplicate()。从压缩数组构造Array(from: PackedByteArray)、Array(from: PackedColorArray)、Array(from: PackedFloat32Array)、Array(from: PackedFloat64Array)、Array(from: PackedInt32Array)、Array(from: PackedInt64Array)、Array(from: PackedStringArray)、Array(from: PackedVector2Array)、Array(from: PackedVector3Array)、Array(from: PackedVector4Array)分别从对应的压缩数组构造普通数组。这是压缩数组与普通数组互转的官方入口之一。元素的增删改核心增删方法方法签名要点行为append(value)push_back()的别名在数组末尾追加valueappend_array(array)—将另一个array追加到本数组末尾push_back(value)—在末尾追加一个元素push_front(value)—在开头添加一个元素会移动所有其他元素的索引大数组上有明显性能开销insert(position, value)返回 Error在position可为负数相对末尾插入元素返回OK或错误常量position之后的索引都要前移大数组开销明显erase(value)按值删除找到并移除value的第一次出现不存在则什么都不做删除后所有后续索引回移remove_at(position)按下标删除删除position处元素负数相对末尾越界会失败需要返回值用pop_at()按值删除用erase()pop_back()删除并返回移除并返回最后一个元素空数组返回null且不报错pop_front()删除并返回移除并返回第一个元素空数组返回null且不报错其余元素索引回移pop_at(position)删除并返回移除并返回position处元素负数相对末尾空数组返回null越界会生成错误信息clear()清空移除所有元素等价于resize(0)resize(size)调整大小设为size个元素缩小则删除末尾扩大则添加默认元素通常为null取决于数组类型。返回OK、ERR_LOCKED只读数组、ERR_INVALID_PARAMETERsize 为负或ERR_OUT_OF_MEMORY。一次性resize后赋值比逐个append更快fill(value)批量赋值将value赋给所有元素常与resize()组合使用set(index, value)按下标赋值与array[index] value等价不改变数组大小assign(array)整体赋值把另一数组的元素复制进本数组按需 resize类型化数组会执行类型转换append_array示例var numbers [1, 2, 3] var extra [4, 5, 6] numbers.append_array(extra) print(numbers) # Prints [1, 2, 3, 4, 5, 6]resizefill组合GDScript 与 C# 对照var array [] array.resize(5) array.fill(2) print(array) # Prints [2, 2, 2, 2, 2]Godot.Collections.Array array []; array.Resize(5); array.Fill(2); GD.Print(array); // Prints [2, 2, 2, 2, 2]注意如果fill()的value是引用类型 Variant继承自 Object、Array、Dictionary 等数组会被填充为对同一个 value 的引用而不是副本。查询与搜索find 系列与成员检查方法说明size()返回元素个数空数组返回0is_empty()返回true当且仅当数组为空has(value)返回是否包含valueGDScript 等价于in操作符C# 中改名为Containscount(value)返回value在数组中出现的次数按条件计数请用reduce()find(what, from 0)返回what第一次出现的索引无则返回-1from指定搜索起点rfind(what, from -1)返回what最后一次出现的索引无则返回-1find()的逆向版本find_custom(callable, from 0)返回第一个使callable返回true的元素索引无则-1rfind_custom(callable, from -1)从后向前查找第一个满足callable的元素索引front()返回第一个元素空数组失败并返回null与array[0]不同只产生错误不中断项目执行back()返回最后一个元素空数组失败并返回null与array[-1]不同get(index)返回index处元素越界或负索引失败并返回null。与[]操作符类似但不完全相同失败时不会在编辑器中暂停项目执行min()所有元素可比较时返回最小值否则返回nullmax()所有元素可比较时返回最大值否则返回null自定义比较器可用reduce()实现pick_random()返回随机一个元素空数组报错并返回nullhash()返回代表数组及其内容的 32 位哈希整数。哈希值相同的数组不一定相同哈希碰撞哈希值不同的数组必然不同has()与in操作符示例print([inside, 7].has(inside)) # Prints true print([inside, 7].has(outside)) # Prints false print([inside, 7].has(7)) # Prints true print([inside, 7].has(7)) # Prints false if 4 in [2, 4, 6, 8]: print(4 is here!) # Will be printed.C# 对照方法更名为ContainsGodot.Collections.Array arr [inside, 7]; GD.Print(arr.Contains(inside)); // Prints True GD.Print(arr.Contains(outside)); // Prints False GD.Print(arr.Contains(7)); // Prints True GD.Print(arr.Contains(7)); // Prints False性能注意出于性能考虑find()/has()的搜索会受到what的Variant.Type影响。例如7int和7.0float对这两个方法而言不相等。find_custom配合bind()传递额外参数func is_even(number): return number % 2 0 func _ready(): print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2 func is_specific_number(number, expected): return number expected func _ready(): print([1, 3, 4, 7].find_custom(is_specific_number.bind(4))) # Prints 2函数式方法map / filter / reduce / all / any这四个方法是函数式编程风格的支柱callable通常只接收当前数组元素一个参数reduce例外接收两个。map(callable)映射对每个元素调用callable返回由返回值组成的新数组。callable接收一个元素参数可返回任意 Variant。func double(number): return number * 2 func _ready(): print([1, 2, 3].map(double)) # Prints [2, 4, 6] # 同样效果使用 lambda 函数 print([1, 2, 3].map(func(element): return element * 2))filter(callable)过滤对每个元素调用callable返回新过滤数组。callable返回true则保留该元素false则排除。func is_even(number): return number % 2 0 func _ready(): print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8] # 同样效果使用 lambda 函数 print([1, 4, 5, 8].filter(func(number): return number % 2 0))reduce(callable, accum null)归约对每个元素调用callable将结果累积到accum并返回。callable接收两个参数当前累积值accum和当前元素。若accum为null默认迭代从第二个元素开始第一个元素作为accum的初始值。func sum(accum, number): return accum number func _ready(): print([1, 2, 3].reduce(sum, 0)) # Prints 6 print([1, 2, 3].reduce(sum, 10)) # Prints 16 # lambda 写法 print([1, 2, 3].reduce(func(accum, number): return accum number, 10))reduce的三个高级用途——自定义比较器、按条件计数替代count()# 自定义比较器找出最长向量 func _ready(): var arr [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)] var longest_vec arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max) print(longest_vec) # Prints (3, 4) func is_length_greater(a, b): return a.length() b.length() # 按条件计数 func is_even(number): return number % 2 0 func _ready(): var arr [1, 2, 3, 4, 5] # 当前元素是偶数则计数加一否则保持不变 var even_count arr.reduce(func(count, next): return count 1 if is_even(next) else count, 0) print(even_count) # Prints 2all(callable)与any(callable)全称与存在性判断all()对所有元素调用callable全部返回true才返回true有一个以上返回false即返回false。any()至少一个元素使callable返回true即返回true全部为false才返回false。两者都支持 lambda。空数组语义不同all()对空数组恒返回true空真原则vacuous truthany()对空数组恒返回false。func greater_than_5(number): return number 5 func _ready(): print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 个元素为 true) print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 个元素为 true) print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 个元素为 true) print([].all(greater_than_5)) # Prints true (0/0 个元素为 true) print([6, 10, 6].any(greater_than_5)) # Prints true (3 个元素为 true) print([4, 10, 4].any(greater_than_5)) # Prints true (1 个元素为 true) print([4, 4, 4].any(greater_than_5)) # Prints false (0 个元素为 true) print([].any(greater_than_5)) # Prints false (0 个元素为 true) # lambda 写法 print([6, 10, 6].all(func(element): return element 5)) # Prints true print([6, 10, 6].any(func(number): return number 5)) # Prints true性能提示与用filter()结果的长度判断相比all()/any()会尽早返回以提升性能尤其对大数组。排序sort()升序排序按元素的小于比较升序排列。var numbers [10, 5, 2.5, 8] numbers.sort() print(numbers) # Prints [2.5, 5, 8, 10]Godot.Collections.Array numbers [10, 5, 2.5, 8]; numbers.Sort(); GD.Print(numbers); // Prints [2.5, 5, 8, 10]注意所用排序算法不稳定not stable等价元素如2与2.0的相对顺序可能被改变。sort_custom(func)自定义排序func按需被调用接收两个元素作为参数返回true表示第一个元素应排在第二个之前返回false则反之。func sort_ascending(a, b): if a[1] b[1]: return true return false func _ready(): var my_items [[Tomato, 5], [Apple, 9], [Rice, 4]] my_items.sort_custom(sort_ascending) print(my_items) # Prints [[Rice, 4], [Tomato, 5], [Apple, 9]] # lambda 写法降序 my_items.sort_custom(func(a, b): return a[1] b[1]) print(my_items) # Prints [[Apple, 9], [Tomato, 5], [Rice, 4]]对文件名做自然顺序排序是sort_custom的典型场景配合 String.naturalnocasecmp_to()var files [newfile1, newfile2, newfile10, newfile11] files.sort_custom(func(a, b): return a.naturalnocasecmp_to(b) 0) print(files) # Prints [newfile1, newfile2, newfile10, newfile11]使用注意C# 中不支持sort_custom排序算法不稳定不要随机化func的返回值——堆排序算法要求一致的结果随机化会导致意外行为。二分搜索bsearch(value, before true)在已排序数组上使用二分查找返回value的索引找不到时返回应插入以保持有序的位置。before为true默认时返回的索引位于所有与value相等的既有元素之前。var numbers [2, 4, 8, 10] var idx numbers.bsearch(7) numbers.insert(idx, 7) print(numbers) # Prints [2, 4, 7, 8, 10] var fruits [Apple, Lemon, Lemon, Orange] print(fruits.bsearch(Lemon, true)) # Prints 1, 指向第一个 Lemon print(fruits.bsearch(Lemon, false)) # Prints 3, 指向 Orange对未排序数组调用bsearch()会产生意外结果务必先sort()。bsearch_custom(value, func, before true)与bsearch()相同但用func做比较。func接收一个数组元素和value两个参数返回true表示该数组元素应排在value之后。func sort_by_amount(a, b): if a[1] b[1]: return true return false func _ready(): var my_items [[Tomato, 2], [Kiwi, 5], [Rice, 9]] var apple [Apple, 5] # Apple 插入到 Kiwi 之前 my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple) var banana [Banana, 5] # Banana 插入到 Kiwi 之后 my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana) # Prints [[Tomato, 2], [Apple, 5], [Kiwi, 5], [Banana, 5], [Rice, 9]] print(my_items)同样地bsearch_custom要求数组已按func排序可先用sort_custom(func)排序。复制与切片duplicate / duplicate_deep / sliceduplicate(deep false)返回数组的新副本。默认浅拷贝所有嵌套的 Array、Dictionary、Resource 元素与原数组共享在一方修改会影响到另一方。deep为true时返回深拷贝嵌套数组和字典被递归复制但Resource 仍然共享。duplicate_deep(deep_subresources_mode 1)类似duplicate(true)的深拷贝但对子资源处理有额外控制。deep_subresources_mode必须是 Resource.DeepDuplicateMode 枚举的值默认只递归复制内部资源。slice(begin, end INT_MAX, step 1, deep false)返回包含从begin含到end不含元素的新数组每隔step取一个。begin/end为负时相对数组末尾step为负时反向迭代返回倒序切片此时begin必须大于enddeep为true时递归复制切片中的嵌套 Array 与 Dictionary。var letters [A, B, C, D, E, F] print(letters.slice(0, 2)) # Prints [A, B] print(letters.slice(2, -2)) # Prints [C, D] print(letters.slice(-2, 6)) # Prints [E, F] print(letters.slice(0, 6, 2)) # Prints [A, C, E] print(letters.slice(4, 1, -1)) # Prints [E, D, C]只读与类型信息查询方法说明is_read_only()返回数组是否为只读make_read_only()将数组设为只读元素不能被覆盖、顺序不能改变不作用于嵌套元素如字典。GDScript 中声明为const的数组自动只读is_typed()返回数组是否为类型化数组。类型化数组的方法仍返回通用 Variantis_same_typed(array)返回本数组与给定array的类型化方式是否相同get_typed_builtin()返回类型化数组的内置 Variant 类型常量非类型化返回TYPE_NILget_typed_class_name()若内置类型为TYPE_OBJECT返回类型化数组的内置类名否则返回空 StringNameget_typed_script()返回与该类型化数组关联的 Script 实例不存在返回nullvar numbers: Array[float] [0.2, 4.2, -2.0] print(numbers.is_typed()) # Prints true此外还有reverse()反转所有元素顺序与shuffle()随机打乱元素顺序。shuffle()与pick_random()一样使用全局共享随机种子要获得可预测的结果可先调用 GlobalScope.seed()。# 可能打印 1、2、3.25 或 Hi print([1, 2, 3.25, Hi].pick_random())运算符运算符返回语义array[index]Variant按索引取元素索引 0 起负数从尾部取越界访问会产生运行时错误在编辑器中会暂停项目执行array1 array2Array拼接把右侧数组追加到左侧产生新数组。对已有数组append_array()比/更高效array1 array2bool长度与内容全部相等才为truearray1 ! array2bool长度或任一元素不同即为true、、、bool从索引 0 起逐对比较直到两个数组共同长度的末尾逐对比较出大小即返回若所有比较过的元素都相等则由数组长度决定结果运算符示例var array1 [One, 2] var array2 [3, Four] print(array1 array2) # Prints [One, 2, 3, Four]C# 中注意原生Array类型不支持拼接但Godot.Collections.Array支持Godot.Collections.Array array1 [One, 2]; Godot.Collections.Array array2 [3, Four]; GD.Print(array1 array2); // Prints [One, 2, 3, Four]遍历 Arrayfor 循环的正确姿势gdscript_basics.rst 说明了遍历数组的两种方式var names [John, Marta, Samantha, Jimmy] for name: String in names: # 类型化循环变量 print(name) # 打印每个名字 # 如果要在迭代过程中赋值最好用索引方式 for i in array.size(): array[i] some_new_value(i)for x in [5, 7, 11]:会把元素依次存入x。注意原文档反复强调的规则不要在遍历数组的同时 erase/pop 元素否则行为不可预测。同时记住range()不会分配数组纯数字循环应优先用for i in range(n)。C# 中的 Array 与压缩数组映射Collections 指南 指出尽管名字是 ArrayGodot Array 更接近 C# 的ListT而非System.Array其大小不固定、可随增删动态伸缩。未类型化的Godot.Collections.Array可等价看作Variant元素数组能容纳任意类型泛型Godot.Collections.ArrayT将元素类型限制为 Variant 兼容类型未类型化数组可通过new Godot.Collections.ArrayT(untypedArray)构造函数转换为类型化数组GDScript 的压缩数组在 C# 中直接使用System.Arraybyte[]、int[]、long[]、float[]、double[]、string[]、Vector2[]、Vector3[]、Vector4[]、Color[]。由于 C# API 与 GDScript 存在差异使用该 API 时请参考 C# 差异指南。例如has()在 C# 中更名为Containssort_custom()在 C# 中不受支持Godot.Collections.Array的拼接也仅在 Godot 集合类型上可用。实战选型建议与易错点清单优先类型化数据类型已知含自定义类时用Array[Type]能获得更快的迭代/修改速度与编译期检查静态类型分析 会考虑类型化数组约束。大批量同质数据用压缩数组达到成千上万个元素、且类型匹配Packed*家族时选择压缩数组换取内存与性能需要map/filter等便捷方法时再转回普通数组。副本用duplicate涉及嵌套结构修改时明确选择浅拷贝默认或深拷贝deeptrue/duplicate_deep并牢记深拷贝仍共享 Resource。插入/删除是 O(n) 操作push_front、insert、erase、remove_at、pop_front都会移动后续元素索引大数组下应评估队列Queue或调整数据结构。二分搜索前提是有序bsearch/bsearch_custom只对已排序数组可靠且sort()/sort_custom()不稳定、sort_custom的比较器必须返回一致结果。遍历期间不改动长度需要增删时先收集索引或改用for i in array.size()模式避免不可预测行为。区分类型敏感比较find/has受 Variant.Type 影响7与7.0不相等布尔上下文只区分空与非空。参考资料Array 类参考本文骨架源GDScript 基础容器类型、类型化数组与压缩数组GDScript 静态类型分析C# 集合指南Array 与 PackedArray 映射C# 与 GDScript 的 API 差异压缩数组类参考PackedByteArray、PackedInt32Array、PackedInt64Array、PackedFloat32Array、PackedFloat64Array、PackedStringArray、PackedVector2Array、PackedVector3Array、PackedVector4Array、PackedColorArray赞分享文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载相关推荐GelEdgeDB数组类型与数组函数完全指南array 的构造、索引、切片与全部 std 数组函数GelEdgeDB数组类型与数组函数完全指南array 的构造、索引、切片与全部 std 数组函数 数组Array是 GelEdgeDB标准库中用数据库图数据库关系型数据库Apache Druid SQL 数组函数ARRAY Functions完全指南类型、语义与底层实现Apache Druid SQL 数组函数ARRAY Functions完全指南类型、语义与底层实现 本文聚焦 Apache Druid SQL 中针对数据库OLAP大数据后端Apache Druid 数组类型ARRAY完全指南摄入、过滤与分组实战Apache Druid 数组类型ARRAY完全指南摄入、过滤与分组实战 Apache Druid 支持 SQL 标准的 ARRAY 类型列涵盖 VAR数据库OLAP大数据后端上一篇Splunk 威胁情报富化管道实战从 Feed 接入到 IOC 生命周期治理下一篇PaddleOCR 基于 PaddleHub Serving 的服务化部署实战指南从文本检测到 PP-Structure 与 KIE 一键上线创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表