Godot Array深度解析:从基础操作到性能优化实战
1. 从“容器”到“瑞士军刀”重新认识Godot中的Array如果你是从其他编程语言转战Godot的可能会觉得Array不就是个数组嘛有什么好讲的在C里是std::vector在Python里是list在JavaScript里是Array概念都差不多。刚开始用GDScript时我也这么想直到我在一个需要频繁进行元素查找、删除中间项、又希望保持顺序的项目里被性能问题狠狠教育了一次。那时我才意识到Godot的Array远不止是一个简单的线性容器它更像是一把集成了多种功能的“瑞士军刀”用对了事半功倍用错了则可能成为性能瓶颈。简单来说Godot 4.2中的Array是一个动态的、类型化的可选、可存储任意类型对象的序列容器。它解决了我们在游戏开发中管理一组有序数据的核心需求比如管理一队敌人的引用、存储关卡中的所有可收集物品ID、或是记录玩家输入的操作序列。但它的能力边界和内部实现逻辑与许多语言中的标准数组有微妙却重要的区别。理解这些区别是写出高效、健壮GDScript代码的关键一步。无论你是刚接触Godot的新手还是已经写过一些脚本的老兵深入理解Array的每一个“刀片”方法及其适用场景都能让你的开发过程更加顺畅。2. Array的创建、类型化与基础操作2.1 三种创建方式与类型化注解在GDScript中创建一个Array非常直观主要有三种方式# 1. 字面量创建 (最常用) var my_array [1, 2, 3, “hello”, Node.new()] # 可以混合类型 var empty_array [] # 空数组 # 2. 使用 Array 构造器 var constructed_array Array() # 创建一个空数组 var from_pool_array Array([100, 200, 300]) # 从另一个数组创建 # 3. 通过类型化注解创建 (Godot 4.0 推荐) var typed_array: Array[int] [1, 2, 3] # 只允许存储int类型 var node_array: Array[Node] [$Sprite2D, $Player] # 只允许存储Node及其派生类型这里需要重点展开的是类型化注解。在Godot 4.0之前GDScript的数组是完全无类型的Array可以放入任何东西。这虽然灵活但极易在运行时因类型错误导致崩溃且编辑器无法提供代码补全和类型检查。从4.0开始你可以使用Array[Type]的语法来指定数组元素的类型。为什么推荐使用类型化数组安全性编译器或脚本编辑器会在你写入错误类型时发出警告甚至直接报错将许多运行时错误提前到编辑期。性能引擎内部可能对已知类型的数组进行优化。可读性与可维护性明确声明了数组的用途其他开发者或未来的你一眼就能看懂里面该存什么。工具链支持编辑器能为你提供精确的代码补全。例如对于一个Array[Node]当你遍历元素时编辑器知道每个元素都是Node可以直接提示.name、.get_parent()等方法。注意类型化注解是“软约束”。在非严格模式下默认如果你尝试typed_array.append(“string”)Godot会抛出错误。但在某些情况下如从无类型数组赋值类型可能被绕过。保持代码清晰主动使用类型化是最佳实践。2.2 增删改查基础四要素对数组最基本的操作就是增删改查。Godot的Array提供了丰富的方法但选择正确的方法很重要。增Append, Insert, Push Backappend(value)/push_back(value)在数组末尾添加一个元素。这是**时间复杂度为O(1)**的操作通常很快。insert(position, value)在指定索引处插入一个元素。这会导致该位置之后的所有元素向后移动一位是一个**时间复杂度为O(n)**的操作。如果数组很大或在循环中频繁调用需谨慎。var arr [“A”, “B”, “D”] arr.append(“E”) # [“A”, “B”, “D”, “E”] arr.insert(2, “C”) # [“A”, “B”, “C”, “D”, “E”]删Remove, Pop, Clearremove_at(position)删除指定索引处的元素。和insert一样它也需要移动元素是**O(n)**操作。pop_back()移除并返回数组的最后一个元素。这是**O(1)**操作非常高效。pop_front()移除并返回数组的第一个元素。这需要移动所有剩余元素是**O(n)**操作。clear()清空整个数组。var arr [10, 20, 30, 40, 50] var last arr.pop_back() # last 50, arr [10, 20, 30, 40] var first arr.pop_front() # first 10, arr [20, 30, 40] arr.remove_at(1) # 删除索引1的元素(30)arr [20, 40]改直接赋值通过索引直接修改元素是最快的操作O(1)。var arr [“apple”, “banana”, “cherry”] arr[1] “blueberry” # arr [“apple”, “blueberry”, “cherry”]查Find, Contains, 索引find(value, from0)从from索引开始查找第一个匹配value的元素返回其索引未找到则返回-1。这是一个线性查找O(n)。rfind(value, from-1)反向查找。has(value)/value in array判断数组是否包含某个值返回布尔值。内部也是线性查找。[index]通过索引直接访问O(1)。务必确保索引在有效范围内0 index size()否则会导致运行时错误。var fruits [“apple”, “banana”, “cherry”, “banana”] var idx fruits.find(“banana”) # idx 1 var last_idx fruits.rfind(“banana”) # last_idx 3 var has_cherry fruits.has(“cherry”) # true var is_in “apple” in fruits # true var first_fruit fruits[0] # “apple”实操心得“查”是性能陷阱高发区find、has、in都是线性查找。如果一个数组有上千个元素并且你在每一帧的_process里都调用has来检查某个值这很快就会成为性能瓶颈。对于需要频繁查找的场景应考虑使用Dictionary哈希表平均O(1)查找或结合其他数据结构。警惕“中间操作”insert、remove_at、pop_front这些涉及数组中间或开头元素的操作在大型数组上代价高昂。在设计数据流时尽量考虑是否能用“尾部操作”append/pop_back或批量操作来替代。3. 迭代、切片与大小管理3.1 多种迭代方式与选择遍历数组是家常便饭Godot提供了几种方式var scores [98, 76, 85, 92] # 1. for...in 循环 (最常用只读遍历) for score in scores: print(score) # 2. 传统的 for i 循环 (需要索引时使用) for i in range(scores.size()): print(“Index “, i, “: “, scores[i]) # 可以在此修改 scores[i] # 3. 使用迭代器 (较少用但更灵活) var it scores.front() while it: print(it.get()) it it.next() # 4. 逆向迭代 for i in range(scores.size()-1, -1, -1): print(scores[i])如何选择绝大多数情况下使用for element in array。它最简洁意图明确。当循环体内需要知道当前元素的索引或者需要根据索引修改数组元素时使用for i in range(array.size())。逆向迭代常用于需要从后向前删除元素时避免索引错乱。3.2 切片快速获取子数组切片Slicing是Python程序员非常熟悉的功能GDScript也支持。它允许你通过指定开始、结束和步长来创建一个原数组的浅拷贝视图。var numbers [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] var slice1 numbers.slice(2, 6) # [2, 3, 4, 5] 索引2到5不包括6 var slice2 numbers.slice(3) # [3, 4, 5, 6, 7, 8, 9] 从索引3到最后 var slice3 numbers.slice(1, 8, 2) # [1, 3, 5, 7] 从1到7步长为2 var slice4 numbers.slice(-3) # [7, 8, 9] 倒数第3个到最后 var slice5 numbers.slice(6, 2, -1) # [6, 5, 4, 3] 逆向切片从6到3重要提示slice()返回的是一个新的Array对象但其中包含的元素引用如果是对象与原数组相同。这意味着修改新数组中某个对象的属性原数组中对应的对象也会改变因为是同一个对象。但如果对新数组进行append、remove_at等结构修改则不会影响原数组。3.3 大小、容量与内存size()返回数组中当前元素的数量。is_empty()判断数组是否为空等价于size() 0但可读性更好。resize(new_size)强制改变数组的大小。如果new_size大于当前大小多出的位置会被填充为null对于Array[Variant]或该类型的默认值对于类型化数组如Array[int]会填充0。如果new_size小于当前大小末尾的元素会被丢弃。shrink_to_fit()这是一个请求建议引擎释放数组未使用的预留内存。注意引擎不保证立即或一定会执行此操作。它主要用于你确定一个数组不会再增长且希望节省内存时。内存管理经验 Godot的Array是动态的内部会预留一些额外的容量capacity以避免每次append都重新分配内存。通常你不需要关心这个。但在处理超大型数组例如数万个元素且生命周期很长时如果经过一波大规模删除操作后数组变得很小但容量依然很大可以调用shrink_to_fit()来尝试释放内存。不过在大多数游戏场景中这点内存优化可能微乎其微优先保证代码清晰更重要。4. 排序、查找与算法操作4.1 自定义排序的威力Godot的Array内置了sort()和sort_custom()方法功能强大。基本排序var numbers [5, 1, 4, 2, 3] numbers.sort() # [1, 2, 3, 4, 5] 升序 var strings [“zebra”, “apple”, “Moon”, “house”] strings.sort() # [“Moon”, “apple”, “house”, “zebra”] 注意默认区分大小写大写字母排前面自定义排序sort_custom(Callable)是真正的利器。它允许你传入一个自定义的比较函数来决定排序规则。# 场景有一组敌人需要按距离玩家的远近排序 var enemies: Array[Node2D] [$Enemy1, $Enemy2, $Enemy3] var player: Node2D $Player # 定义一个比较函数a和b是数组中的两个元素 func _sort_by_distance_to_player(a: Node2D, b: Node2D) - bool: # 返回 true 表示 a 应该排在 b 前面 var dist_a a.global_position.distance_squared_to(player.global_position) var dist_b b.global_position.distance_squared_to(player.global_position) return dist_a dist_b # 距离近的排前面 # 使用 sort_custom 进行排序 enemies.sort_custom(_sort_by_distance_to_player)比较函数规则函数接收两个参数a和b返回一个bool值。返回true表示在排序后的数组中a应该出现在b之前。更复杂的例子多级排序# 对一组单位先按等级降序再按血量升序排序 var units […] func _sort_units(a, b) - bool: if a.level ! b.level: return a.level b.level # 等级高的在前 else: return a.hp b.hp # 等级相同血量少的在前 units.sort_custom(_sort_units)4.2 二分查找与性能飞跃当数组已经排序后线性查找find()就显得很低效。此时应该使用二分查找Binary SearchGodot提供了bsearch()和bsearch_custom()。var sorted_numbers [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] # 使用 bsearch 查找值 var index sorted_numbers.bsearch(45) print(index) # 输出可能是 4。注意bsearch 返回的是“插入位置”不一定是精确匹配的位置。 # 精确查找需要结合值比较 index sorted_numbers.bsearch(40) if index sorted_numbers.size() and sorted_numbers[index] 40: print(“Found at “, index) else: print(“Not found”) # 自定义比较规则的二分查找 var sorted_objects […] # 假设已按某个对象的score属性排序 func _compare_by_score(obj, value): # 自定义比较逻辑返回 obj.score 与 value 的比较结果 # 这需要与排序时使用的规则一致 pass # index sorted_objects.bsearch_custom(value, _compare_by_score)关键点bsearch()的时间复杂度是O(log n)对于大型排序数组查找速度比find()的O(n)快几个数量级。bsearch()返回的是如果要将查找值插入数组并保持有序它应该被放置的索引。因此返回值可能指向一个不等于查找值但位置正确的元素。进行精确查找时必须用返回的索引访问元素并进行值比较。使用bsearch_custom()的前提是数组必须已经按照你提供的自定义比较规则排好序。4.3 其他实用算法操作shuffle()随机打乱数组元素的顺序。常用于抽奖、随机出敌等场景。reverse()将数组元素顺序反转。min()/max()返回数组中的最小值和最大值。对于基本类型int, float直接可用。对于对象数组需要对象支持比较操作符,。count(value)计算特定值在数组中出现的次数。all(method: Callable)/any(method: Callable)高阶函数用于判断数组中的所有元素或任一元素是否满足某个条件。var numbers [1, 2, 3, 4, 5] numbers.shuffle() # 顺序随机化 numbers.reverse() # 顺序反转 var scores [88, 92, 76, 95, 82] var highest scores.max() # 95 var lowest scores.min() # 76 var count_90 scores.count(90) # 0 # 判断数组中的所有数字是否都是正数 var all_positive numbers.all(func(x): return x 0) # true5. 二维数组、数组的数组与扁平化处理Godot没有内置的二维数组类型但我们通常用“数组的数组”Array[Array]来模拟。5.1 创建与访问二维数组# 创建一个 3x3 的网格二维数组 var rows 3 var cols 3 var grid: Array[Array] [] for i in range(rows): grid.append([]) # 添加一行是一个空数组 for j in range(cols): grid[i].append(0) # 为当前行的每一列赋初始值0 # 访问元素 grid[1][2] 5 # 第2行第3列索引从0开始 print(grid[0][0]) # 访问第1行第1列5.2 扁平化与性能考量有时为了性能或简化操作我们会将二维数组“扁平化”为一维数组。# 二维数组 grid[3][3] # 扁平化为一维数组 flat[9] # 映射关系grid[row][col] - flat[row * cols col] var rows 3 var cols 3 var flat_array: Array[int] [] flat_array.resize(rows * cols) # 预分配空间 flat_array.fill(0) # 填充0 # 设置 grid[1][2] 为 5 flat_array[1 * cols 2] 5 # 获取 grid[1][2] var value flat_array[1 * cols 2]为什么要扁平化内存局部性一维数组在内存中是连续存储的CPU缓存命中率更高遍历速度可能更快。简化序列化存储到文件或网络传输时一维数组更简单。某些算法需要比如一些图像处理或数学库函数要求数据是连续的一维缓冲区。注意事项扁平化增加了索引计算的复杂性row * cols col代码可读性会下降。对于大多数游戏逻辑如地图格子、棋盘使用直观的二维数组grid[y][x]在可读性和维护性上优势明显除非性能分析明确表明这里是瓶颈否则建议优先使用直观的二维数组。5.3 使用Array.flatten()方法Godot 4.2的Array提供了一个flatten()方法可以将一个嵌套的数组不限于二维展开成一维数组。var nested [[1, 2], [3, 4, 5], [6]] var flat nested.flatten() # [1, 2, 3, 4, 5, 6]这在处理一些不规则的多维数据时非常方便。但要注意它返回的是一个全新的数组。6. 数组与Dictionary、PackedArray的对比与选型Array不是唯一的选择。Godot提供了多种集合类型了解它们的区别至关重要。特性ArrayDictionaryPackedByteArray / PackedInt32Array 等核心用途有序序列通过整数索引访问键值对映射通过唯一键访问存储大量单一基础类型数据高性能查找性能按索引O(1)按值O(n)按键O(1)平均按索引O(1)内存与速度通用平衡哈希表开销略高于Array内存紧凑速度极快连续内存元素类型任意类型可类型化键值均可为任意类型单一基础类型如byte, int, float, string顺序性严格保持插入/索引顺序从Godot 4起保持插入顺序有序典型场景敌人队列、技能列表、对话序列玩家库存、物体ID到实例的映射、配置数据网格数据、顶点数组、网络数据包、图像像素选型指南需要保持顺序并通过位置索引访问- 选Array。需要通过一个唯一的“键”如字符串ID快速查找、添加、删除数据- 选Dictionary。即使Godot 4的Dictionary保持了顺序它的核心优势依然是基于键的快速查找。存储海量的同类型数值数据如顶点坐标、颜色、体素数据对性能和内存有极致要求- 选Packed*Array系列。例如PackedVector3Array用于存储成千上万的顶点位置其性能远超Array[Vector3]。一个常见误区试图用Array来模拟字典的功能例如存储[ [key1, value1], [key2, value2] ]然后通过遍历来查找。这在数据量稍大时就会成为性能灾难。该用Dictionary的时候不要犹豫。7. 实战避坑与性能优化技巧7.1 遍历中修改数组的大坑这是新手最容易踩的坑之一在遍历数组的同时对其进行添加或删除操作。# 错误示例尝试移除所有值为 “remove_me” 的元素 var data [“a”, “remove_me”, “b”, “remove_me”, “c”] for i in range(data.size()): if data[i] “remove_me”: data.remove_at(i) # 删除后数组大小和索引都变了 # 下一次循环 i 会增加但后面的元素已经前移导致跳过一个元素的检查解决方案1逆向遍历for i in range(data.size() - 1, -1, -1): # 从后往前 if data[i] “remove_me”: data.remove_at(i) # 删除当前元素不影响前面待遍历的索引解决方案2构建新数组var new_data [] for item in data: if item ! “remove_me”: new_data.append(item) data new_data解决方案3使用filter方法 (GDScript 2.0风格)data data.filter(func(item): return item ! “remove_me”)7.2 对象数组与引用语义当数组存储的是对象如Node、Resource时存储的是引用而不是副本。var node1 $Sprite2D var node2 $Player var node_array: Array[Node] [node1, node2] # 修改数组中的对象属性 node_array[0].modulate Color.RED # 这会直接改变 $Sprite2D 的颜色 # 两个数组包含对同一个对象的引用 var another_array [node_array[0]] another_array[0].modulate Color.BLUE # $Sprite2D 的颜色又变成了蓝色这意味着如果你希望得到一个对象的独立副本需要手动复制如果该对象支持duplicate()方法。var original_texture preload(“res://icon.png”) var texture_array [original_texture, original_texture.duplicate()] # 第二个元素是副本 # 修改 texture_array[1] 不会影响 original_texture7.3 类型化数组的运行时检查与性能类型化数组Array[int]在非严格模式下如果你尝试放入错误类型错误会在运行时抛出。在严格模式下# strict或项目设置中启用错误在编译时或解析时就能被发现。关于性能类型化数组理论上能给引擎更多的优化信息。但在绝大多数游戏逻辑中这种差异微乎其微。代码的清晰度和安全性带来的收益远大于那一点点可能的性能提升。因此我强烈建议在任何可能的地方使用类型化注解。7.4 超大数组的处理建议避免在每帧进行O(n)操作对于成百上千个元素的数组find、has、insert(在开头)、remove_at(在开头)等操作放在_process里是危险的。考虑使用Dictionary做索引或者重构逻辑。批量操作如果需要添加大量元素考虑一次性构建好一个数组然后使用append_array(other_array)这比在循环中多次调用append可能更高效。预分配如果你事先知道数组的大致大小可以使用resize()预分配空间避免多次动态扩容的开销。考虑Packed*Array如果数据是纯粹的数字或向量毫不犹豫地使用PackedInt32Array、PackedFloat32Array、PackedVector2Array等。它们是为数值计算而生的。7.5 一个综合案例对象池实现对象池是重用游戏对象如子弹、敌人以优化性能的经典模式Array是实现它的绝佳选择。extends Node class_name ObjectPool export var object_scene: PackedScene export var initial_size: int 10 var _pool: Array[Node] [] var _available: Array[int] [] # 存储可用对象在_pool中的索引 func _ready(): # 初始化对象池 for i in range(initial_size): var obj object_scene.instantiate() obj.visible false obj.process_mode Node.PROCESS_MODE_DISABLED add_child(obj) _pool.append(obj) _available.append(i) # 初始时所有对象都可用 func acquire() - Node: if _available.is_empty(): # 池已空动态扩容也可选择不扩容返回null var obj object_scene.instantiate() add_child(obj) _pool.append(obj) return obj else: var idx _available.pop_back() # 从可用索引中取出一个 var obj _pool[idx] obj.visible true obj.process_mode Node.PROCESS_MODE_INHERIT return obj func release(obj: Node) - void: obj.visible false obj.process_mode Node.PROCESS_MODE_DISABLED # 找到对象在池中的索引这里用了线性查找如果池很大可以用Dictionary建立映射优化 var idx _pool.find(obj) if idx ! -1: _available.append(idx)在这个案例中我们使用了两个Array_pool存储所有对象实例_available作为栈使用pop_back和append来高效管理可用对象的索引。这避免了频繁的创建和销毁对象极大地提升了性能。

