agentleFS
MindsMasterMindsMaster/godot-claude-code-skills/skills/godot-2d/SKILL.md

godot-2d

Skill3 starsChanged 19 days agoMITView on GitHub

写 Godot 4 的 2D 场景时用。CharacterBody2D 角色移动与平台跳跃、碰撞层、Area2D、TileMapLayer 瓦片地图与地形自动接边、Camera2D 跟随 平滑 limit 震屏、Parallax2D、y_sort 绘制顺序、像素风缩放、2D 光照、寻路、射线与物理查询、_draw 自绘。也用于查某个 2D 需求有没有内置节点。3D 里放 2D 角色见 godot-2d-in-3d。

The file

Files
SKILL.md

Godot 2D

2D 游戏常见需求的内置节点选择、最短写法和易错点。

范围

不含去哪
动画播放、Tweengodot-animation
shader、粒子、命中闪白写法godot-shaders-vfx
UI 控件、HUD 布局godot-ui
输入映射godot-input
3D 场景里放 2D 角色godot-2d-in-3d
大量实体的性能godot-performance

先查内置

需求用这个别自己写
角色、敌人移动与碰撞CharacterBody2D.move_and_slide手写碰撞检测与滑动
单向平台CollisionShape2D.one_way_collision按 Y 坐标手动开关碰撞
推得动的箱子、球RigidBody2D,一次性冲击 apply_central_impulse,持续推力 apply_central_force每帧改 position 或 linear_velocity
拾取、伤害区、触发区Area2D 加信号手写矩形相交
脚下、身前持续探测RayCast2D、ShapeCast2D 节点每帧 new 查询参数
一次性射线、点选、范围内有谁direct_space_state 的 intersect_ray、intersect_point、intersect_shape遍历全部物体手算相交
瓦片地图TileMapLayer 加 TileSetTileMap 已弃用,每格一个节点
相机边界Camera2D 的 limit_*每帧手写夹取
相机平滑与死区position_smoothing_enabled、drag_*_enabled手写 SmoothDamp
震屏Camera2D.offset 加 FastNoiseLite移动相机节点本身
视差背景Parallax2D(4.3+)ParallaxBackground 与 ParallaxLayer 已弃用,手算偏移
是否在屏幕内VisibleOnScreenNotifier2D手写矩形与相机比较
离屏暂停逻辑VisibleOnScreenEnabler2D每帧距离判断
遮挡排序y_sort_enabled、z_index每帧改 z_index
固定在屏幕上的层CanvasLayer手算相机反向偏移
光照与阴影PointLight2D、DirectionalLight2D、LightOccluder2D、CanvasModulate多个 SubViewport 拼光照
泛光WorldEnvironment 的 Environment.glow_enabledSubViewport 手搓 bloom
实时寻路NavigationRegion2D 加 NavigationAgent2D手写 A* 与路径跟随
格子寻路AStarGrid2D手写 A*
线、轨迹、血条形状Line2D、Polygon2D、_draw一格一个 ColorRect
大量相同物体MultiMeshInstance2D几千个 Sprite2D
像素风项目设置,见下手写缩放与取整
命中闪白shader uniform 加 Tween把 Modulate 调到大于 1

做法

CharacterBody2D

平台跳跃:

<!-- check: extends CharacterBody2D -->
const SPEED := 160.0
const JUMP := -320.0

func _physics_process(delta: float) -> void:
	if not is_on_floor():
		velocity += get_gravity() * delta
	elif Input.is_action_just_pressed("jump"):
		velocity.y = JUMP
	velocity.x = Input.get_axis("left", "right") * SPEED
	move_and_slide()

俯视角:

<!-- check: extends CharacterBody2D -->
func _physics_process(_delta: float) -> void:
	velocity = Input.get_vector("left", "right", "up", "down") * 120.0
	move_and_slide()
属性或方法用途
motion_mode俯视角设 MOTION_MODE_FLOATING,所有碰撞按墙处理
floor_snap_length下坡不脱地
floor_constant_speed上下坡速度一致
floor_stop_on_slope站定不下滑
platform_on_leave移动平台带动角色是内置的,此项管离开时的速度
get_slide_collision(i).get_collider()本帧撞到什么,数量 get_slide_collision_count()
  • velocity 单位像素每秒,move_and_slide 不乘 delta,move_and_collide 要乘
  • 默认 grounded 模式按 up_direction 区分地面墙天花板,斜坡加减速

