Part 2 - The Enemy
Class
In this walkthrough, create a new Enemy
class and use it to display a moving enemy on the screen.
Adding ScreenHeight
and ScreenWidth
Properties to the ArcadeFlyerGame
Class
Before creating an enemy, it will be necessary to add two properties to the ArcadeFlyerGame
class: ScreenHeight
and ScreenWidth
. This will allow the Enemy
objects to know where the screen starts and ends. A simple way to create these properties is to use the propfull
code snippet.
- Open the ArcadeFlyerGame.cs file
- Make a new line in the body of the
ArcadeFlyerGame
class, under the existing private fields - If using VS Code with the C# extension, type in "propfull" and press
Enter
. The following code should appear automatically:private int myVar; public int MyProperty { get { return myVar; } set { myVar = value; } }
- Press the
Tab
key to tab through and update the property values;myVar
should bescreenWidth
, andMyProperty
should beScreenWidth
:private int screenWidth; public int ScreenWidth { get { return screenWidth; } set { screenWidth = value; } }
- Set the initial field value to be
1600
, the preferred width of the screen - Add the
private
keyword in front of theset
accessor, so that only theArcadeFlyerGame
class can set the screen width - Repeat the steps above for the
ScreenHeight
property, using900
for the preferred height - In the
ArcadeFlyerGame
constructor, replace the hard-coded1600
and900
with the field values
Code
ArcadeFlyerGame
class:
private int screenWidth = 1600;
public int ScreenWidth
{
get { return screenWidth; }
private set { screenWidth = value; }
}
private int screenHeight = 900;
public int ScreenHeight
{
get { return screenHeight; }
private set { screenHeight = value; }
}
ArcadeFlyerGame
constructor:
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
Loading an Enemy Image Asset
To create an enemy, it will be necessary to have an image for the enemy! Use the following evil ball image, or any other image:
- Save a new image named Enemy.png in the "Content" folder
- Open up the Content.mgcb file in the MonoGame Pipeline Tool
- Click the "Add Existing Item" button
- Select the Enemy.png file
- Click the "Build" button
Now the "Enemy" asset should be loadable in the game!
Defining the Enemy
Class
Now it's time to create an Enemy
class. This will be very similar to creating the Player
class.
Setup
Start with the basic setup for the class.
- Create a new file named Enemy.cs in the "src" folder
- Add
using
statements forMicrosoft.Xna.Framework
andMicrosoft.Xna.Framework.Graphics
- Create a
namespace
wrapper forArcadeFlyer2D
- In the body of the
ArcadeFlyer2D
namespace, define aclass
namedEnemy
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace ArcadeFlyer2D
{
class Enemy
{
}
}
Basic Fields
Add some basic private fields for the Enemy
class:
- A reference to the
root
ArcadeFlyerGame
object - A
position
stored in aVector2
object - A
spriteImage
stored in aTexture2D
object - A
spriteWidth
stored in afloat
- A two-dimensional
velocity
stored in aVector2
object
private ArcadeFlyerGame root;
private Vector2 position;
private Texture2D spriteImage;
private float spriteWidth;
private Vector2 velocity;
Calculated Properties
Some properties can be calculated based on the private fields:
- A
SpriteHeight
property that calculates the properly scaled heightfloat
based on the image dimensions and sprite width - A
PositionRectangle
property that returns aRectangle
representing the location of the enemy on the screen
Because they are calculated, these properties should only have get
accessors, and no set
accessors.
public float SpriteHeight
{
get
{
float scale = spriteWidth / spriteImage.Width;
return spriteImage.Height * scale;
}
}
public Rectangle PositionRectangle
{
get
{
return new Rectangle((int)position.X, (int)position.Y, (int)spriteWidth, (int)SpriteHeight);
}
}
Construction and Content Loading
Next, create the constructor for the Enemy
class, and a LoadContent
method for loading the "Enemy" image asset.
- Define a
public
constructor for theEnemy
class that takes in anArcadeFlyerGame root
object and aVector2 position
object - In the body of the constructor, set the
root
andposition
private fields to the parameter values - Under those statements, set the
spriteWidth
field to128.0f
- Set the
velocity
field to a newVector2
object with-1.0f
and5.0f
- This means the enemy will move left and down
- Define a new method named
LoadContent
with a return type ofvoid
and no parameters - In the body of the
LoadContent
method, useroot.Content.Load
to load the "Enemy" asset - Under that, set the
spriteImage
field to the loaded "Enemy" asset - Back in the constructor, at the bottom of the body, call the
LoadContent
method
public Enemy(ArcadeFlyerGame root, Vector2 position)
{
this.root = root;
this.position = position;
this.spriteWidth = 128.0f;
this.velocity = new Vector2(-1.0f, 5.0f);
LoadContent();
}
public void LoadContent()
{
this.spriteImage = root.Content.Load<Texture2D>("Enemy");
}
The Update
Method
To make an enemy move from frame to frame, it will be necessary to update the position
field. This should happen in a method named Update
. The enemy should move according to the velocity
field, and the velocity
should update so the enemy bounces off the top and bottom of the screen.
- In the body of the
Enemy
class, define a new method namedUpdate
- The method should have a
void
return type, and it should take in aGameTime
parameter
- The method should have a
- In the body of the
Update
method, update theposition
field by adding thevelocity
to it:position += velocity;
- Under the
position
update, create anif
statement - In the condition for the
if
statement, check if the enemy is hitting the top or the bottom of the screen. Either of the following:- Its Y position is less than
0
- Its Y position is greater than the height of the screen minus its own height
- Its Y position is less than
- In the body of the
if
statement, flip the Y velocity by multiplying it by-1
Now, the sprite should be able to move and bounce properly!
public void Update(GameTime gameTime)
{
position += velocity;
if (position.Y < 0 || position.Y > (root.ScreenHeight - SpriteHeight))
{
velocity.Y *= -1;
}
}
The Draw
Method
The last thing the Enemy
class needs to do is actually draw the enemy on the screen!
- In the body of the
Enemy
class, define a new method namedDraw
- The method should have a
void
return type, and it should take in aGameTime
parameter and aSpriteBatch
parameter
- The method should have a
- In the body of the
Draw
method, call thespriteBatch.Draw
method- Pass in the
spriteImage
field, thePositionRectangle
property, andColor.White
- Pass in the
That's all that's needed to draw the sprite!
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(spriteImage, PositionRectangle, Color.White);
}
The Enemy
Class
The code in the Enemy.cs file should look something like this:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace ArcadeFlyer2D
{
class Enemy
{
private ArcadeFlyerGame root;
private Vector2 position;
private Texture2D spriteImage;
private float spriteWidth;
private Vector2 velocity;
public float SpriteHeight
{
get
{
float scale = spriteWidth / spriteImage.Width;
return spriteImage.Height * scale;
}
}
public Rectangle PositionRectangle
{
get
{
return new Rectangle((int)position.X, (int)position.Y, (int)spriteWidth, (int)SpriteHeight);
}
}
public Enemy(ArcadeFlyerGame root, Vector2 position)
{
this.root = root;
this.position = position;
this.spriteWidth = 128.0f;
this.velocity = new Vector2(-1.0f, 5.0f);
LoadContent();
}
public void LoadContent()
{
this.spriteImage = root.Content.Load<Texture2D>("Enemy");
}
public void Update(GameTime gameTime)
{
position += velocity;
if (position.Y < 0 || position.Y > (root.ScreenHeight - SpriteHeight))
{
velocity.Y *= -1;
}
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(spriteImage, PositionRectangle, Color.White);
}
}
}
Using the Enemy
Class to Create an Enemy
Now that the Enemy
class has been defined, all that's left is to use it in the ArcadeFlyerGame
class to make an enemy in the game!
- Open the ArcadeFlyerGame.cs file
- In the body of the
ArcadeFlyerGame
class, add a private field namedenemy
of typeEnemy
- In the body of the
ArcadeFlyerGame
constructor, initialize a newEnemy
object - Pass in
this
, and a newVector2
object for the position to make it appear on the right side of the screen:enemy = new Enemy(this, new Vector2(screenWidth, 0));
- In the
Update
method, call theEnemy
'sUpdate
method on theenemy
field - In the
Draw
method, call theEnemy
'sDraw
method on theenemy
field
Run the game, and the new enemy should appear! It should move to the left, and bounce off the bottom and top of the screen.
Final Code
The final code for this walkthrough is available on GitHub.