Skip to content

Godot 常用 2D Node 完整指南

适用版本:Godot 4.x

1. Node2D — 2D 基类

所有 2D 节点的基类,提供位置、旋转、缩放等变换功能。

核心属性

var node = $Node2D

# 局部变换
node.position  = Vector2(100, 200)   # 局部坐标
node.rotation  = deg_to_rad(45)      # 旋转(弧度)
node.scale     = Vector2(2.0, 2.0)   # 缩放

# 全局变换
node.global_position = Vector2(300, 400)
node.global_rotation = deg_to_rad(90)
node.global_scale    = Vector2(1.5, 1.5)

# Z 排序
node.z_index   = 1       # Z 层级,越大越在前
node.z_as_relative = true  # 相对父节点累加

常用方法

# 朝向目标
node.look_at(target_position)

# 获取朝向向量
var forward = Vector2.RIGHT.rotated(node.rotation)

# 变换空间转换
var local  = node.to_local(global_pos)
var global = node.to_global(local_pos)

# 获取与目标的距离和方向
var dist = node.position.distance_to(target.position)
var dir  = node.position.direction_to(target.position)

2. Sprite2D — 静态精灵

显示一张静态图片。

关键属性

var sprite = $Sprite2D

sprite.texture        = load("res://art/player.png")  # 图片资源
sprite.centered       = true       # 以中心为原点
sprite.offset         = Vector2(0, -16)  # 偏移
sprite.flip_h         = false      # 水平翻转
sprite.flip_v         = false      # 垂直翻转

# 图集切割(使用大图中的某一格)
sprite.hframes        = 4          # 横向帧数
sprite.vframes        = 2          # 纵向帧数
sprite.frame          = 3          # 当前帧索引(0开始)

# 等价于手动设置 region
sprite.region_enabled = true
sprite.region_rect    = Rect2(32, 0, 32, 32)

# 调制颜色(乘法混合)
sprite.modulate       = Color(1, 0.5, 0.5, 1)  # 偏红
sprite.self_modulate  = Color(1, 1, 1, 0.5)    # 半透明(只影响自身)

常用技巧

# 闪烁效果(受伤反馈)
func flash(duration: float):
    var tween = create_tween().set_loops(6)
    tween.tween_property($Sprite2D, "modulate:a", 0.0, duration / 6)
    tween.tween_property($Sprite2D, "modulate:a", 1.0, duration / 6)

# 朝向鼠标翻转
func _process(_delta):
    var mouse_x = get_global_mouse_position().x
    $Sprite2D.flip_h = mouse_x < global_position.x

3. AnimatedSprite2D — 动画精灵

内置帧动画播放,使用 SpriteFrames 资源管理动画。

基本使用

var anim = $AnimatedSprite2D

# 播放动画
anim.play("run")
anim.play_backwards("run")  # 反向播放
anim.stop()
anim.pause()

# 属性
anim.animation        = "idle"     # 当前动画名
anim.frame            = 0          # 当前帧
anim.speed_scale      = 1.5        # 播放速度倍率
anim.flip_h           = true       # 水平翻转

信号

func _ready():
    $AnimatedSprite2D.animation_finished.connect(_on_anim_finished)
    $AnimatedSprite2D.frame_changed.connect(_on_frame_changed)

func _on_anim_finished():
    # 一次性动画(如攻击)播完后切回 idle
    $AnimatedSprite2D.play("idle")

func _on_frame_changed():
    # 特定帧触发事件(如第3帧播放脚步音效)
    if $AnimatedSprite2D.frame == 3:
        $StepSound.play()

用代码创建 SpriteFrames

var frames = SpriteFrames.new()
frames.add_animation("run")
frames.set_animation_speed("run", 12.0)
frames.set_animation_loop("run", true)

for i in range(4):
    var tex = load("res://art/run_%d.png" % i)
    frames.add_frame("run", tex)

$AnimatedSprite2D.sprite_frames = frames
$AnimatedSprite2D.play("run")

4. Camera2D — 摄像机

控制 2D 场景的视角。

关键属性

var cam = $Camera2D

cam.enabled           = true
cam.zoom              = Vector2(2, 2)   # 放大 2 倍(值越大场景看起来越小)
cam.offset            = Vector2(0, -50) # 视角偏移
cam.rotation          = deg_to_rad(5)  # 摄像机旋转