单向平台与推动刚体

  • 单向平台:平台的 CollisionShape2D 勾 one_way_collision
  • 角色撞上 RigidBody2D 不推动它,每物理帧对它 apply_central_force
  • 下穿、漏穿、推箱写法见 references/bodies.md

碰撞层

layer 是我在哪一层,mask 是我扫描哪些层。先在项目设置里给层起名,代码只用 1 到 32 的编号。

[layer_names]

2d_physics/layer_1="world"
2d_physics/layer_2="player"
2d_physics/layer_3="enemy"
2d_physics/layer_4="player_hitbox"
2d_physics/layer_5="enemy_hitbox"
对象layermask
地形、墙world无
玩家playerworld
敌人enemyworld
玩家攻击判定 Area2Dplayer_hitboxenemy
敌人攻击判定 Area2Denemy_hitboxplayer
拾取物 Area2D无player
  • 检测方 Area2D 只设 mask,除非别的 Area2D 要检测它
  • 改单个位:set_collision_layer_value(2, true),编号从 1 起
  • 函数参数里的位掩码是 1 << (层号 - 1),全部层 0xffffffff
  • 敌人互不挤:敌人的 mask 不放 enemy 层

Area2D

<!-- check: extends Area2D -->
signal collected(by: Node2D)

@onready var _shape: CollisionShape2D = $CollisionShape2D

func _ready() -> void:
	body_entered.connect(_on_body_entered)


func _on_body_entered(body: Node2D) -> void:
	collected.emit(body)
	_shape.set_deferred("disabled", true)
  • monitoring 是我检测别人,monitorable 是别人能检测我
  • 信号回调里禁用形状、改 monitoring 用 set_deferred
  • get_overlapping_bodies 每物理步更新一次,刚移动完查不到,优先用信号
  • 撞 TileMapLayer 时 body_entered 的参数是 TileMapLayer,不是格子
  • 回查格子见 references/tilemaplayer.md

射线与空间查询

需求用这个
固定方向持续探测,脚下、身前RayCast2D 节点,每物理步自动更新
有宽度的探测,台阶、宽激光ShapeCast2D 节点
一次性射线,hitscan、视线intersect_ray
点下去有谁intersect_point
圆形或矩形范围内有谁intersect_shape
[node name="GroundProbe" type="RayCast2D" parent="."]
target_position = Vector2(0, 12)
collision_mask = 1
<!-- check: extends CharacterBody2D -->
@onready var _ground: RayCast2D = $GroundProbe

func _physics_process(_delta: float) -> void:
	if _ground.is_colliding():
		var point: Vector2 = _ground.get_collision_point()
		print(point, _ground.get_collider())
<!-- check: extends CharacterBody2D -->
const MASK := (1 << 0) | (1 << 2)

func _physics_process(_delta: float) -> void:
	if not Input.is_action_just_pressed("fire"):
		return
	var query := PhysicsRayQueryParameters2D.create(
			global_position, get_global_mouse_position(), MASK, [get_rid()])
	var hit: Dictionary = get_world_2d().direct_space_state.intersect_ray(query)
	if not hit.is_empty():
		var point: Vector2 = hit.position
		print(point, hit.collider)
  • RayCast2D.target_position 相对自己
  • exclude_parent 默认 true,排除父级碰撞体
  • 同一物理步改了位置要读结果,先 force_raycast_update()
  • enabled 为 false 时 force_raycast_update() 仍有效
  • 查询参数的 mask 默认全部层,节点的 collision_mask 默认只有第 1 层
  • intersect_ray 返回字典,没命中为空
  • intersect_point intersect_shape 返回字典数组,无 position
  • ShapeCast2D、范围与点查询、结果字段见 references/physics-queries.md

TileMapLayer

一层一个节点,多层靠多个节点,旧 TileMap 在编辑器里一键转换。

  • 读写用 set_cell、erase_cell、get_cell_tile_data、local_to_map
  • 地形接边用 set_cells_terrain_connect,不手写位掩码,挖掉时 terrain 传 -1
  • erase_cell 不刷新邻格地形
  • 碰撞、导航、遮挡、自定义数据、地形先在 TileSet 建层,再给瓦片填
  • 宝箱、火把等带逻辑物件用 Scenes Collection 源,或直接放场景
  • 预置格子用无头脚本 set_cell 加 ResourceSaver.save 生成
  • 手编 tile_map_data 头 2 字节须为 0,否则整层读成 0 格
  • 配置表、peering bit、运行时改瓦片、Y 排序见 references/tilemaplayer.md

