You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot 4.3 2D对象移动问题:宠物跟随玩家时抖动异常

解决宠物跟随/随机移动时的抖动问题

宠物抖动的核心原因是状态切换的边界冲突和移动逻辑的硬切换,结合你的代码,给出以下几个针对性修复方案:

1. 给状态切换加缓冲区间,避免阈值反复横跳

当宠物距离玩家刚好在follow_distance(90)附近时,每一帧可能在"向玩家移动"和"随机移动"之间反复切换,导致方向突变抖动。给两个状态设置不同的触发阈值,中间留缓冲区间:

  • 距离>90时,触发向玩家移动
  • 距离<80时,才进入随机移动

同时把移动逻辑从_process改成_physics_process,物理帧是固定时间步长,能避免帧率波动导致的移动不均匀:

func _physics_process(delta):
    if is_active and player:
        var distance = global_position.distance_to(player.global_position)
        # 加入10像素缓冲区间,避免90阈值附近反复切换状态
        if distance > follow_distance:
            move_towards_player(delta)
        elif distance < follow_distance - 10:
            random_move(delta)
        # 距离在80-90之间时,保持当前移动状态,避免频繁切换
        update_depth()

2. 限制随机移动的范围,防止越界触发返回

随机移动时,宠物可能会跑到follow_distance之外,立刻触发向玩家移动,来回抖动。修改random_move函数,确保宠物不会超出玩家的跟随范围:

func random_move(delta):
    random_move_timer += delta
    if random_move_timer >= random_move_interval:
        random_move_timer = 0.0
        random_direction = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized()
    
    # 先计算移动后的临时位置
    var new_pos = global_position + random_direction * move_speed * delta
    # 检查新位置是否超出跟随范围
    var new_distance = new_pos.distance_to(player.global_position)
    if new_distance <= follow_distance:
        global_position = new_pos
    else:
        # 超出范围时,向玩家方向小幅修正
        var to_player_dir = (player.global_position - global_position).normalized()
        global_position += to_player_dir * move_speed * delta * 0.5

3. 给随机方向加平滑过渡,避免硬切换

直接替换random_direction会导致方向突变,用lerp做平滑过渡,让方向变化更自然:

func random_move(delta):
    random_move_timer += delta
    if random_move_timer >= random_move_interval:
        random_move_timer = 0.0
        var new_dir = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized()
        # 用lerp平滑过渡到新方向,0.1是平滑系数,数值越小过渡越慢
        random_direction = random_direction.lerp(new_dir, 0.1)
    
    var new_pos = global_position + random_direction * move_speed * delta
    var new_distance = new_pos.distance_to(player.global_position)
    if new_distance <= follow_distance:
        global_position = new_pos
    else:
        var to_player_dir = (player.global_position - global_position).normalized()
        global_position += to_player_dir * move_speed * delta * 0.5

完整修复后的代码

extends Node2D

var is_active = false
var move_speed = 90.0
var follow_distance = 90.0
var random_move_timer = 0.0
var random_direction = Vector2()
var random_move_interval = 1.0 

var player = null

func random_move(delta):
    random_move_timer += delta
    if random_move_timer >= random_move_interval:
        random_move_timer = 0.0
        var new_dir = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized()
        random_direction = random_direction.lerp(new_dir, 0.1)
    
    var new_pos = global_position + random_direction * move_speed * delta
    var new_distance = new_pos.distance_to(player.global_position)
    if new_distance <= follow_distance:
        global_position = new_pos
    else:
        var to_player_dir = (player.global_position - global_position).normalized()
        global_position += to_player_dir * move_speed * delta * 0.5

func move_towards_player(delta):
    if player:
        var direction = player.global_position - global_position
        var distance = direction.length()
        if distance > 0:
            direction = direction.normalized()
        var speed_factor = clamp(distance / 100.0, 1.0, 3.0)
        if distance > 0.5:
            global_position += direction * move_speed * speed_factor * delta  

func toggle_active(player_node):
    is_active = !is_active
    if is_active:
        player = player_node
        show()
    else:
        player = null
        hide()

func update_depth():
    if player:
        if global_position.y < player.global_position.y:
            z_index = -1
        else:
            z_index = 1

func _physics_process(delta):
    if is_active and player:
        var distance = global_position.distance_to(player.global_position)
        if distance > follow_distance:
            move_towards_player(delta)
        elif distance < follow_distance - 10:
            random_move(delta)
        update_depth()

内容的提问来源于stack exchange,提问作者JVicM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:37:40