# 限制摄像机移动范围
cam.limit_left        = 0
cam.limit_top         = 0
cam.limit_right       = 3200
cam.limit_bottom      = 1800

# 平滑跟随
cam.position_smoothing_enabled = true
cam.position_smoothing_speed   = 5.0
cam.rotation_smoothing_enabled = true
cam.rotation_smoothing_speed   = 3.0

# 拖拽边距(摄像机不立即跟随,到达边缘才移动)
cam.drag_horizontal_enabled = true
cam.drag_vertical_enabled   = true
cam.drag_left_margin        = 0.2
cam.drag_right_margin       = 0.2
cam.drag_top_margin         = 0.2
cam.drag_bottom_margin       = 0.2

常用技巧

# 屏幕震动
func shake(duration: float, intensity: float):
    var tween = create_tween()
    var end_time = Time.get_ticks_msec() / 1000.0 + duration
    while Time.get_ticks_msec() / 1000.0 < end_time:
        $Camera2D.offset = Vector2(
            randf_range(-intensity, intensity),
            randf_range(-intensity, intensity)
        )
        await get_tree().process_frame
    $Camera2D.offset = Vector2.ZERO

# 平滑缩放
func zoom_to(target_zoom: Vector2, duration: float):
    var tween = create_tween()
    tween.tween_property($Camera2D, "zoom", target_zoom, duration)\
         .set_trans(Tween.TRANS_SINE)

5. 物理体三兄弟

5.1 StaticBody2D — 静态体

不会移动的物理体,用于地面、墙壁、平台。

# 基本上只需在编辑器配置,代码极少
var body = $StaticBody2D

# 物理材质(摩擦力、弹性)
var mat = PhysicsMaterial.new()
mat.friction  = 0.5
mat.bounce    = 0.2
body.physics_material_override = mat

# 传送带效果(给角色施加恒定速度)
body.constant_linear_velocity  = Vector2(100, 0)
body.constant_angular_velocity = 0.0

5.2 CharacterBody2D — 角色体

玩家和 NPC 的首选,提供精确移动控制。

extends CharacterBody2D

const SPEED    = 200.0
const GRAVITY  = 980.0
const JUMP_VEL = -400.0

func _physics_process(delta):
    # 重力
    if not is_on_floor():
        velocity.y += GRAVITY * delta

    # 跳跃
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = JUMP_VEL

    # 水平移动
    var dir = Input.get_axis("move_left", "move_right")
    velocity.x = dir * SPEED

    move_and_slide()

# 常用检测方法
func check_state():
    is_on_floor()           # 站在地面
    is_on_ceiling()         # 顶到天花板
    is_on_wall()            # 贴着墙壁
    is_on_wall_only()       # 只贴墙(不在地面)
    get_floor_normal()      # 地面法线向量
    get_floor_angle()       # 地面角度(弧度)
    get_last_slide_collision()  # 最后一次碰撞信息
    get_slide_collision_count() # 本帧碰撞次数

move_and_slide 配置

# 上坡最大角度(超过则视为墙)
up_direction             = Vector2.UP
floor_max_angle          = deg_to_rad(46)

# 停在斜坡上不下滑
floor_stop_on_slope      = true

# 楼梯/小台阶自动爬升高度
floor_snap_length        = 16.0

# 推动 RigidBody2D
motion_mode              = CharacterBody2D.MOTION_MODE_GROUNDED

5.3 RigidBody2D — 刚体

受物理引擎完全控制,有质量、重力、摩擦力等。

extends RigidBody2D

func _ready():
    mass           = 2.0
    gravity_scale  = 1.0
    linear_damp    = 0.1   # 线性阻尼
    angular_damp   = 1.0   # 角度阻尼

    # 施加力(持续)
    apply_force(Vector2(100, 0))

    # 施加冲量(瞬间)
    apply_impulse(Vector2(0, -500))

    # 在指定位置施加冲量(产生旋转)
    apply_impulse(Vector2(0, -300), Vector2(20, 0))

    # 直接设置速度
    linear_velocity  = Vector2(200, 0)
    angular_velocity = PI

# 物理回调(不要用 _process)
func _integrate_forces(state: PhysicsDirectBodyState2D):
    # state.linear_velocity
    # state.transform
    pass

# 信号
func _ready():
    body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node):
    print("碰到:", body.name)

6. Area2D — 区域检测

不参与物理碰撞,只检测重叠,用于触发器、拾取物、伤害区域等。

extends Area2D

