In the last tutorial, we started to see the basics of MonoGame and we were able to put a sprite on the screen, this time we will start to create our own game and program our engine to make it easier to divide our code.

Refactoring our code

First, in Visual Studio, we will create a new folder called Engine, this will be the core of our game and where we will put the general classes.

Within the Engine folder, we will create three classes RenderContextGameObject2D, and GameSprite.

Render Context

In RenderContext we will have our own graphics device, sprite batch and game time. Let’s open our RenderContext class and add the following

The base class

The base class of our game is called GameObject2D. It only saves the position, scale, and rotation of our object and has a Boolean property that determines whether the object should be drawn. This object has only four methods: InitializeLoadContentDraw and Update. These methods are currently empty, but the objects that inherit from this base class are going to implement them.

Open the GameObject2D class and replace what there is with the following

Building our GameSprite class

Now it’s time to build our sprite class. This class will inherit from GameObject2D. In the last tutorial we use the Draw method of the spritebatch to draw our sprite. Now that this class is going to be a common class to our elements, we are going to use it a lot.

Since we are going to use this class to draw textures on the screen, we need to save the name of the texture we want to use and an object to load it.

In our class, we are going to need properties that are used in the Drawmethod, for which we will add all these arguments.

Finally, our class will have two methods: LoadContent and Draw. We will use LoadContent to load our textures and in the Draw method we verify if the object can be drawn to put it on the screen.

This class should be like this

As you can see, this time we use an overload of the Draw method that contains many more parameters than the one we used previously, this is because we want a little more control in our sprite besides just giving it the position. On this occasion, we will be able to use rotation, effects, depth, etc.

Updating our Game1.cs file

We have already created part of our engine, now what we need is to update our main game file to be able to use the classes that we already created.

Let’s update our sprite and create a RenderContext

Now let’s initialize our renderContext, we will update our sprite now as GameSprite and we will also give it an initial position.

We will also update our LoadContent to use our renderContext and call the LoadContent method of our sprite.

In the Update method we need to pass the GameTime to our renderContext. Also here we send to call the Update of our sprite.

Finally, in the Draw method we update our sprite.

If you run the project again, you should see the same thing. What we did was prepare for when our game grows in size and be better organized.

Adding movement to our sprite

For now we have a nice static ship, but what I want is that it has movement so let’s go to do it. The best we can do is encapsulate our player in his own class, we will create a class called Player2D. This class is going to be responsible for loading the texture, updating the position and drawing the texture.

We’re going to make this class inherit from GameObject2D. We could make it inherit from GameSprite but we will not do it, instead we will add a field of the GameSprite type. This is called composition.

Our class should look like the following

The Update method is where we do the logic to move to our sprite, follow the following steps:

  1. As we only calculate the distance that the player has moved since the last update, we must store the current position of the sprite in a temporary variable.
  2. If the address field is 1 (which means we are moving to the right) and the hero’s position is larger than the width of the screen minus the width of the hero (the hero is touching the right edge of the screen) , then, we will deny the address and establish the sprite effect of our hero sprite in FlipHorizontally.
  3. If the address is minus one and the position of the sprite is less than zero, we will set the address to one and we will stop applying a sprite effect.
  4. Then we will add a delta to the position x of the hero. This delta will represent the movement and is calculated by multiplying the speed, the elapsed time of the game and the direction between them. We multiply by the elapsed time of the game to make sure that our hero moves at the same speed, regardless of the frame rate.
  5. Finally, set the position of the sprite.

Updating our Game1.cs class

Since we have our new class, we will update Game1.cs to suit what we have.

First, we change the type of our sprite

In the Initialize method, we create our Player2D instance and remove the position

Now let’s run the project and see how our player moves

Generating animations

It is time to generate the animation of our sprite. For that, we are going to generate the xnb file using the Pipeline as we did in the previous tutorial. We’re going to use the file called Ship.png.

After we have our sprite, we will generate a new GameAnimatedSprite class that will be an extension of GameSprite. Extra functionality will include animation of the sprite.

Let’s go step by step to explain a little better what we will do

Fields

For now, we will need 3 private fields that will help us with the animations, currentFrame tells us the image of the current animation we have, totalFrames is the number of frames we have for sprite sheet and timeUntilNextFrame helps us calculate the speed of the animation

Properties

We also need some properties, values that we need to be able to access from outside the class. We need to know how many frames there are in the sprite sheet, what size each frame has, what frame we are currently showing, and also if we are playing an animation or if it is paused. These values can have a private setter because we do not want them to be modified outside of this class. We also need the frame interval (at what speed the animation goes) and a boolean that determines if we should start the animation.

Constructor

In our constructor, we will pass the necessary parameters of our sprite sheet such as the file name, the number of rows and columns, etc.

Play, Pause and Stop

We will need to add a method to pause, animate or stop the animations. These methods are very simple since we only need to put some values. These properties will be used in the update method.

The Update method

In the Update method we calculate which frame is what we are going to use, we also help frame speed since several frame quantities will give different speeds. That is why in the constructor we pass the number of frames per second that he will need to animate himself well.

The Draw method

In the Draw method is where we really show the animation, first we check if the sprite is animated and it is not paused, if so, then we proceed to draw the sprite. Since it is now a spritesheet, we need to know what frame we are going to draw, calculate the frame with the amount of row and column and then send this calculation to DrawRect so that our class knows what line to draw.

Updating the GameSprite class

As in our GameSpriteAnimation we need to know about the texture and now we can not access it because it is private, we will have to modify the GameSprite class to add a new property

This will stop us from marking an error in the previous file.

Updating our Player2D

Finally, we need to update our Player2D class to use animations.

First, we need to update the playerSprite type

Next, we need to update the Initialize method to user our new animated class

And we also update the Update method so that it takes the new width of the sprite, since as we change the image that we use, we only want to calculate the current frame, this method should be like this

Now we run our game and we should see the animation of our sprite

Summarizing

This time we write a lot of code 🙂 We made a refactoring of our files to make maintenance easier and to help us better manage the objects. We create an animation from a sprite sheet and now we can animate any sprite sheet that we have thanks to the classes that we created.

In the next lesson, we will move our player using the keyboard and not automatically as we are doing.

If you want to see the full code until this part, you can see it on my Github