2D Map and Scene Generator
0x0funky/agent-sprite-forge
Plans and builds 2D game maps and scenes, from tilemaps and parallax backgrounds to HD-2D plates, with collision checks, a playable HTML preview and Tiled, Godot or LDtk export.
NavigationAgent2D使用、AStarGrid2D算法、自定义A实现、流式寻路及性能优化。用于2D/3D导航系统、动态障碍物避让、游戏AI导航等场景。
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install 925236118/AlphaAgent godot-navigation-system --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .claude/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .claude/skills/godot-navigation-system && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .claude/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-systemType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install 925236118/AlphaAgent godot-navigation-system --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .agents/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .agents/skills/godot-navigation-system && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .agents/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install 925236118/AlphaAgent godot-navigation-system --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .cursor/skills/godot-navigation-system && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .cursor/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/925236118/AlphaAgent.git --path addons/agent/skills/default_skills/godot-navigation-system--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install 925236118/AlphaAgent godot-navigation-system --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .gemini/skills/godot-navigation-system && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .gemini/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install 925236118/AlphaAgent godot-navigation-systemInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .github/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .github/skills/godot-navigation-system && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .github/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install 925236118/AlphaAgent godot-navigation-system --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/925236118/AlphaAgent.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/addons/agent/skills/default_skills/godot-navigation-system .opencode/skills/godot-navigation-system && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "godot-navigation-system" agent skill from https://github.com/925236118/AlphaAgent/tree/master/addons/agent/skills/default_skills/godot-navigation-system into .opencode/skills/godot-navigation-system/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-navigation-system", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
godot-navigation-systemNavigationAgent2D使用、AStarGrid2D算法、自定义A实现、流式寻路及性能优化。用于2D/3D导航系统、动态障碍物避让、游戏AI导航等场景。
Godot Navigation System is an agent skill from 925236118/AlphaAgent. NavigationAgent2D使用、AStarGrid2D算法、自定义A实现、流式寻路及性能优化。用于2D/3D导航系统、动态障碍物避让、游戏AI导航等场景。
Its SKILL.md is about 5.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Game Development, covering Game development. It works with Godot. The repository describes itself as: 为Godot引擎编辑器开发的Ai Agent插件. The licence is MIT.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit ed0da30. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are gdscript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Godot Navigation System loads about 5.9k tokens when it runs. Until then it costs about 27 tokens; SKILL.md has 113 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from 925236118/AlphaAgent at commit ed0da30, republished under its MIT licence (© 925236118). 113 words, ~5,913 tokens.
.claude/skills/godot-navigation-system/SKILL.md (or your agent's skills folder).Godot 4 导航系统完整指南,涵盖 NavigationAgent2D、AStarGrid2D、自定义 A* 算法、流场寻路及性能优化策略。
NavigationAgent2D 是 Godot 4 推荐的 2D 导航解决方案,封装了 NavigationServer 的复杂操作。
# navigation_agent_2d.gd
class_name NavigationAgent2D
extends NavigationAgent2D
signal navigation_finished
signal path_changed
signal target_reached
@export var actor: CharacterBody2D
@export var move_speed: float = 200.0
var _target_position: Vector2 = Vector2.ZERO
func _ready() -> void:
# 设置代理半径(障碍物避让)
agent_height = 0
agent_max_speed = move_speed
# 连接信号
navigation_finished.connect(_on_navigation_finished)
path_changed.connect(_on_path_changed)
target_reached.connect(_on_target_reached)
# 等待NavigationServer同步
await get_tree().physics_frame
await get_tree().physics_frame
func _physics_process(delta: float) -> void:
if actor and _target_position != Vector2.ZERO:
if is_navigation_finished():
return
var next_pos := get_next_path_position()
var current_pos := actor.global_position
var new_velocity := (next_pos - current_pos).normalized() * move_speed
actor.velocity = new_velocity
actor.move_and_slide()
func set_target(world_position: Vector2) -> void:
_target_position = world_position
target_position = world_position
func _on_navigation_finished() -> void:
navigation_finished.emit()
func _on_path_changed() -> void:
path_changed.emit()
func _on_target_reached() -> void:
target_reached.emit()# navigation_region.gd
class_name NavigationRegion
extends NavigationRegion2D
@export var tile_map: TileMap
@export var bake_on_ready: bool = true
func _ready() -> void:
if bake_on_ready:
await get_tree().physics_frame
bake_navigation_polygon()
# 从 TileMap 几何数据生成导航多边形
func bake_from_tilemap() -> void:
var polygon := NavigationPolygon.new()
var outline: Array[Vector2] = []
var used_rect := tile_map.get_used_rect()
for x in range(used_rect.size.x):
for y in range(used_rect.size.y):
var cell := Vector2i(used_rect.position.x + x, used_rect.position.y + y)
var tile_data := tile_map.get_cell_tile_data(0, cell)
if tile_data and tile_data.get_custom_data("obstacle"):
# 障碍物格子不加入导航
continue
var world_pos := tile_map.map_to_local(cell)
outline.append(world_pos)
if not outline.is_empty():
polygon.add_outline(outline)
polygon.make_polygons_from_outlines()
navigation_polygon = polygon
bake_navigation_polygon()# dynamic_obstacle.gd
class_name DynamicObstacle
extends Area2D
@export var radius: float = 32.0
@export var navigation_region: NavigationRegion
var _last_position: Vector2
func _ready() -> void:
area_entered.connect(_on_area_entered)
area_exited.connect(_on_area_exited)
func _physics_process(_delta: float) -> void:
if global_position != _last_position:
_last_position = global_position
_update_navigation()
func _update_navigation() -> void:
# 简单实现:移动时重新烘焙导航网格
# 生产环境建议使用 NavigationMesh::update()
if navigation_region:
navigation_region.bake_navigation_polygon()
func _on_area_entered(area: Area2D) -> void:
# 障碍物进入逻辑
pass
func _on_area_exited(area: Area2D) -> void:
# 障碍物离开逻辑
passAStarGrid2D 是 Godot 4 内置的高效网格寻路组件,适合规则网格的快速 A* 搜索。
# astar_grid_2d.gd
class_name AStarGrid2D
extends Node
@export var tile_map: TileMap
@export var obstacles_layer: int = 0
var _grid: AStarGrid2D
func _ready() -> void:
_setup_grid()
func _setup_grid() -> void:
var region := tile_map.get_used_rect()
_grid = AStarGrid2D.new()
_grid.size = region.size
_grid.offset = tile_map.tile_set.tile_size / 2
_grid.cell_size = tile_map.tile_set.tile_size
_grid.center = false
_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
_grid.update()
# 标记障碍物
for cell in tile_map.get_used_cells(obstacles_layer):
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
if tile_data and tile_data.get_custom_data("obstacle"):
_grid.set_point_solid(cell - region.position)
func find_path(start: Vector2i, end: Vector2i) -> PackedVector2Array:
var region := tile_map.get_used_rect()
var local_start := start - region.position
var local_end := end - region.position
if not _grid.is_point_inside(local_start) or not _grid.is_point_inside(local_end):
return PackedVector2Array()
if _grid.is_point_solid(local_start) or _grid.is_point_solid(local_end):
return PackedVector2Array()
var path := _grid.get_point_path(local_start, local_end)
# 转换回世界坐标
var world_path := PackedVector2Array()
for point in path:
world_path.append(tile_map.map_to_local(point + region.position))
return world_path
func is_walkable(cell: Vector2i) -> bool:
var region := tile_map.get_used_rect()
var local_cell := cell - region.position
if not _grid.is_point_inside(local_cell):
return false
return not _grid.is_point_solid(local_cell)
func set_obstacle(cell: Vector2i, obstacle: bool) -> void:
var region := tile_map.get_used_rect()
var local_cell := cell - region.position
if obstacle:
_grid.set_point_solid(local_cell)
else:
_grid.clear_point(local_cell)# weighted_astar_grid.gd
class_name WeightedAStarGrid
extends AStarGrid2D
var _cell_weights: Dictionary = {}
func _ready() -> void:
_setup_grid()
func _setup_grid() -> void:
var region := tile_map.get_used_rect()
_grid = AStarGrid2D.new()
_grid.size = region.size
_grid.offset = tile_map.tile_set.tile_size / 2
_grid.cell_size = tile_map.tile_set.tile_size
_grid.center = false
_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES
_grid.update()
# 初始化权重
for x in range(region.size.x):
for y in range(region.size.y):
var cell := Vector2i(region.position.x + x, region.position.y + y)
_initialize_cell_weight(cell)
# 标记障碍物
for cell in tile_map.get_used_cells(obstacles_layer):
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
if tile_data and tile_data.get_custom_data("obstacle"):
_grid.set_point_solid(cell - region.position)
func _initialize_cell_weight(cell: Vector2i) -> void:
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
if tile_data:
var weight := tile_data.get_custom_data("weight")
if weight != null:
_cell_weights[cell] = weight
else:
_cell_weights[cell] = 1.0
else:
_cell_weights[cell] = 1.0
func find_path(start: Vector2i, end: Vector2i) -> PackedVector2Array:
# 使用默认的 A* 路径(权重需要在使用时自定义处理)
return super.find_path(start, end)
# 估计成本(启发式函数)
func _estimate_cost(from: Vector2i, to: Vector2i) -> float:
var weight := _cell_weights.get(to, 1.0)
return (from - to).length() * weight# custom_astar.gd
# 自定义 A* 寻路实现
class_name CustomAStar
extends Node
@export var tile_map: TileMap
@export var obstacles_layer: int = 0
var _grid_size: Vector2i
var _walkable: Dictionary = {}
class AStarNode:
var cell: Vector2i
var g_cost: float # 从起点到当前节点的实际成本
var h_cost: float # 从当前节点到终点的估计成本
var f_cost: float: # g_cost + h_cost
return g_cost + h_cost
var parent: AStarNode = null
func _init(c: Vector2i, g: float, h: float) -> void:
cell = c
g_cost = g
h_cost = h
func _ready() -> void:
_initialize_grid()
func _initialize_grid() -> void:
_grid_size = tile_map.get_used_rect().size
var origin := tile_map.get_used_rect().position
for x in range(_grid_size.x):
for y in range(_grid_size.y):
var cell := Vector2i(origin.x + x, origin.y + y)
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
_walkable[cell] = tile_data == null or not tile_data.get_custom_data("obstacle")
func find_path(start: Vector2i, end: Vector2i) -> Array[Vector2i]:
if not _walkable.has(start) or not _walkable.has(end):
return []
if not _walkable.get(end, false):
# 目标不可达,寻找最近的可通行点
end = _find_nearest_walkable(end)
if end == Vector2i(-1, -1):
return []
var open_set: Array[AStarNode] = []
var closed_set: Dictionary = {}
var start_node := AStarNode.new(start, 0.0, _heuristic(start, end))
open_set.append(start_node)
while not open_set.is_empty():
# 找到 f_cost 最低的节点
open_set.sort_custom(func(a, b): return a.f_cost < b.f_cost)
var current := open_set.pop_front()
if current.cell == end:
return _reconstruct_path(current)
closed_set[current.cell] = current
for neighbor in _get_neighbors(current.cell):
if closed_set.has(neighbor) or not _walkable.get(neighbor, false):
continue
var g_cost := current.g_cost + _get_move_cost(current.cell, neighbor)
var h_cost := _heuristic(neighbor, end)
var existing := _find_in_open_set(open_set, neighbor)
if existing == null:
var new_node := AStarNode.new(neighbor, g_cost, h_cost)
new_node.parent = current
open_set.append(new_node)
elif g_cost < existing.g_cost:
existing.g_cost = g_cost
existing.parent = current
return []
func _find_in_open_set(open_set: Array[AStarNode], cell: Vector2i) -> AStarNode:
for node in open_set:
if node.cell == cell:
return node
return null
func _heuristic(a: Vector2i, b: Vector2i) -> float:
# 曼哈顿距离
return absf(a.x - b.x) + absf(a.y - b.y)
func _get_move_cost(from: Vector2i, to: Vector2i) -> float:
# 斜向移动
if from.x != to.x and from.y != to.y:
return 1.414
return 1.0
func _get_neighbors(cell: Vector2i) -> Array[Vector2i]:
return [
cell + Vector2i(0, -1),
cell + Vector2i(1, 0),
cell + Vector2i(0, 1),
cell + Vector2i(-1, 0),
cell + Vector2i(1, -1),
cell + Vector2i(1, 1),
cell + Vector2i(-1, 1),
cell + Vector2i(-1, -1),
]
func _find_nearest_walkable(target: Vector2i) -> Vector2i:
var closest: Vector2i = Vector2i(-1, -1)
var min_dist := INF
for cell in _walkable.keys():
if _walkable[cell]:
var dist := (cell - target).length()
if dist < min_dist:
min_dist = dist
closest = cell
return closest
func _reconstruct_path(end_node: AStarNode) -> Array[Vector2i]:
var path: Array[Vector2i] = []
var current: AStarNode = end_node
while current != null:
path.push_front(current.cell)
current = current.parent
return path流场寻路特别适合大量单位同时寻路的 RTS 游戏场景。
# nav_flow_field.gd
# 使用 NavigationServer 实现流场
class_name NavFlowField
extends Node2D
@export var navigation_region: NavigationRegion2D
@export var tile_map: TileMap
@export var obstacles_layer: int = 0
@export var destination_layer: int = 1
var _nav_rid: RID
var _flow_map: Dictionary = {} # Vector2i -> Vector2
var _update_needed: bool = false
func _ready() -> void:
_nav_rid = navigation_region.navigation_rid
_build_initial_flow_field()
func _physics_process(_delta: float) -> void:
if _update_needed:
_build_flow_field()
_update_needed = false
func request_update() -> void:
_update_needed = true
func _build_initial_flow_field() -> void:
_build_flow_field()
func _build_flow_field() -> void:
_flow_map.clear()
# 获取所有可行走格子
var walkable_cells: Array[Vector2i] = []
var destination_cells: Array[Vector2i] = []
for cell in tile_map.get_used_cells(0):
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
if tile_data and tile_data.get_custom_data("obstacle"):
continue
walkable_cells.append(cell)
for cell in tile_map.get_used_cells(destination_layer):
destination_cells.append(cell)
if destination_cells.is_empty():
return
# BFS 构建距离场
var distance_field: Dictionary = {}
var queue: Array[Vector2i] = destination_cells.duplicate()
for dest in destination_cells:
distance_field[dest] = 0.0
while not queue.is_empty():
var current := queue.pop_front()
var current_dist := distance_field[current]
for neighbor in _get_neighbors(current):
if not _walkable(neighbor):
continue
if not distance_field.has(neighbor):
distance_field[neighbor] = current_dist + 1.0
queue.append(neighbor)
# 构建流场
for cell in distance_field.keys():
_flow_map[cell] = _calculate_flow_direction(cell, distance_field)
func _walkable(cell: Vector2i) -> bool:
var tile_data := tile_map.get_cell_tile_data(obstacles_layer, cell)
return tile_data == null or not tile_data.get_custom_data("obstacle")
func _get_neighbors(cell: Vector2i) -> Array[Vector2i]:
return [
cell + Vector2i(0, -1),
cell + Vector2i(1, 0),
cell + Vector2i(0, 1),
cell + Vector2i(-1, 0),
]
func _calculate_flow_direction(cell: Vector2i, distance_field: Dictionary) -> Vector2:
var neighbors := _get_neighbors(cell)
var best_dir := Vector2.ZERO
var lowest_dist := INF
for neighbor in neighbors:
if distance_field.has(neighbor):
var dist := distance_field[neighbor]
if dist < lowest_dist:
lowest_dist = dist
best_dir = Vector2(neighbor - cell).normalized()
return best_dir
func get_flow_direction(world_pos: Vector2) -> Vector2:
var cell := tile_map.local_to_map(world_pos)
if _flow_map.has(cell):
return _flow_map[cell]
return Vector2.ZERO# batched_pathfinding.gd
# 分组批量寻路,减少每帧计算量
class_name BatchedPathfinding
extends Node
signal batch_completed(paths: Dictionary)
@export var max_paths_per_frame: int = 5
var _pending_requests: Array[Dictionary] = []
var _completed_paths: Dictionary = {}
var _current_batch: int = 0
class PathRequest:
var requester_id: int
var start: Vector2i
var end: Vector2i
var priority: int
func _init(id: int, s: Vector2i, e: Vector2i, p: int = 0) -> void:
requester_id = id
start = s
end = e
priority = p
func _physics_process(_delta: float) -> void:
_process_batch()
func request_path(requester_id: int, start: Vector2i, end: Vector2i, priority: int = 0) -> void:
_pending_requests.append(PathRequest.new(requester_id, start, end, priority))
func _process_batch() -> void:
if _pending_requests.is_empty():
return
# 按优先级排序
_pending_requests.sort_custom(func(a, b): return a.priority > b.priority)
var processed: int = 0
while not _pending_requests.is_empty() and processed < max_paths_per_frame:
var request := _pending_requests.pop_front() as PathRequest
var path := _calculate_path(request.start, request.end)
_completed_paths[request.requester_id] = path
processed += 1
if _pending_requests.is_empty():
batch_completed.emit(_completed_paths)
_completed_paths.clear()
func _calculate_path(start: Vector2i, end: Vector2i) -> Array[Vector2i]:
# 这里使用自定义的 A* 或其他寻路算法
var astar: CustomAStar = $CustomAStar
return astar.find_path(start, end)
func get_completed_path(requester_id: int) -> Array[Vector2i]:
if _completed_paths.has(requester_id):
return _completed_paths[requester_id]
return []# throttled_pathfinding.gd
# 节流寻路,避免频繁计算
class_name ThrottledPathfinding
extends Node
@export var throttle_duration: float = 0.2 # 秒
var _path_cache: Dictionary = {}
var _last_update_time: float = 0.0
var _pending_requests: Dictionary = {}
var _needs_update: bool = false
var _astar: CustomAStar
func _ready() -> void:
_astar = $CustomAStar
func _physics_process(delta: float) -> void:
if _needs_update:
_last_update_time += delta
if _last_update_time >= throttle_duration:
_execute_throttled_update()
_last_update_time = 0.0
_needs_update = false
func request_path(id: int, start: Vector2i, end: Vector2i) -> void:
_pending_requests[id] = {"start": start, "end": end, "path": null}
_needs_update = true
func _execute_throttled_update() -> void:
for id in _pending_requests.keys():
var request := _pending_requests[id]
var path := _astar.find_path(request.start, request.end)
_path_cache[id] = path
request.path = path
_pending_requests.clear()
func get_path(id: int) -> Array[Vector2i]:
return _path_cache.get(id, [])# lod_pathfinding.gd
# 分层寻路,远距离用粗糙网格
class_name LODPathfinding
extends Node
enum LODLevel { HIGH, MEDIUM, LOW }
@export var tile_map: TileMap
@export var obstacles_layer: int = 0
var _lod_grid_sizes: Dictionary = {
LODLevel.HIGH: Vector2i(1, 1),
LODLevel.MEDIUM: Vector2i(4, 4),
LODLevel.LOW: Vector2i(8, 8),
}
var _lod_astar: Dictionary = {}
func _ready() -> void:
_initialize_lod_grids()
func _initialize_lod_grids() -> void:
for level in _lod_grid_sizes.keys():
_create_lod_grid(level)
func _create_lod_grid(level: LODLevel) -> void:
var grid_size := _lod_grid_sizes[level]
var region := tile_map.get_used_rect()
var astar := AStarGrid2D.new()
var coarse_size := Vector2i(
ceili(region.size.x / float(grid_size.x)),
ceili(region.size.y / float(grid_size.y))
)
astar.size = coarse_size
astar.cell_size = tile_map.tile_set.tile_size * grid_size
astar.center = false
astar.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
astar.update()
_lod_astar[level] = astar
func find_path(start: Vector2i, end: Vector2i) -> Array[Vector2i]:
var distance := (start - end).length()
var level: LODLevel
if distance < 200:
level = LODLevel.HIGH
elif distance < 500:
level = LODLevel.MEDIUM
else:
level = LODLevel.LOW
return _find_path_at_level(start, end, level)
func _find_path_at_level(start: Vector2i, end: Vector2i, level: LODLevel) -> Array[Vector2i]:
var astar: AStarGrid2D = _lod_astar[level]
# 转换到 LOD 网格坐标
var grid_size := _lod_grid_sizes[level]
var region := tile_map.get_used_rect()
var local_start := (start - region.position) / grid_size
var local_end := (end - region.position) / grid_size
if astar.is_point_inside(local_start) and astar.is_point_inside(local_end):
return astar.get_point_path(local_start, local_end)
return []NavLink 用于连接不连续的导航区域,实现跳跃、传送等效果。
# custom_nav_link.gd
class_name CustomNavLink
extends NavigationLink2D
@export var link_type: int = 0 # 0: 传送, 1: 跳跃, 2: 桥梁
var _is_active: bool = true
func _ready() -> void:
navigation_layers = 1 # 设置导航层
func _get_navigation_links(start_position: Vector2, end_position: Vector2) -> Array[Vector2]:
if not _is_active:
return []
return [start_position, end_position]
func set_active(active: bool) -> void:
_is_active = active# platform_nav_link.gd
class_name PlatformNavLink
extends NavigationLink2D
@export var jump_height: float = 100.0
@export var jump_duration: float = 0.5
var _start_pos: Vector2
var _end_pos: Vector2
func _ready() -> void:
var owner := get_parent()
if owner is Node2D:
_start_pos = owner.global_position
_end_pos = global_position
func get_jump_path(start: Vector2, end: Vector2) -> PackedVector2Array:
if not _is_enabled():
return PackedVector2Array()
var path := PackedVector2Array()
path.append(start)
# 抛物线中间点
var mid_point := (start + end) / 2.0
mid_point.y -= jump_height
path.append(mid_point)
path.append(end)
return path
func _is_enabled() -> bool:
# 检查平台是否可用
var platform := get_parent()
if platform.has_method("is_active"):
return platform.is_active()
return true# ai_navigation_controller.gd
# 完整的 AI 单位导航控制器
class_name AINavigationController
extends CharacterBody2D
signal destination_reached
signal path_updated(path: PackedVector2Array)
@export var navigation_agent: NavigationAgent2D
@export var move_speed: float = 150.0
@export var path_reach_distance: float = 10.0
@export var use_flow_field: bool = false
@export var flow_field: NavFlowField
@export var use_lod: bool = false
@export var lod_controller: LODPathfinding
var _target_position: Vector2 = Vector2.ZERO
var _current_path: PackedVector2Array = []
var _path_index: int = 0
func _ready() -> void:
navigation_agent.velocity_computed.connect(_on_velocity_computed)
set_physics_process(false)
await get_tree().physics_frame
set_physics_process(true)
func _physics_process(delta: float) -> void:
if navigation_agent.is_navigation_finished():
destination_reached.emit()
return
var next_pos: Vector2
if use_flow_field and flow_field:
# 流场导航
next_pos = _get_flow_field_next_position(delta)
else:
# 标准导航
next_pos = navigation_agent.get_next_path_position()
var current_pos := global_position
var new_velocity := (next_pos - current_pos).normalized() * move_speed
if navigation_agent.velocity_computed.size() > 0:
velocity = new_velocity
move_and_slide()
else:
navigation_agent.velocity = new_velocity
func _get_flow_field_next_position(delta: float) -> Vector2:
var flow_dir := flow_field.get_flow_direction(global_position)
if flow_dir.length() > 0.01:
return global_position + flow_dir * move_speed * delta
else:
return global_position
func set_destination(world_position: Vector2) -> void:
_target_position = world_position
if use_lod and lod_controller:
var start_cell := navigation_agent.get_current_navigation_region()
var end_cell := (world_position / lod_controller.tile_map.tile_set.tile_size).floor()
_current_path = Array(lod_controller.find_path(start_cell, end_cell))
_path_index = 0
path_updated.emit(_current_path)
navigation_agent.target_position = world_position
func _on_velocity_computed(velocity: Vector2) -> void:
self.velocity = velocity
move_and_slide()bake_navigation_polygon() 重新烘焙© 925236118, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in addons/agent/skills/default_skills/godot-navigation-system of 925236118/AlphaAgent.
Open the folder on GitHubat commit ed0da30
Godot Navigation System next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Godot Navigation System this skill925236118/AlphaAgent | 103 | — | ~5.9k | Automated safety check: Pass | MIT | |
| 2D Map and Scene Generator0x0funky/agent-sprite-forge | 4.4k | — | ~2.9k | Automated safety check: Pass | MIT | |
| Godot UI Integrationzimo-xiao-zheng/godot-ui-integration | 285 | — | ~1.5k | Automated safety check: Pass | MIT | |
| Godot Wechat Minigame Adaptergodothub/godot-minigame | 187 | — | ~1.5k | Automated safety check: Pass | MIT | |
| AI Game Art Pipelineybuild-ai/ai-game-art-pipeline-skill | 297 | — | ~1.1k | Automated safety check: Pass | MIT | |
| MCP DriverRandallLiuXin/GodotMaker | 550 | 1 repos | ~1.1k | Automated safety check: Pass | Custom licence |
0x0funky/agent-sprite-forge
Plans and builds 2D game maps and scenes, from tilemaps and parallax backgrounds to HD-2D plates, with collision checks, a playable HTML preview and Tiled, Godot or LDtk export.
zimo-xiao-zheng/godot-ui-integration
Build or revise Godot UI from an approved design, separated art, or a visual reference when scene structure, gameplay binding, and runtime visual verification all matter.
godothub/godot-minigame
Apply the bundled self-contained Godot WeChat Mini Game adapter kit to an official Godot checkout.
ybuild-ai/ai-game-art-pipeline-skill
Provider-neutral open-source skill for planning and producing game-runtime art assets and animation: static props/icons, canonical character sheets, combat sprites, 3D/video motion references…
RandallLiuXin/GodotMaker
Runtime debugging and live project inspection via godot-mcp.
ukanwat/overtime
Build game cameras that feel good — 2D follow with a deadzone, look-ahead, smoothing, and level-bounds clamping; 3D third-person orbit with collision and first-person look; plus multi-target framing…
925236118/AlphaAgent
Master Godot 4 GDScript patterns including signals, scenes, state machines, and optimization.
925236118/AlphaAgent
Godot 4.x .tscn 场景文件纯文本格式规范与 AI 操作指南 — 文件结构、资源引用、 Transform 变换、属性值格式、信号连接,以及 AI 直接读写 .tscn 文件的操作方法。
925236118/AlphaAgent
Godot 4 Autoload单例模式最佳实践,包含全局管理、事件总线、信号通信. An agent skill from 925236118/AlphaAgent.
925236118/AlphaAgent
Godot 4 Buff系统完整实现,支持状态效果管理、持续时间、循环效果、层叠机制等。使用Resource+Component架构。
925236118/AlphaAgent
Godot 4 建造系统实现,包含GridMap方块管理、第一人称视角、射线交互. An agent skill from 925236118/AlphaAgent.
925236118/AlphaAgent
Godot 4 ECS实体组件系统模式,包含组件化设计、数据与逻辑分离、组件通信. An agent skill from 925236118/AlphaAgent.
Works with
Categories
NavigationAgent2D使用、AStarGrid2D算法、自定义A实现、流式寻路及性能优化。用于2D/3D导航系统、动态障碍物避让、游戏AI导航等场景。. Godot Navigation System is an agent skill from 925236118/AlphaAgent.
Godot Navigation System fits situations like: tasks that involve Game development.
Run `npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a claude-code`. Or copy the skill folder (addons/agent/skills/default_skills/godot-navigation-system in 925236118/AlphaAgent) into .claude/skills/godot-navigation-system in your project. Claude Code loads it when a task matches its description.
Run `npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a codex`. Or copy the skill folder (addons/agent/skills/default_skills/godot-navigation-system in 925236118/AlphaAgent) into .agents/skills/godot-navigation-system in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add 925236118/AlphaAgent --skill godot-navigation-system -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/godot-navigation-system, .gemini/skills/godot-navigation-system, .github/skills/godot-navigation-system and .opencode/skills/godot-navigation-system in your project.
SKILL.md names no scripts, command-line tools or credentials: Godot Navigation System is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Godot Navigation System is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.9k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Godot Navigation System: 2D Map and Scene Generator (0x0funky/agent-sprite-forge, 4.4k stars), Godot UI Integration (zimo-xiao-zheng/godot-ui-integration, 285 stars), Godot Wechat Minigame Adapter (godothub/godot-minigame, 187 stars) and AI Game Art Pipeline (ybuild-ai/ai-game-art-pipeline-skill, 297 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
925236118 (a GitHub user) maintains it in 925236118/AlphaAgent, which has 103 GitHub stars. The repository holds 17 skills in this directory. The repository was last updated on October 8, 2026.
Source: 925236118/AlphaAgent on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.