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

Godot 4.3 C#网格移动卡顿、响应不灵敏问题求助

解决Godot中宝可梦风格网格移动的卡顿与转向问题

问题根源

  1. 移动卡顿:当前代码仅在角色静止时处理输入,移动过程中无法接收后续方向输入,必须等当前移动完成才能触发下一次移动,导致出现停顿间隙。
  2. 转向限制:移动时直接跳过输入处理逻辑,必须等角色完全静止才能切换方向,操作体验生硬。

修复方案

  • 分离输入检测与移动触发逻辑:无论角色是否在移动,都持续检测输入方向并更新角色朝向、动画;移动完成后自动检查当前是否有持续输入,触发下一次移动。
  • 移除移动时的输入阻塞,允许移动过程中实时切换方向。

修改后的完整代码

using Godot; 
using Godot.Collections;

public partial class CharacterBody2d : CharacterBody2D
{
    int tile_size = 16;
    bool moving;
    Vector2 input_dir = Vector2.Zero;
    Vector2 last_dir = Vector2.Down;
   
    AnimatedSprite2D charAnim;
    Marker2D directionMarker;
    Area2D actionableFinder;
    public Tween tween;
   
    public override void _Ready()
    {
        charAnim = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
        directionMarker = FindChild("Direction") as Marker2D;
        actionableFinder = GetNode<Area2D>("Direction/Area2D");
        if (actionableFinder == null)
        {
            GD.PrintErr("Actionale Node is empty");
        }
        else 
        { 
            GD.Print("Found: " + actionableFinder.Name);
        }
    }

    public override void _UnhandledInput(InputEvent @event)
    {
        if (Input.IsActionJustPressed("ui_accept"))
        {
            Array<Area2D> actionables = actionableFinder.GetOverlappingAreas();
            if (actionables.Count > 0)
            {
                (actionables[0] as Actionable).Action();
                input_dir = Vector2.Zero;
                GD.Print("Hey Man!");
            }
        }

        // 无论是否移动,都持续检测输入方向
        input_dir = Vector2.Zero;
        if (Input.IsActionPressed("ui_down"))
        {
            input_dir = Vector2.Down;
            directionMarker.Rotation = Mathf.DegToRad(0);
            charAnim.Play("WalkFront");
        }
        else if (Input.IsActionPressed("ui_up"))
        {
            input_dir = Vector2.Up;
            directionMarker.Rotation = Mathf.DegToRad(180);
            charAnim.Play("WalkBack");
        }
        else if (Input.IsActionPressed("ui_right"))
        {
            input_dir = Vector2.Right;
            directionMarker.Rotation = Mathf.DegToRad(270);
            charAnim.FlipH = true;
            charAnim.Play("WalkSide");
        }
        else if (Input.IsActionPressed("ui_left"))
        {
            input_dir = Vector2.Left;
            directionMarker.Rotation = Mathf.DegToRad(90);
            charAnim.FlipH = false;
            charAnim.Play("WalkSide");
        }

        // 记录最后输入的方向,用于静止时的 idle 动画
        if (input_dir != Vector2.Zero)
        {
            last_dir = input_dir;
        }
    }

    public override void _PhysicsProcess(double delta)
    {
        // 静止且无输入时播放 idle 动画
        if (!moving && input_dir == Vector2.Zero)
        {
            if (last_dir == Vector2.Down) charAnim.Play("IdleFront");
            else if (last_dir == Vector2.Up) charAnim.Play("IdleBack");
            else if (last_dir == Vector2.Left)
            {
                charAnim.FlipH = false;
                charAnim.Play("IdleSide");
            }
            else if (last_dir == Vector2.Right)
            {
                charAnim.FlipH = true;
                charAnim.Play("IdleSide");
            }
        }

        // 移动完成后,若有持续输入则自动触发下一次移动
        if (!moving && input_dir != Vector2.Zero)
        {
            Move();
        }
    }

    protected void Move()
    {
        if (moving) return;

        Vector2 motion = input_dir * tile_size;
        bool canMove = !TestMove(Transform.Translated(motion), Vector2.Zero);

        if (canMove)
        {
            moving = true;
            Vector2 target_pos = Position + motion;

            tween = CreateTween();
            tween.TweenProperty(this, "position", target_pos, 0.35);
            // 移动完成后标记为非移动状态,让 PhysicsProcess 检测是否触发下一次移动
            tween.TweenCallback(Callable.From(() => moving = false));
        }
        else
        {
            // 无法移动时,切换为 idle 动画
            if (last_dir == Vector2.Down) charAnim.Play("IdleFront");
            else if (last_dir == Vector2.Up) charAnim.Play("IdleBack");
            else if (last_dir == Vector2.Left)
            {
                charAnim.FlipH = false;
                charAnim.Play("IdleSide");
            }
            else if (last_dir == Vector2.Right)
            {
                charAnim.FlipH = true;
                charAnim.Play("IdleSide");
            }
        }
    }
}

关键修改说明

  1. 输入处理逻辑调整:移除了if (moving) return;,无论角色是否移动都持续检测输入,实时更新方向和动画,解决转向必须静止的问题。
  2. 移动触发时机调整:将移动触发从_UnhandledInput移到_PhysicsProcess,移动完成后自动检查当前是否有持续输入,无缝触发下一次移动,消除卡顿停顿。
  3. 不可移动时的动画处理:添加了无法移动时的动画切换逻辑,避免角色在障碍物前保持行走动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:55:14