func _ready():
    # 有物体进入/离开
    body_entered.connect(_on_body_entered)
    body_exited.connect(_on_body_exited)

    # 另一个 Area2D 进入/离开
    area_entered.connect(_on_area_entered)
    area_exited.connect(_on_area_exited)

func _on_body_entered(body: Node2D):
    if body.is_in_group("player"):
        print("玩家进入区域")
        body.apply_damage(10)

func _on_body_exited(body: Node2D):
    print("物体离开:", body.name)

# 主动查询当前重叠的所有物体
func get_overlapping():
    var bodies = get_overlapping_bodies()  # Array[Node2D]
    var areas  = get_overlapping_areas()   # Array[Area2D]
    return bodies + areas

# 检测是否有特定物体在内
func has_player() -> bool:
    for body in get_overlapping_bodies():
        if body.is_in_group("player"):
            return true
    return false

常见用途

# 拾取物
extends Area2D
func _on_body_entered(body):
    if body.is_in_group("player"):
        body.add_item(item_type)
        queue_free()

# 伤害区域(持续)
extends Area2D
var bodies_inside: Array = []

func _ready():
    body_entered.connect(func(b): bodies_inside.append(b))
    body_exited.connect(func(b): bodies_inside.erase(b))

func _process(delta):
    for body in bodies_inside:
        if body.has_method("take_damage"):
            body.take_damage(5 * delta)

# 视野检测
extends Area2D
func can_see_player() -> bool:
    return get_overlapping_bodies().any(func(b): return b.is_in_group("player"))

7. 碰撞形状

7.1 CollisionShape2D

配合物理体或 Area2D 使用,定义碰撞区域形状。

# 常用 Shape 类型
var circle  = CircleShape2D.new();   circle.radius = 16.0
var rect    = RectangleShape2D.new(); rect.size = Vector2(32, 48)
var capsule = CapsuleShape2D.new();  capsule.radius = 12; capsule.height = 40
var seg     = SegmentShape2D.new()   # 线段
var ray     = WorldBoundaryShape2D.new()  # 无限平面

$CollisionShape2D.shape    = circle
$CollisionShape2D.disabled = false   # 禁用碰撞(不删除节点)
$CollisionShape2D.debug_color = Color.RED  # 调试颜色

# 运行时禁用碰撞(如无敌帧)
func set_invincible(value: bool):
    $CollisionShape2D.set_deferred("disabled", value)
    # 注意:物理帧内修改碰撞需用 set_deferred,否则报错

7.2 CollisionPolygon2D

自定义多边形碰撞形状。

var poly = $CollisionPolygon2D

# 设置多边形顶点
poly.polygon = PackedVector2Array([
    Vector2(-20, -30),
    Vector2(20, -30),
    Vector2(30, 0),
    Vector2(20, 30),
    Vector2(-20, 30),
    Vector2(-30, 0),
])

# build_mode 影响碰撞方式
poly.build_mode = CollisionPolygon2D.BUILD_SOLIDS   # 实心
poly.build_mode = CollisionPolygon2D.BUILD_SEGMENTS # 只有边线

8. RayCast2D — 射线检测

从某点向某方向发射射线,检测第一个碰到的物体。

extends Node2D

@onready var ray = $RayCast2D

func _ready():
    ray.enabled        = true
    ray.target_position = Vector2(0, 200)   # 射线终点(局部坐标)
    ray.collision_mask  = 1                  # 只检测 Layer 1

    # 排除自身
    ray.exclude_parent  = true
    ray.collide_with_bodies = true
    ray.collide_with_areas  = false

func _physics_process(_delta):
    if ray.is_colliding():
        var hit_point  = ray.get_collision_point()   # 碰撞点(世界坐标)
        var hit_normal = ray.get_collision_normal()  # 碰撞法线
        var hit_obj    = ray.get_collider()          # 碰到的节点
        var hit_rid    = ray.get_collider_rid()      # 碰到的 RID

        print("碰到:", hit_obj.name, " 在:", hit_point)

# 一次性检测(不需要常驻节点)
func cast_once(from: Vector2, to: Vector2):
    var space = get_world_2d().direct_space_state
    var query = PhysicsRayQueryParameters2D.create(from, to, 1)
    var result = space.intersect_ray(query)
    if result:
        print("命中:", result.collider.name)
    return result

9. ShapeCast2D — 形状扫描

类似 RayCast2D,但用形状代替点,可以检测指定形状沿路径上的碰撞。