相关新闻

Windows本机搭建FTP服务器:10分钟搞定局域网文件共享

Windows本机搭建FTP服务器:10分钟搞定局域网文件共享

1. 项目概述:为什么要在Windows本机搭建FTP?如果你手头有一台Windows电脑,无论是台式机还是笔记本,想快速地在局域网内和同事、家人或者自己的其他设备之间共享文件,搭建一个FTP服务器可能是最直接、最“复古”也最可靠…

2026/8/6 6:26:50 阅读更多 →
Vibe Coding 全栈实战:从概念到项目落地的 AI 协作开发指南

Vibe Coding 全栈实战:从概念到项目落地的 AI 协作开发指南

最近在技术社区和招聘要求中,一个词的出现频率越来越高:Vibe Coding。很多开发者,尤其是前端和全栈方向的朋友,可能都听说过它,但感觉它既熟悉又陌生——它似乎不是一门具体的编程语言,也不是一个框架&…

2026/8/6 6:26:50 阅读更多 →
Kubernetes Pod生命周期详解与最佳实践

Kubernetes Pod生命周期详解与最佳实践

1. Kubernetes Pod 生命周期全景解析在云原生技术栈中,Pod作为Kubernetes的最小调度单元,其生命周期管理是每个Kubernetes使用者必须掌握的核心知识。不同于虚拟机或物理机的静态运行模式,Pod从诞生到终止的整个过程都体现着云原生应用的动态…

