Godot 4.3 C#网格移动卡顿、响应不灵敏问题求助
解决Godot中宝可梦风格网格移动的卡顿与转向问题
问题根源
- 移动卡顿:当前代码仅在角色静止时处理输入,移动过程中无法接收后续方向输入,必须等当前移动完成才能触发下一次移动,导致出现停顿间隙。
- 转向限制:移动时直接跳过输入处理逻辑,必须等角色完全静止才能切换方向,操作体验生硬。
修复方案
- 分离输入检测与移动触发逻辑:无论角色是否在移动,都持续检测输入方向并更新角色朝向、动画;移动完成后自动检查当前是否有持续输入,触发下一次移动。
- 移除移动时的输入阻塞,允许移动过程中实时切换方向。
修改后的完整代码
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"); } } } }
关键修改说明
- 输入处理逻辑调整:移除了
if (moving) return;,无论角色是否移动都持续检测输入,实时更新方向和动画,解决转向必须静止的问题。 - 移动触发时机调整:将移动触发从
_UnhandledInput移到_PhysicsProcess,移动完成后自动检查当前是否有持续输入,无缝触发下一次移动,消除卡顿停顿。 - 不可移动时的动画处理:添加了无法移动时的动画切换逻辑,避免角色在障碍物前保持行走动画。
内容的提问来源于stack exchange,提问作者Grantlbart
相关产品推荐
相关产品推荐