@onready var shape_cast = $ShapeCast2D

func _ready():
    var circle = CircleShape2D.new()
    circle.radius = 10.0

    shape_cast.shape          = circle
    shape_cast.target_position = Vector2(0, 100)
    shape_cast.collision_mask  = 1
    shape_cast.max_results     = 5  # 最多检测几个碰撞

func _physics_process(_delta):
    if shape_cast.is_colliding():
        var count = shape_cast.get_collision_count()
        for i in count:
            print(shape_cast.get_collider(i).name)

    # 获取安全移动距离(0.0 ~ 1.0)
    var safe_fraction = shape_cast.get_closest_collision_safe_fraction()

10. VisibleOnScreenNotifier2D — 屏幕可见检测

检测节点是否进入/离开摄像机视野,不影响节点行为,只发出信号。

extends Node2D

func _ready():
    $VisibleOnScreenNotifier2D.screen_entered.connect(_on_entered)
    $VisibleOnScreenNotifier2D.screen_exited.connect(_on_exited)

func _on_entered():
    print("进入屏幕,开始处理")
    set_process(true)

func _on_exited():
    print("离开屏幕,停止处理")
    set_process(false)
    queue_free()  # 敌人/子弹移出屏幕时销毁

调整检测区域

# 默认检测区域是节点的 Rect2
# 可手动设置更大/更小的区域
$VisibleOnScreenNotifier2D.rect = Rect2(-32, -32, 64, 64)

主动查询

if $VisibleOnScreenNotifier2D.is_on_screen():
    # 当前在屏幕内
    play_animation()

11. VisibleOnScreenEnabler2D — 屏幕可见自动开关

VisibleOnScreenNotifier2D 的增强版,自动启用/禁用指定节点的处理,无需写信号代码。

@onready var enabler = $VisibleOnScreenEnabler2D

func _ready():
    # 设置控制哪个节点
    enabler.enable_mode = VisibleOnScreenEnabler2D.ENABLE_MODE_INHERIT_PARENT

    # 控制哪些处理被暂停
    enabler.enable_node_path = NodePath("../Enemy")  # 控制同级 Enemy 节点

enable_mode 选项

说明
ENABLE_MODE_INHERIT_PARENT 控制父节点的 process/physics_process
ENABLE_MODE_ALWAYS 节点始终处于激活状态(不暂停)

推荐用法:VisibleOnScreenEnabler2D 作为敌人节点的子节点,自动在屏外停止 AI 运算,节省性能。


12. Timer — 计时器

精确的倒计时工具,到时发出 timeout 信号。

# 方式一:节点方式
@onready var timer = $Timer

func _ready():
    timer.wait_time  = 2.0
    timer.one_shot   = true   # true=只触发一次,false=循环
    timer.autostart  = false
    timer.timeout.connect(_on_timeout)
    timer.start()

func _on_timeout():
    print("计时结束")

# 暂停/继续
timer.paused = true
timer.paused = false

# 查询剩余时间
print(timer.time_left)

# 方式二:代码创建(无需节点)
func wait_seconds(sec: float):
    await get_tree().create_timer(sec).timeout
    print("等待完成")

# 实用示例:冷却系统
var skill_cooldown := false

func use_skill():
    if skill_cooldown:
        return
    skill_cooldown = true
    _do_skill()
    await get_tree().create_timer(3.0).timeout
    skill_cooldown = false

13. AudioStreamPlayer2D — 2D 音频

在 2D 世界中播放有位置感的音效(距离越远声音越小)。

@onready var player = $AudioStreamPlayer2D

func _ready():
    player.stream          = load("res://audio/explosion.ogg")
    player.volume_db       = 0.0     # 音量(分贝)
    player.pitch_scale     = 1.0     # 音调(>1 变高)
    player.max_distance    = 500.0   # 最远可听距离
    player.attenuation     = 1.0     # 衰减曲线
    player.bus             = "SFX"   # 音频总线

    player.play()
    player.stop()

# 随机音调(让同一音效有变化感)
func play_random_pitch():
    player.pitch_scale = randf_range(0.9, 1.1)
    player.play()

# 完成播放后自动清理(一次性音效)
func play_oneshot(stream: AudioStream, pos: Vector2):
    var p = AudioStreamPlayer2D.new()
    p.stream   = stream
    p.position = pos
    add_child(p)
    p.play()
    p.finished.connect(p.queue_free)