2026/8/6 6:26:50 阅读更多 →

最新新闻

酒店行业定岗定编成功案例:北京华恒智信按班次和客流分级配置

酒店行业定岗定编成功案例:北京华恒智信按班次和客流分级配置

【导读】酒店环境的好坏直接影响着许多消费项目的质量。由于酒店服务的特殊性,环境部的工作随意性较大,无规律,有时工作量剧增,有时各部门又非常清闲,给人员配置带来了一定的难度。那么,如何确定各岗位的人…

2026/8/6 16:48:06 阅读更多 →
vscode的background插件突然是用不了的解决方法

vscode的background插件突然是用不了的解决方法

背景:本来唱着歌写着express中,但是新建了vscode窗口之后backgroud突然就用不了,与此同时还有插件标出Connection to server got closed. Server will not be restarted. Sourc:IntellCode API Usage Example和Client API Usage Examples LSP: connection to server is errori…

2026/8/6 16:48:06 阅读更多 →
SpringBoot3+Vue3+MySQL 电子设备保修售后管理系统源码 前后端分离实战

SpringBoot3+Vue3+MySQL 电子设备保修售后管理系统源码 前后端分离实战

一、项目简介 本项目是一套基于 Spring Boot 3 Vue 3 前后端分离架构的电子设备保修与售后管理系统。系统围绕设备保修与售后工单流转这一核心业务,划分为普通用户端、商家端(企业售后人员)和管理员端三个角色入口。普通用户可完成设备注册、…

