How to make 4-directional movement for an enemy

Godot Version

4.3

Question

I’m trying to code an enemy that will move the player based on the 4 different main directions; left right down and up. Currently I have a setup of conditional statements that will set the enemy’s movement vector based on what axis it is away from the player (target). However, in testing, the enemy does move sideways but not up or down, and instead it is stuck in a jittering motion when it tries to. How can I fix this?

Here’s the code:

Vector2 movement = Vector2.Zero;

		if (Position.X <= target.Position.X)
		{
			movement = Vector2.Right;
		}
		else if (Position.X >= target.Position.X)
		{
			movement = Vector2.Left;
		}
		else if (Position.Y <= target.Position.Y)
		{
			movement = Vector2.Down;
		}
		else if (Position.Y >= target.Position.Y)
		{
			movement = Vector2.Up;
		}

		Position += movement * speed * (float)delta;

		MoveAndSlide();
Vector2 movement = Vector2.Zero;

		if (Position.X <= target.Position.X)
		{
			movement = Vector2.Right;
		}
		else if (Position.X >= target.Position.X)
		{
			movement = Vector2.Left;
		}
		if (Position.Y <= target.Position.Y)
		{
			movement = Vector2.Down;
		}
		else if (Position.Y >= target.Position.Y)
		{
			movement = Vector2.Up;
		}

		Position += movement * speed * (float)delta;

		MoveAndSlide();

you can change this:

		if (Position.X <= target.Position.X)

To something like

		if (Position.X - target.Position.X > 0.1)
        ....
		else if (Position.X - target.Position.X < -0.1)
        ....

to remove jittering when position gonna be near player because float is usually near 0 but never 0 if not set manually 0.

Sadly the jittering still happens.

I don’t know if this would help, but you can take the vector to the target and round it to the nearest multiple of Tau/4 radians or Tau / 8 radians if you want. It might still jitter if the target is directly along one of those lines.

Sorry, I don’t know C#. The ideas should be roughly the same, even if the exact code is slightly different.

#In GDScript
var target := Vector2(0, 0)
var vector_to_target := target - position #I can never remember, it might be position - target
var direction := (TAU / 4) * (round(vector_to_target.angle / (TAU / 4)))
#Round the angle to the nearest multiple, where TAU / 4 is the angle you want.
#TAU / 4 is 90 degrees, TAU / 8 is 45 degrees
position += direction * speed * delta

you can check with different length

using Godot;

public partial class Enemy : CharacterBody2D
{
	[Export] public Node2D target;
	public const float Speed = 200.0f;

	public override void _PhysicsProcess(double delta)
	{
		Vector2 movement = Vector2.Zero;

		if (Position.X - target.Position.X < -2)
			movement = Vector2.Right;

		else if (Position.X - target.Position.X > 2)
			movement = Vector2.Left;

		else if (Position.Y - target.Position.Y < -2)
			movement = Vector2.Down;

		else if (Position.Y - target.Position.Y > 2)
			movement = Vector2.Up;

		Position += movement * Speed * (float)delta;

		MoveAndSlide();

	}
}

MoveAndSlide can collide with manual position settings

1 Like

if you want more direct to player you needed check which distance is longest (X or Y)

using Godot;

public partial class Enemy : CharacterBody2D
{
	[Export] public Node2D target;
	public const float Speed = 200.0f;

	public override void _PhysicsProcess(double delta)
	{
		Vector2 movement = Vector2.Zero;

		var distances = new Vector2(Position.X - target.Position.X, Position.Y - target.Position.Y);

		if (Mathf.Abs(distances.X) > Mathf.Abs(distances.Y))
		{
			if (distances.X < -2)
				movement = Vector2.Right;
			else if (distances.X > 2)
				movement = Vector2.Left;
		}
		else
		{
			if (distances.Y > 2)
				movement = Vector2.Up;
			else if (distances.Y < -2)
				movement = Vector2.Down;
		}

		Position += movement * Speed * (float)delta;

	}
}
1 Like

This is what I needed, thank you!

1 Like