若不需要位置感(如背景音乐、UI 音效),用 AudioStreamPlayer(无 2D 后缀)。


14. AnimationPlayer — 动画播放器

关键帧动画系统,可以对任意节点的任意属性设置动画。

@onready var anim = $AnimationPlayer

func _ready():
    anim.play("idle")
    anim.play("attack", -1, 1.5)  # 动画名, 混合时间, 速度倍率
    anim.play_backwards("run")
    anim.pause()
    anim.stop()

    # 属性
    anim.current_animation     # 当前动画名
    anim.current_animation_position  # 当前播放位置(秒)
    anim.speed_scale           # 全局速度倍率
    anim.autoplay              # 自动播放的动画名

    # 信号
    anim.animation_finished.connect(_on_anim_finished)
    anim.animation_changed.connect(_on_anim_changed)

func _on_anim_finished(anim_name: String):
    if anim_name == "attack":
        $AnimationPlayer.play("idle")

# 等待动画完成
func do_attack():
    $AnimationPlayer.play("attack")
    await $AnimationPlayer.animation_finished
    # 攻击动画结束后继续执行
    state = State.IDLE

15. AnimationTree — 动画状态机

基于图形的动画混合和状态机,配合 AnimationPlayer 使用。

@onready var tree  = $AnimationTree
@onready var state = $AnimationTree.get("parameters/playback") as AnimationNodeStateMachinePlayback

func _ready():
    tree.active = true

# 切换状态
func set_state_run():
    state.travel("Run")

func set_state_idle():
    state.travel("Idle")

# 设置混合参数
func set_move_blend(direction: float):
    # BlendSpace1D 参数
    tree.set("parameters/BlendSpace1D/blend_position", direction)

    # BlendSpace2D 参数
    tree.set("parameters/BlendSpace2D/blend_position", Vector2(dir_x, dir_y))