2026/8/6 16:48:06 阅读更多 →
物业行业精细化成功案例:北京华恒智信引入三级五角色工具

物业行业精细化成功案例:北京华恒智信引入三级五角色工具

在过去几个月的咨询过程中,华恒智信咨询师们始终以我公司的发展目标和项目要求为导向,以优化公司人力资源管理问题、持续提高企业的核心竞争力,为公司尽心尽力地提供咨询和服务。项目期间进行了大量的调研和访谈,大约180位管理者和…

2026/8/6 16:48:06 阅读更多 →
2026这6款硬核降AI率平台大起底,一键让AIGC率断崖式下跌!

2026这6款硬核降AI率平台大起底,一键让AIGC率断崖式下跌!

步入 2026 年,学术圈的风向早已不是从前的模样。曾经只需担心查重率的焦虑,如今已被更严峻的“降 AI 率”难题所取代。随着 AI 检测系统不断迭代升级,高校对论文的审查标准也愈发严苛,仿佛每一句话都被置于显微镜下审视。单纯降低…

2026/8/6 16:48:06 阅读更多 →
DS4Windows终极指南:3步让PlayStation手柄在Windows上完美兼容Xbox游戏

DS4Windows终极指南:3步让PlayStation手柄在Windows上完美兼容Xbox游戏

