I have to start by telling you that I don’t have too much experience in game programming and I’m also not an expert at MonoGame or C#, but I do have more than a decade of experience in programming in general and code design. Game programming is a specific domain where sometimes you have to trade in some good design practice in exchange of performance, but I try to find the middle ground between code that favors me and the code that runs as fast as possible.
With this in mind, here are my thoughts on the example you ask about:
I find this code to be very specific to this game, I don’t see many reusable design there which would the base of a manageable codebase.
I always try to use abstract classes to maximize code reusability to a point where I can just create a controllable player character class like this:
public Knight(ContentManager contentManager, Vector2 position, SpriteFont font = null) : base(RootContainer.Instance.EntityLayer, null, position, null, true, font)
{
SetupAnimations(contentManager);
SetupController();
animations.Offset = new Vector2(0, -10f);
shotEffect = contentManager.Load<SoundEffect>("Audio/Effects/GunShot");
}
private void SetupController()
{
Input = new UserInputController();
UserInput.RegisterControllerState(Keys.Right, () => {
Direction.X += Config.CHARACTER_SPEED * elapsedTime;
CurrentFaceDirection = Engine.Source.Entities.FaceDirection.RIGHT;
});
UserInput.RegisterControllerState(Keys.Left, () => {
Direction.X -= Config.CHARACTER_SPEED * elapsedTime;
CurrentFaceDirection = Engine.Source.Entities.FaceDirection.LEFT;
});
UserInput.RegisterControllerState(Keys.Space, () => {
Direction.Y -= Config.JUMP_FORCE;
}, true);
UserInput.RegisterControllerState(Keys.Down, () => {
if (HasGravity)
{
return;
}
Direction.Y += Config.CHARACTER_SPEED * elapsedTime;
CurrentFaceDirection = Engine.Source.Entities.FaceDirection.DOWN;
});
UserInput.RegisterControllerState(Keys.Up, () => {
if (HasGravity)
{
return;
}
Direction.Y -= Config.CHARACTER_SPEED * elapsedTime;
CurrentFaceDirection = Engine.Source.Entities.FaceDirection.UP;
});
Action shoot = () =>
{
if (lastBulletInSeconds >= SHOOT_RATE)
{
lastBulletInSeconds = 0;
new Bullet(this, CurrentFaceDirection);
shotEffect.Play();
}
};
UserInput.RegisterControllerState(Keys.RightShift, shoot, true);
UserInput.RegisterControllerState(Keys.LeftShift, shoot, true);
UserInput.RegisterMouseActions(() => {Config.SCALE += 0.1f; Globals.Camera.Recenter(); }, () => { Config.SCALE -= 0.1f; Globals.Camera.Recenter(); });
}
public override void Update(GameTime gameTime)
{
lastBulletInSeconds += gameTime.ElapsedGameTime.TotalSeconds;
base.Update(gameTime);
}
private void SetupAnimations(ContentManager contentManager)
{
animations = new AnimationStateMachine();
string folder = "SideScroller/KnightAssets/HeroKnight/";
List<Texture2D> knightIdle = SpriteUtil.LoadTextures(folder + "Idle/HeroKnight_Idle_", 7);
AnimatedSpriteGroup knightAnimationIdleRight = new AnimatedSpriteGroup(knightIdle, this, animationFps);
Func<bool> isIdleRight = () => CurrentFaceDirection == FaceDirection.RIGHT;
animations.RegisterAnimation("IdleRight", knightAnimationIdleRight, isIdleRight);
AnimatedSpriteGroup knightAnimationIdleLeft = new AnimatedSpriteGroup(knightIdle, this, animationFps, SpriteEffects.FlipHorizontally);
Func<bool> isIdleLeft = () => CurrentFaceDirection == FaceDirection.LEFT;
animations.RegisterAnimation("IdleLeft", knightAnimationIdleLeft, isIdleLeft);
List<Texture2D> knightRun = SpriteUtil.LoadTextures(folder + "Run/HeroKnight_Run_", 7);
AnimatedSpriteGroup knightRunRightAnimation = new AnimatedSpriteGroup(knightRun, this, animationFps);
Func<bool> isRunningRight = () => Direction.X > 0.5f && !CollisionChecker.HasColliderAt(GridUtil.GetRightGrid(GridCoordinates));
animations.RegisterAnimation("RunRight", knightRunRightAnimation, isRunningRight, 1);
List<Texture2D> knightJump = SpriteUtil.LoadTextures(folder + "Jump/HeroKnight_Jump_", 2);
AnimatedSpriteGroup knightJumpRightAnimation = new AnimatedSpriteGroup(knightJump, this, animationFps);
Func<bool> isJumpingRight = () => JumpStart > 0f && CurrentFaceDirection == FaceDirection.RIGHT;
animations.RegisterAnimation("JumpRight", knightJumpRightAnimation, isJumpingRight, 2);
List<Texture2D> knightRun = SpriteUtil.LoadTextures(folder + "Run/HeroKnight_Run_", 7);
AnimatedSpriteGroup knightRunRightAnimation = new AnimatedSpriteGroup(knightRun, this, animationFps);
Func<bool> isRunningRight = () => Direction.X > 0.5f && !CollisionChecker.HasColliderAt(GridUtil.GetRightGrid(GridCoordinates));
animations.RegisterAnimation("RunRight", knightRunRightAnimation, isRunningRight, 1);
List<Texture2D> knightFall = SpriteUtil.LoadTextures(folder + "Fall/HeroKnight_Fall_", 3);
AnimatedSpriteGroup knightFallRightAnimation = new AnimatedSpriteGroup(knightFall, this, animationFps);
Func<bool> isFallingRight = () => Direction.Y > 0f && CurrentFaceDirection == FaceDirection.RIGHT;
animations.RegisterAnimation("FallRight", knightFallRightAnimation, isFallingRight, 3);
//and so on...
Animations = animations;
}
This example showcases my approach of code design. Each of my displayed entities has one instance of my class called AnimationStateMachine, this can contain as many animations as you want, and they are invoked when their condition becomes true based on their priority. For example, the condition for playing the “RightRun” animation is checking whether character’s X direction is bigger than 0.5 (it could be checked against simply 0, but this 0.5 gives better look) and whether there is a collider to the right of the character:
Func<bool> isRunningRight = () => Direction.X > 0.5f && !CollisionChecker.HasColliderAt(GridUtil.GetRightGrid(GridCoordinates));
When you are running to the right, the “RunRight” animation will be played , but if you also hit jump while running, the jump has higher priority so the animation controller will paly the “JumpRight” animation, so the character is not going to run in the air. I can add another animation very easily, for example if I want to add shooting, that must be the highest priority, becuase when I’m running right, and then jump and shoot in the air, the shooting animation must take precedence. This would really just take 3-4 lines of code to add to my character and it works.
It also works when an AI controls the entity, as the animations are not tied to keyboard inputs, but to the state of my objects, which also changes if an AI does something to my character, which is a huge advantage and time saver!
This kind of approach maximize my code reusability and minimizes the maintenance/refactoring efforts, and I’m not hardcoding animations like they do in the platformer example you linked. I can create a new kind of visual entity in my game by simply instantianating my Entity class or creating a child class from it, setup the audio, animation states, controllers if necessary and that’s it!
I use a similar, but reversed logic for the key inputs:
You can register key presses with an action, and when the user hits the key, my inputcontroller will fire that specific action, like how shooting is mapped to my left/right shift keys:
Action shoot = () =>
{
if (lastBulletInSeconds >= SHOOT_RATE)
{
lastBulletInSeconds = 0;
new Bullet(this, CurrentFaceDirection);
shotEffect.Play();
}
};
UserInput.RegisterControllerState(Keys.RightShift, shoot, true);
UserInput.RegisterControllerState(Keys.LeftShift, shoot, true);
I’m not saying that my approach is the best (there is no best anyways), I’m not even stating that it’s among the best or nicest solutions, but it served me well so far and I can create a basic platformer or top down game example with really not so much code (although there is still a lot to be implemented, as I only started writing this engine a few weeks ago in my free time). I also take the time to refactor and redesign if I see that something isn’t as good as good as I though or I come up with a better design or better performance.
There a few things that I try to keep in mind:
1, Is this piece of code very specific to this object I’m working on, or can it be reused somewhere else? If so, I go for abstract class and interface based design (although I try avoid unnecessary casting in Draw/Update loops)
2, Can’t this forest of if statements be simplified to a better design? like my anmation controller, that decides by itself which animation to play based on the set of criteria. Check “finite state machines” in general to understand to understand the idea behind this design.
3, Am I repeating a piece of code for too many times now? If so, then it’s time to add/change an abstract class or create a new child class that encapsulates the repeated code and just instainate that instead.
4, Am I executing some code unnecessarily in a loop? Or during Draw() or Update() maybe? If so, I put them outside of loops or redesign the code that loops only contain only the absolutely necessary code pieces, everything else is only executed once or as few time as possible.
5, When designing a new feature, what are the “core” features that will most likely be shared across the game? Is there a code that it’s mostly the same for all my objects and the only difference is just a small implementation detail? If so, I just put it to an abstract class and call an abstract function that I override in each child classes for the desired functionality.
6, Am I creating new objects in a high volume? Will this functionality trigger fequent garbage collection? If so, then I’ll add some kind of Object Pooling solution and reuse whatever is possible and makes sense.
7, And of course: is this code going to perform well? 
Some people to follow if you’d like to see good design patterns and high performance solutions:
https://deepnight.net/tutorials/ - the blog of the creator of Dead Dells, his git repos are amazing. Even though it’s not MonoGame, his ideas are still great and can easily be translated to mono.
https://www.patreon.com/NemoKrad/posts - he is writing a game engine in monogame, although it’s many aspects are applicable in 2D as well 
I hope this writing is helpful to you, good luck on your journey.