Here I will breakdown the system I used to animate characters via 2D sprite sheets.
FaceTexController.cs
This is where the core logic is handled. Each facial expression is assigned an ID, essentially the coordinates on the sprite sheet that expression is placed at. When an expression needs to be changed, I just call the SetTextureOffset() method in the meshRenderer component and update the ID to match. This happens instantly, so if done in quick succession it gives the illusion of animation. I have methods to force each expression so that when I want the AI to react to something it's as simple as calling that method. I also have methods running that control the blink animation, making the character blink at random intervals within a given range. Every sprite expression has a variant where the character is either looking left or right, allowing variations within that system as well. Although the manual ID assigning process was very painstaking and tedious, the rest of this process was quite painless and as long as I keep consistent sprite speed sizes I wont need to re-do the ID process many times over and over.
customInspector.cs
This script simply creates buttons that I can use in editor to force certain emotions, purely for debugging purposes.