DS4Windows终极指南:3步让PlayStation手柄在Windows上完美兼容Xbox游戏 【免费下载链接】DS4Windows Like those other ds4tools, but sexier 项目地址: https://gitcode.com/gh_mirrors/ds/DS4Windows 还在为PC游戏无法识别你的PlayStation手柄而烦恼吗&…

2026/8/6 16:47:06 阅读更多 →

日新闻

深入解析LimboAI C++内核:架构设计与性能优化实战

深入解析LimboAI C++内核:架构设计与性能优化实战

1. 项目概述:为什么我们需要深入LimboAI的C内核?如果你是一名使用Godot引擎的游戏开发者,尤其是对AI行为逻辑有较高要求的项目,那么LimboAI这个名字你大概率不会陌生。它作为Godot 4生态中一个备受瞩目的行为树与状态机插件&#…

2026/8/6 0:00:06 阅读更多 →
Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

1. 项目概述与核心思路大家好,我是老张,一个在游戏开发一线摸爬滚打了十多年的老码农。今天咱们接着聊《空洞骑士》风格2D动作游戏的Demo制作。上一期我们搭好了基础框架,处理了角色移动和碰撞,这一期,我们要让游戏世界…

2026/8/6 0:00:06 阅读更多 →
被动防火门市场前景发展趋势

被动防火门市场前景发展趋势

被动防火门依靠材质结构、密闭构造阻隔烟火蔓延,无需电控启动,是建筑被动消防系统核心构件,行业依托新规管控、城市更新、工业安全升级迎来稳定扩容,整体朝着合规化、专项化、低碳化、智能化方向发展。现阶段 GB12955‑2024 新版国…

2026/8/6 0:00:06 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/5 23:28:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/5 21:00:14 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/5 23:46:51 阅读更多 →