# 触发一次性动画(Trigger)
func attack():
    tree.set("parameters/AttackTrigger/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)

16. Path2D + PathFollow2D — 路径跟随

让节点沿预设路径移动,常用于巡逻 NPC、弹幕轨迹等。

# Path2D 定义路径曲线(编辑器中绘制贝塞尔曲线)
# PathFollow2D 沿路径移动

@onready var follower = $Path2D/PathFollow2D

var speed := 100.0  # 像素/秒

func _process(delta):
    # progress 是沿路径的像素距离
    follower.progress += speed * delta

    # progress_ratio 是 0.0~1.0 的比例
    # follower.progress_ratio += 0.1 * delta

    # 循环
    follower.loop = true

    # 是否旋转跟随路径方向
    follower.rotates = true

# 代码创建路径
func create_path():
    var path = Path2D.new()
    var curve = Curve2D.new()
    curve.add_point(Vector2(0, 0))
    curve.add_point(Vector2(200, 0))
    curve.add_point(Vector2(200, 200))
    curve.add_point(Vector2(0, 200))
    path.curve = curve
    add_child(path)

17. NavigationAgent2D — 寻路代理

配合 NavigationRegion2D(或 TileMapLayer 的导航层)进行自动寻路。

extends CharacterBody2D

@onready var agent = $NavigationAgent2D

func _ready():
    agent.path_desired_distance    = 4.0   # 到达路径点的判定距离
    agent.target_desired_distance  = 16.0  # 到达目标的判定距离
    agent.max_speed                = 200.0
    agent.navigation_layers        = 1

    # 目标改变时的信号
    agent.navigation_finished.connect(_on_nav_finished)
    agent.target_reached.connect(_on_target_reached)
    agent.waypoint_reached.connect(_on_waypoint_reached)

func move_to(target: Vector2):
    agent.target_position = target

func _physics_process(delta):
    if agent.is_navigation_finished():
        return

    var next_pos  = agent.get_next_path_position()
    var direction = (next_pos - global_position).normalized()

    velocity = direction * 200.0
    move_and_slide()

func _on_nav_finished():
    print("到达目标")

# 避障设置
func setup_avoidance():
    agent.avoidance_enabled = true
    agent.radius            = 16.0
    agent.neighbor_distance = 100.0
    agent.max_neighbors     = 10

18. RemoteTransform2D — 远程变换

将自身的 Transform 同步到另一个节点,常用于摄像机跟随、骨骼挂载等。

# 例:摄像机跟随玩家,但摄像机放在单独的场景中

# 在玩家节点下挂 RemoteTransform2D
@onready var remote = $RemoteTransform2D

func _ready():
    # 指向要同步的目标节点路径
    remote.remote_path         = "/root/World/Camera2D"
    remote.update_position     = true
    remote.update_rotation     = false
    remote.update_scale        = false
    remote.use_global_coordinates = true

19. Marker2D — 标记点

纯粹的位置标记,没有任何功能,用于在场景中标记出生点、巡逻点、炮口位置等。

# Marker2D 本身无属性,只提供 position / rotation

# 常见用途:
# 1. 敌人出生点
var spawn_points = $SpawnPoints.get_children()  # 多个 Marker2D
func get_random_spawn() -> Vector2:
    return spawn_points.pick_random().global_position

# 2. 子弹发射位置
func shoot():
    var bullet = BULLET.instantiate()
    bullet.global_position = $MuzzlePoint.global_position
    bullet.rotation        = $MuzzlePoint.global_rotation
    get_parent().add_child(bullet)

# 3. 巡逻路径点
var patrol_points: Array[Marker2D] = []
var patrol_index := 0

func next_patrol_point() -> Vector2:
    patrol_index = (patrol_index + 1) % patrol_points.size()
    return patrol_points[patrol_index].global_position

20. Line2D — 折线

渲染一条由多个点组成的折线,可设置宽度、颜色、纹理。

@onready var line = $Line2D

func _ready():
    line.width         = 4.0
    line.default_color = Color.RED
    line.begin_cap_mode = Line2D.LINE_CAP_ROUND   # 起点形状
    line.end_cap_mode   = Line2D.LINE_CAP_ROUND   # 终点形状
    line.joint_mode     = Line2D.LINE_JOINT_ROUND # 转折点形状

# 动态绘制轨迹
var trail_points: PackedVector2Array = []

func _process(_delta):
    trail_points.append(global_position)
    if trail_points.size() > 30:
        trail_points.remove_at(0)
    line.points = trail_points

# 清空
line.clear_points()

# 添加/移除点
line.add_point(Vector2(100, 200))
line.remove_point(0)
line.set_point_position(1, Vector2(150, 250))

21. Polygon2D — 多边形

渲染填充多边形,支持纹理、骨骼蒙皮。

@onready var poly = $Polygon2D

func _ready():
    poly.polygon = PackedVector2Array([
        Vector2(-50, -50),
        Vector2(50, -50),
        Vector2(50, 50),
        Vector2(-50, 50),
    ])

    poly.color   = Color(0.2, 0.8, 0.4, 0.8)
    poly.texture = load("res://art/ground.png")

    # UV 坐标(控制纹理映射)
    poly.uv = PackedVector2Array([
        Vector2(0, 0),
        Vector2(1, 0),
        Vector2(1, 1),
        Vector2(0, 1),
    ])

    # 内部孔洞
    poly.internal_vertex_count = 0

22. CPUParticles2D — CPU 粒子

在 CPU 上运算的粒子系统,兼容性好,适合粒子数量少的场合。

@onready var particles = $CPUParticles2D

func _ready():
    particles.emitting        = true
    particles.amount          = 50         # 粒子数量
    particles.lifetime        = 1.5        # 生命周期(秒)
    particles.one_shot        = false      # 是否只发射一次
    particles.explosiveness   = 0.0        # 0=匀速发射 1=同时爆发

    # 方向与散布
    particles.direction       = Vector2(0, -1)  # 发射方向
    particles.spread          = 45.0            # 散布角度

    # 速度
    particles.initial_velocity_min = 50.0
    particles.initial_velocity_max = 150.0

    # 重力
    particles.gravity         = Vector2(0, 98)

    # 缩放
    particles.scale_amount_min = 0.5
    particles.scale_amount_max = 1.5

    # 颜色
    particles.color = Color.YELLOW

# 一次性爆发(如爆炸效果)
func burst(pos: Vector2):
    var p = CPUParticles2D.new()
    p.global_position  = pos
    p.one_shot         = true
    p.explosiveness    = 1.0
    p.amount           = 30
    p.lifetime         = 0.8
    get_parent().add_child(p)
    p.emitting = true
    # 粒子播完后自动销毁
    await get_tree().create_timer(p.lifetime + 0.1).timeout
    p.queue_free()

23. GPUParticles2D — GPU 粒子

在 GPU 上运算,性能更好,支持更多粒子,需要配置 ParticleProcessMaterial

@onready var particles = $GPUParticles2D

func _ready():
    particles.amount      = 500
    particles.lifetime    = 2.0
    particles.emitting    = true

    var mat = ParticleProcessMaterial.new()
    mat.direction                 = Vector3(0, -1, 0)
    mat.spread                    = 30.0
    mat.initial_velocity_min      = 100.0
    mat.initial_velocity_max      = 200.0
    mat.gravity                   = Vector3(0, 98, 0)
    mat.color                     = Color.CYAN

    # 颜色随生命周期变化
    var gradient = Gradient.new()
    gradient.set_color(0, Color.WHITE)
    gradient.set_color(1, Color(1, 1, 1, 0))  # 渐渐透明
    var grad_tex = GradientTexture1D.new()
    grad_tex.gradient = gradient
    mat.color_ramp = grad_tex

    particles.process_material = mat

24. PointLight2D — 点光源

在 2D 场景中投射圆形光照。

@onready var light = $PointLight2D

func _ready():
    light.texture        = load("res://art/light_texture.png")
    light.color          = Color(1.0, 0.8, 0.5)  # 暖黄色
    light.energy         = 1.5
    light.texture_scale  = 2.0        # 光照范围
    light.shadow_enabled = true       # 开启阴影
    light.shadow_color   = Color(0, 0, 0, 0.5)

    # 混合模式
    light.blend_mode = Light2D.BLEND_MODE_ADD  # 叠加(常用)

# 火把闪烁效果
func _process(delta):
    light.energy = 1.0 + sin(Time.get_ticks_msec() * 0.01) * 0.2 \
                       + randf_range(-0.05, 0.05)

25. DirectionalLight2D — 方向光

模拟太阳光等平行光源。

@onready var light = $DirectionalLight2D

func _ready():
    light.color          = Color.WHITE
    light.energy         = 0.8
    light.height         = 0.0         # 光源高度(影响阴影角度)
    light.max_distance   = 10000       # 最大照射距离
    light.shadow_enabled = true

26. LightOccluder2D — 光遮挡

配合 2D 光源使用,定义哪些区域会产生阴影。

@onready var occluder = $LightOccluder2D

func _ready():
    var shape = OccluderPolygon2D.new()
    shape.polygon = PackedVector2Array([
        Vector2(-16, -32),
        Vector2(16, -32),
        Vector2(16, 32),
        Vector2(-16, 32),
    ])
    shape.cull_mode = OccluderPolygon2D.CULL_DISABLED

    occluder.occluder = shape
    occluder.sdf_collision = true  # 参与 SDF 碰撞

27. BackBufferCopy — 后备缓冲

复制屏幕上某区域的像素到纹理,供着色器读取,实现折射、玻璃等效果。

@onready var bbc = $BackBufferCopy

func _ready():
    bbc.copy_mode = BackBufferCopy.COPY_MODE_RECT    # 复制矩形区域
    # 或
    bbc.copy_mode = BackBufferCopy.COPY_MODE_VIEWPORT # 复制整个视口

    bbc.rect = Rect2(-100, -100, 200, 200)  # 复制区域

通常配合 ShaderMaterial 使用,着色器中用 SCREEN_TEXTURE 采样复制的内容。


附录:节点选型速查

显示图片           → Sprite2D
帧动画             → AnimatedSprite2D
复杂动画/属性动画  → AnimationPlayer
动画状态机         → AnimationTree
玩家/NPC 移动      → CharacterBody2D
地形/平台          → StaticBody2D
物理模拟(箱子)   → RigidBody2D
触发区域/拾取      → Area2D
摄像机跟随         → Camera2D
射线检测           → RayCast2D
形状扫描           → ShapeCast2D
自动寻路           → NavigationAgent2D
路径跟随           → Path2D + PathFollow2D
屏幕外销毁         → VisibleOnScreenNotifier2D
屏幕外暂停 AI      → VisibleOnScreenEnabler2D
位置标记           → Marker2D
倒计时/冷却        → Timer
定向音效           → AudioStreamPlayer2D
轨迹/连线          → Line2D
填充形状           → Polygon2D
少量粒子           → CPUParticles2D
大量粒子           → GPUParticles2D
动态光照           → PointLight2D / DirectionalLight2D
产生阴影           → LightOccluder2D
屏幕折射效果       → BackBufferCopy + Shader
位置同步           → RemoteTransform2D