Weird issue with script for "flanking"

I have a script for enemy movement. The enemies can switch states between attacking, idle, flanking, etc.

During attacking the movement is perfect! However during my flanking state, the enemy slowly spins in a circle to the player’s flankPosition (behind the player). I have spent about half a day trying to debug, nothing makes sense! Any help is appreciated! I am putting my code below. For sake of easy reading, I have removed code that is not important!

BROKEN STATE (FLANKING)

Blockquote
void HandleFlankingState()
{
Vector2 flankingPosition = GetFlankingPosition();

    // Check if the monster has line of sight to the player
    bool hasLineOfSight = HasLineOfSight();

    // Check if the monster has reached the flanking position
    if (Vector2.Distance(transform.position, flankingPosition) < nextWaypointDistance)
    {
        // Transition to attacking
        currentMonsterState = MonsterState.Attacking;
    }
    else
    {
        // Move towards the flanking position
        if (hasLineOfSight && seeker.IsDone())
        {
            seeker.StartPath(transform.position, flankingPosition, OnPathComplete);
        }
        MoveAlongPath(); // Reuse the same movement logic as in MoveTowardsPlayer
    }
    

}

Vector2 GetFlankingPosition()
{
    // Get the player's current movement direction
    Vector2 playerDirection = player.GetComponent<Rigidbody2D>().velocity.normalized;

    // If the player is not currently moving, use their facing direction
    if (playerDirection == Vector2.zero)
    {
        playerDirection = player.transform.right; // Assuming the player faces right by default
    }

    // Calculate a position behind the player
    Vector2 flankingPosition = (Vector2)player.transform.position - playerDirection * 2.0f;

    return flankingPosition;
}

void MoveAlongPath()
{
    if (path == null || currentWaypoint >= path.vectorPath.Count)
        return;

    // Direction to the next waypoint
    Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - (Vector2)transform.position).normalized;

    // Move the enemy
    enemyRigidbody.MovePosition(enemyRigidbody.position + direction * speed * Time.deltaTime);

    // Update the animation based on the direction
    monsterAnimator.SetFloat("XInput", direction.x);
    monsterAnimator.SetFloat("YInput", direction.y);
    ChangeAnimationState(MONSTER_WALK);

    // Check if close enough to the next waypoint and advance
    if (Vector2.Distance(transform.position, path.vectorPath[currentWaypoint]) < nextWaypointDistance)
    {
        currentWaypoint++;
    }
}

WORKING STATE (ATTACKING)

void UpdatePath()
{

    // Skip path update if in Flanking state
    if (currentMonsterState == MonsterState.Flanking)
    return;

    // Check if the monster has line of sight to the player
    bool hasLineOfSight = HasLineOfSight();

    // Only update the path if the monster has line of sight and the seeker is ready for a new path
    if (hasLineOfSight && seeker.IsDone()) 
    {
        Path p = seeker.StartPath(transform.position, player.transform.position);
        p.BlockUntilCalculated(); // This will ensure the path is fully calculated
        if (!p.error) 
        {
            // Extract the list of graph nodes from the path
            List<GraphNode> nodePath = p.path;

            // Check if a valid path is possible using the list of nodes
            if (PathUtilities.IsPathPossible(nodePath)) 
            {
                path = p;
                currentWaypoint = 0;
            }
        }
    }
}

void MoveTowardsPlayer()
{
if (path == null || currentWaypoint >= path.vectorPath.Count)
return;

    // Direction to the next waypoint
    Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - (Vector2)transform.position).normalized;

    // Calculate and update lastDirection
    lastDirection = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;

    // Move the enemy
    enemyRigidbody.MovePosition(enemyRigidbody.position + direction * speed * Time.deltaTime);

    // Update the animation based on the direction
    monsterAnimator.SetFloat("XInput", direction.x);
    monsterAnimator.SetFloat("YInput", direction.y);
    ChangeAnimationState(MONSTER_WALK);

    // Check if close enough to the next waypoint and advance
    if (Vector2.Distance(transform.position, path.vectorPath[currentWaypoint]) < nextWaypointDistance)
    {
        currentWaypoint++;
    }

    // Dampen the force over time
    forceToApply *= forceDamping;
    if (Mathf.Abs(forceToApply.x) <= 0.01f && Mathf.Abs(forceToApply.y) <= 0.01f)
    {
        forceToApply = Vector2.zero;
    }
}

Any chance I can get some help for the above?

Hi

It’s hard to tell without knowing anything more about what is going wrong. Is pathfinding not working? Is the unit going to the wrong position? Does it go to the right position, but in a weird way? I’d need more information to help you.

ProblemWithFlanking5
Sorry! I have included a video with DrawGizmos to trace the path of the flanking monster.

You are recalculating the path as quickly as possible (probably once every few frames).
But in your MoveTowardsPlayer method you only check if you have reached a waypoint after you have moved one step towards it. This will make the agent confused since when a new path is calculated, the first waypoint will always be the agent’s position during the last frame when it started to calculate the path.

I’d recommend moving the distance check above the direction code.

1 Like

That was 100% it. Haha thanks! Wonderful asset and wonderful service, I truly appreciate your help.

1 Like