I am making a 2d topdown shooter. The entities are zombies which get a desired direction from a astar pathfinding. The zombie also has a context steering behavior to avoid walls and objects around the map. But for some reason, they interefere with one another, colliding with each other and the like.

Solutions I have tried:

  1. [Currently In-code] if the danger ray hits a zombie, the danger is set to value more than 1, so when the chosen direction is calculated, the interest ray towards that direction will be negative, pointing the interest ray to the opposite direction with slight tweaks to favor sideways motion. This results to zombie moving along each other, however if the zombie sometimes just circle around since it can't find any good direction to move.

How can i make it so that if the zombie detects another zombie towards its path, it moves to the side, avoiding the zombie but still going towards the desired direction?

** Here is a video showing the problem
** Here is the full source code

Here is the code for physicsprocess of zombie:

public override void _PhysicsProcess(float delta)
    {
        base._PhysicsProcess(delta);
        stateManager.PhysicsProcess(delta);
        var space = GetWorld2d().DirectSpaceState;

        var rayDirections = new Vector2[numOfRays].Select((v, i) => Vector2.Right.Rotated(i * 2 * Mathf.Pi / numOfRays).Normalized()).ToArray();
        interestArr = new Vector2[numOfRays];
        dangerArr = new Vector2[numOfRays];
        
        var interest  = new float[numOfRays];
        var dangers = new float[numOfRays];    
        
        // Set interest
        for (int i = 0; i < numOfRays; i++)
        {
            var d = rayDirections[i].Dot(DesiredVelocity.Normalized());
            interest[i] = Mathf.Max(0, d);
        }
        
        Array exclude = new Array() { this };
        // Set dangers
        for (int i = 0; i < numOfRays; i++)
        {
            var result = space.IntersectRay(GlobalPosition,
                GlobalPosition + rayDirections[i] * lookAhead, exclude, collisionLayer: steeringCollisionLayer);
            if (result.Count > 0)
            {
                var distance = GlobalPosition.DistanceTo(result["position"] as Vector2? ?? default) ;
                dangers[i] = 1 - (distance / lookAhead);
                // dangers[i] *= 0.75f;
                if (result["collider"] is ZombieController)
                {
                    dangers[i] = 1f + (distance/lookAhead) * 0.15f;
                }
            }
            else
            {
                dangers[i] = 0;
            }
        }
        
        var chosenDir = Vector2.Zero;

        // Eliminate interest with danger
        for (int i = 0; i < numOfRays; i++)
        {
            if (dangers[i] > 0)
            {
                interest[i] -= dangers[i];
            }

            chosenDir += rayDirections[i] * interest[i];
        }

        var l = DesiredVelocity.Length();
        if (stateManager.CurrentStateEnum == ZombieState.Chasing ||
            stateManager.CurrentStateEnum == ZombieState.Wandering)
        {
            Velocity = chosenDir.Normalized();
        }
        else
        {
            Velocity = DesiredVelocity;
        }

        
        MoveAndSlide(Velocity.Normalized() * MovementSpeed);
    }