admin管理员组

文章数量:1410682

I am trying to create a Pokemon Gameboy like grid based movement in Godot, however the movement is choppy, it feels weird as when the character moves after going one tile there is a short pause after which he continues, trying to turn direction is quite the hassle as you need to stand still for a little time before you can go in a different direction, it just doesn't feel right

Here you can see my code, I am using the Dialogue Manager Add-on, which is why Input is inside the Unhandeled Input and use tweening for the actual movement as well as checking if I can actually move to the next tile

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!");
            }
        }
        

        if (moving) return;

        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");
        }


        if (input_dir != Vector2.Zero)
        {
            if (!moving)
            {
                last_dir = input_dir;
                Move();
            }
            
        }
    }

    public override void _PhysicsProcess(double delta)
    {



        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");
            }
        }
    }

    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);
            tween.TweenCallback(Callable.From(() => moving = false));
        }
    }
}

I am trying to create a Pokemon Gameboy like grid based movement in Godot, however the movement is choppy, it feels weird as when the character moves after going one tile there is a short pause after which he continues, trying to turn direction is quite the hassle as you need to stand still for a little time before you can go in a different direction, it just doesn't feel right

Here you can see my code, I am using the Dialogue Manager Add-on, which is why Input is inside the Unhandeled Input and use tweening for the actual movement as well as checking if I can actually move to the next tile

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!");
            }
        }
        

        if (moving) return;

        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");
        }


        if (input_dir != Vector2.Zero)
        {
            if (!moving)
            {
                last_dir = input_dir;
                Move();
            }
            
        }
    }

    public override void _PhysicsProcess(double delta)
    {



        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");
            }
        }
    }

    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);
            tween.TweenCallback(Callable.From(() => moving = false));
        }
    }
}
Share Improve this question asked Mar 7 at 20:39 GrantlbartGrantlbart 111 silver badge1 bronze badge 2
  • 1 Can you add a video showing how the current movement plays out? We will better understand why it feels "choppy" and "weird" if we also see it in action – liggiio Commented Mar 8 at 10:59
  • "Choppiness" is related to the frame rate and the amount of travel one does during that frame. e.g. a rate of (say) 1 pixel per 50-100 ms will look "smooth". (As would a degree of rotation). – Gerry Schmitz Commented Mar 8 at 19:13
Add a comment  | 

1 Answer 1

Reset to default 1

Your call to `Move` should be in physics process, not unhandled input. Physics process is called at a steady interval, unhandled input isn't.

本文标签: Grid based movement in Godot 43 C feeling choppy and not quite responsiveStack Overflow