NPC changing sprites to face the player

Hi, I’m currently experiencing an issue with programming NPC’s. I want NPC’s to change their sprite depending on where the player is positioned (example: if the Player is interacting with them and they’re facing right then the NPC faces left). However, while I do know that I’m on the right track, as soon as the Player interacts with the NPC, the NPC changes sprites but then immediately changes back to the idle sprite. If I try interacting with the NPC again, it no longer changes sprites at all and stays at the idle sprite. I’ve been trying to solve this on my own for way too long so I’m reaching out to see who can help.

I’ve linked a video representation of my issue if it helps. Also, if you believe that there’s any extra scripts you may need to see, I’ll show you the script.

https://1drv.ms/v/s!Akv6vtVraeC9mRoo--FF7JpJ0GkK?e=h3DL3P

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*
public class NPCController : MonoBehaviour, Interactable
{
    [SerializeField] Dialogue dialogue;
   
    public void Interact()
    {
        StartCoroutine (DialogueManager.Instance.ShowDialogue(dialogue));
    }
}
*/

public class NPCController : MonoBehaviour, Interactable
{
    [SerializeField] Dialogue dialogue;
    [SerializeField] Transform playerTransform; // Assign the player's transform in the inspector
    private Animator animator; // Reference to the Animator component

    private void Awake()
    {
        animator = GetComponent<Animator>();
    }

    public void Interact()
    {
        Debug.Log("Interact method called");
       
        // Determine the direction to the player
        Vector3 directionToPlayer = playerTransform.position - transform.position;

        // Set the appropriate animation based on the player's position
        if (Mathf.Abs(directionToPlayer.x) > Mathf.Abs(directionToPlayer.y))
        {
            // Player is primarily horizontal to NPC
            if (directionToPlayer.x > 0)
            {
                animator.SetTrigger("FaceRight");
            }
            else if (directionToPlayer.x < 0)
            {
                animator.SetTrigger("FaceLeft");
            }
        }
        else
        {
            // Player is primarily vertical to NPC
            if (directionToPlayer.y > 0)
            {
                animator.SetTrigger("FaceUp");
            }
            else if (directionToPlayer.y < 0)
            {
                animator.SetTrigger("FaceDown");
            }
        }

        // Start the dialogue and wait for it to finish before resetting the sprite
        StartCoroutine(ShowDialogueAndReset());
    }

    private IEnumerator ShowDialogueAndReset()
    {
        yield return StartCoroutine(DialogueManager.Instance.ShowDialogue(dialogue));
        // Reset the NPC sprite to idle after the dialogue is finished
        animator.SetTrigger("ResetIdle");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public enum GameState { FreeRoam, Dialogue, Battle }
public class GameController : MonoBehaviour
{
    [SerializeField] PlayerMovement playerController;

    GameState state;

    private void Start()
    {
        DialogueManager.Instance.OnShowDialogue += () =>
        {
            state = GameState.Dialogue;
        };
        DialogueManager.Instance.OnHideDialogue += () =>
        {
            if (state == GameState.Dialogue)
                state = GameState.FreeRoam;
        };
    }

    void Update()
    {
        if (state == GameState.FreeRoam)
        {
            playerController.HandleUpdate();
        }
        else if (state == GameState.Dialogue)
        {
            DialogueManager.Instance.HandleUpdate();
        }
        else if (state == GameState.Battle)
        {
           
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]

public class Dialogue
{
    [SerializeField] List<string> lines;

    public List<string> Lines
    {
        get { return lines; }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DialogueManager : MonoBehaviour
{
    [SerializeField] GameObject dialogueBox;
    [SerializeField] Text dialogueText;

    [SerializeField] int lettersPerSeconds;

    public event Action OnShowDialogue;
    public event Action OnHideDialogue;
   
    public static DialogueManager Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
    }

    Dialogue dialogue;
    int currentLine = 0;
    bool isTyping;

    public IEnumerator ShowDialogue(Dialogue dialogue)
    {
        yield return new WaitForEndOfFrame();
        OnShowDialogue?.Invoke();

        this.dialogue = dialogue;
        dialogueBox.SetActive(true);
        StartCoroutine(TypeDialogue(dialogue.Lines[0]));
    }

    public void HandleUpdate()
    {
        if (Input.GetKeyDown(KeyCode.F) && !isTyping)
        {
            ++currentLine;
            if (currentLine < dialogue.Lines.Count)
            {
                 StartCoroutine(TypeDialogue(dialogue.Lines[currentLine]));
            }
            else
            {
                dialogueBox.SetActive(false);
                currentLine = 0;
                OnHideDialogue?.Invoke();
            }
        }
    }
   
    public IEnumerator TypeDialogue(string line)
    {
        isTyping = true;  
        dialogueText.text = "";
        foreach (var letter in line.ToCharArray())
        {
            dialogueText.text += letter;
            yield return new WaitForSeconds(1f / lettersPerSeconds);
        }
        isTyping = false;
    }
}

This just sounds like a bug you need to track down and fix by debugging.

Remember, the issue might be in code or it might be in the Animator. Test the Animator first and PROVE it works as you expect when properties are manually changed at runtime without the script interfering.

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

It may be a good idea to add a Debug.Log statement just prior to the line that sets the “ResetIdle” trigger. That way, you can see when it is being triggered.

From the ShowDialogueAndReset code, it looks like the ResetIdle happens after the ShowDialogue coroutine finishes. However, the ShowDialogue coroutine only has a single “yield return new WaitForEndOfFrame()” before it will finish. Was ShowDialogue supposed to have a yield when it called TypeDialogue?