Camera2D

[node name="Camera2D" type="Camera2D" parent="Player"]
position_smoothing_enabled = true
position_smoothing_speed = 6.0
limit_left = 0
limit_top = 0
limit_right = 2560
limit_bottom = 720
  • 相机做玩家子节点,跟随、边界、平滑、死区都内置
  • limit_* 是整数像素
  • 震屏改 offset 不改节点位置,噪声用 FastNoiseLite
  • offset 在 limit 之后叠加,贴边会露出界外,要夹紧
  • 复活、传送后同一段代码里紧接着调 reset_smoothing()
  • 不在相机里比较位移距离猜传送,冲刺会误判
  • 视差背景用 Parallax2D 4.3+,scroll_scale 小于 1 是远景
  • 画面抖、zoom、完整震屏、算 limit、Parallax2D 摆法见 references/camera-parallax.md

绘制顺序

工具规则
y_sort_enabled共同父节点开,子节点按原点 Y 排序,角色原点放脚底
子节点未开 y_sort整棵子树作为一个整体参与排序
z_indexY 排序只在同 z_index 间生效,默认相对父节点累加
z_as_relative关掉后 z_index 是绝对值
同级不排序场景树里靠后的画在上面
CanvasLayer不随 Camera2D 移动缩放,layer 大的在上,负数在世界后
  • HUD、暂停菜单、转场放 CanvasLayer,不靠 z_index 堆高
  • 同一 layer 值的多个 CanvasLayer 前后顺序不确定
  • 跟着世界走带深度感:follow_viewport_enabled 加 follow_viewport_scale

像素风

路线设置
低分辨率整体放大display/window/stretch/mode 设 viewport,display/window/stretch/scale_mode 设 integer
高分辨率加取整canvas_items,开 rendering/2d/snap/snap_2d_transforms_to_pixel
  • 两条路线都把 rendering/textures/canvas_textures/default_texture_filter 设 0 即 Nearest
  • 4.7 新建项目默认 canvas_items 加 expand,要手动改
  • Sprite2D.centered 默认 true,奇数尺寸贴图落在半像素上变形
  • 完整设置、抖动排查、字体、光影分辨率见 references/pixel-art.md

光照、离屏、寻路、自绘

需求要点文件
2D 光照与阴影CanvasModulate 压暗,PointLight2D 必须有 texture,LightOccluder2D 投影lighting-glow.md
泛光与 HDR 2Drendering/viewport/hdr_2d 加 WorldEnvironment,modulate 大于 1 发光lighting-glow.md
离屏销毁与暂停VisibleOnScreenNotifier2D,VisibleOnScreenEnabler2Dnavigation-culling.md
寻路NavigationRegion2D 烘焙,NavigationAgent2D 每物理帧取 get_next_path_positionnavigation-culling.md
线、多边形、网格线Line2D、Polygon2D、_draw 加 queue_redrawdrawing.md

陷阱

现象做法
信号回调里直接改碰撞形状 disabled 出错用 set_deferred
_process 或 _input 里查 direct_space_state 结果滞后,物理单独线程时报 Space state is inaccessible查询放进 _physics_process,输入里只记标志
PhysicsRayQueryParameters2D 命中发射者自己exclude 填 [get_rid()],查询不会自动排除
射线与点查询打不到 Area2Dcollide_with_areas 默认 false,手动开
Area2D 检测不到 TileMapLayer 或 StaticBody2D对方 layer 放进 mask,TileSet 配碰撞形状
静止的 Area2D 检测不到后生成或瞬移进来的 StaticBody2D会动的固体用 AnimatableBody2D
Camera2D.zoom 放大后文字糊文字放进 CanvasLayer,或开 MSDF
viewport 拉伸下精灵无亚像素位置和旋转需要时改 canvas_items 加取整
2D 节点每帧手算透视缩放伪 3D改真 3D 加 Sprite3D,见 godot-2d-in-3d

参考

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.