1 Introduction to Graphics Programming
ITP4710
2D/3D Graphics Programming
02
Basic 2D Graphics Programming
When you create a new MonoGame project, one of the easiest method is to use the MonoGame given project templates
Start your Visual Studio 2015
Game1.cs, Program.cs and other files will be added into your project automatically
You will mainly work on Game1.cs file.
Like any C# application, a MonoGame application begins by referencing the assemblies and namespaces required by the program
All necessary MonoGame implemented XNA framework references for Graphics, Input and etc. will be automatically added for you in the default Game1.cs file generated
© VTC 2016
2
MonoGame Template
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1 {
public class Game1 : Game {
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1() {
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
}
© VTC 2016
3
Game1.cs
© VTC 2016
4
/// Initialize:
/// Allows the game to perform any initialization
/// it needs to before starting to run.
/// This is where the game query for any required
/// services and load any non-graphic related content.
protected override void Initialize() {
// TODO: Add your initialization logic here
base.Initialize();
}
/// LoadContent:
/// called once per game to load all contents
protected override void LoadContent() {
// Create a new SpriteBatch for drawing textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use Content to load game content here
}
/// UnloadContent: called once per game to unload contents
protected override void UnloadContent() {
// TODO: Unload any non ContentManager content here
}
© VTC 2016
5
/// Update: Allows the game to run logic such as updating
/// the world, checking for collisions, gathering input,
/// and playing audio.
protected override void Update(GameTime gameTime) {
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)
this.Exit(); // Allows the game to exit
// TODO: Add your update logic here
base.Update(gameTime);
}
/// Draw: This is called when the game should draw itself.
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue); // Clear bkgd
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}
MonoGame application requires a GraphicsDeviceManager to handle the configuration and management of the graphics device
The GraphicsDevice class is used for drawing
The GraphicsDeviceManager object is initialized in the game class constructor
The SpriteBatch object provides access to methods for drawing images, referred to as sprites, in the game window
One SpriteBatch object is enough to draw all 2D images in your game
SpriteBatch object is initialized in the LoadContent() function.
6
GraphicsDeviceManager And SpriteBatch
© VTC 2016
ContentManager is used to load, manage and dispose of the media content through the content pipeline
When you uses the game template, the root directory of your content will be defined in the constructor as follows:
Content.RootDirectory = “Content”;
That means all your image, audio and models should be placed in the Content folder in your Solution.
The Content object will be used to load these media content in your LoadContent() function.
7
ContentManager
© VTC 2016
After the GraphicsDeviceManager object has been created, Initialize() method will do the one-time game startup event, such as:
Setting window properties (e.g., title or full-screen).
Initializing arrays and other variables.
Initializing vertices for storing position, color, image coordinates and etc.
Setting up your camera to view the 3D game world.
Setting up other game objects
LoadContent() method is used to load binary image and model content through the content pipeline
LoadContent() is called after Initialize()
LoadContent() will also be called to reload your media resources when the DeviceReset event occurs
8
Initialize() and LoadContent()
© VTC 2016
Once the MonoGame application is initialized, it enters a continuous loop that draw and update the game – which we call game loop
By default, a game uses a fixed-step game loop with a default TargetElapsedTime of 1/60th of a second.
In a fixed-step game loop, Game calls Update() once the TargetElapsedTime has elapsed.
After Update() is called, if it is not time to call Update() again, the game will call Draw().
After Draw() is called, if it is not time to call Update() again, the game idles until it is time to call Update().
If Update() takes too long to process, the game will set IsRunningSlowly to true and calls Update() again, without calling Draw() in between.
You can change the default setting by changing the property Game.IsFixedTimeStep and Game.TargetElapsedTime.
9
Game Loop
© VTC 2016
Update() function is called when the game logic needs to be processed.
This might include the management of the game state, the processing of user input, or the updating of simulation data.
You should override this method in your game with game-specific logic.
Draw() function is called when the game needs to re-draw the frame.
You should override this method with game-specific rendering code.
Override the UnloadContent() function to free up your memory resources that is not loaded into the game through the content manager.
© VTC 2016
10
Update(), Draw() and UnloadContent()
© VTC 2016
11
Game Application Flow
Source: http://centurion2.com/XNA/XNA120/xna120.php
YES
11
Building a 2D game is a nice way to start to learn using MonoGame
Much easier to create than 3D games
Cover many basic techniques and get exciting results
2D image animation is very important to an exciting interactive 2D game
2D coordinate system is used to position the images and determine which sections of the image are drawn
Width and height of the window and all images are measured in pixels
X values start from 0 on the left and increase towards the right
Y values start from 0 on the top and increase downwards
12
2D Graphics Game Programming
© VTC 2016
You can change the size of the game screen or toggle full screen by setting the following properties inside the constructor.
graphics.IsFullScreen = false;
graphics.PreferredBackBufferHeight = height;
graphics.PreferredBackBufferWidth = width;
If you want to change the screen setting after calling the constructor, you need to add the following statement after changing the above properties:
graphics.ApplyChanges();
© VTC 2016
13
Screen Size and Full Screen
MonoGame’s Content Manager loads an image to a Texture2D object
MonoGame supports automatic loading of bmp, dds, dib, hdr, jpg, pfm, png, ppm and tga image files.
The Content Pipeline is also extensible to support other media files
Texture2D is an in-memory digital image that is represented as a 2D array of color values, each representing a pixel
To load the image to a Texture2D object,
A Texture2D object should be declared in class level.
Image file should be added into the Content project through MonoGame’s Content Pipeline Tool.
Use the Content object to load the image file to the Texture2D object.
© VTC 2016
14
Loading Image Files to Textures
15
Loading Image Files to Textures
(Step 1)
© VTC 2016
Texture2D objects declared
16
Loading Image Files to Textures
(Step 2)
© VTC 2016
Double-click the Content Pipeline Tool inside the Content folder
17
Loading Image Files to Textures
(Step 2)
© VTC 2016
Click here to add a folder
Or choose Edie/Add from menu
Or click mouse right button after selecting Content item
Click here to add existing image file(s)
Or choose Edie/Add from menu
Or click mouse right button after selecting Content item
Save and Build the Content Project before exiting back to the MonoGame project.
18
Loading Image Files to Textures
(Step 3)
© VTC 2016
Use “Content” object to load the image files to Texture2D objects
A sprite is a 2D image that is integrated into a larger game scene
Sprites can be positioned and animated independent of each other, using the same texture
Large textures may be broken into multiple smaller images in memory for drawing different sprites
SpriteBatch class manages the drawing of your sprites to the screen
To begin drawing sprites, you call the Begin() method on the SpriteBatch object
Draw your sprites in your Draw() method
Call the End() method of the SpriteBatch to end the process
You may want to set the properties of your SpriteBatch object before drawing your sprite. This will be discussed in later slides.
19
Sprite and SpriteBatch
© VTC 2016
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(texture,
GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
The texture is drawn to the screen by stretching the image to the exact size of your game window
Stretch to the rectangle represented by the second parameter.
new Rectangle(left, top, width, height)
GraphicsDevice.Viewport.Bounds represents the rectangle bounding the window screen.
© VTC 2016
20
Example: Drawing Background Texture
If you don’t want your image stretched, you may call spriteBatch.Draw() function in this way:
spriteBatch.Draw(texture, Vector2.Zero, Color.White);
Vector2.Zero represents (0,0) and such function will draw the image with original size and place it on the top-left corner.
If you want to place your image in the middle, you may try this:
spriteBatch.Draw(texture, new Vector2(
(GraphicsDevice.ViewPort.Width-texture.Width)/2, (GraphicsDevice.ViewPort.Height-texture.Height)/2, Color.White);
© VTC 2016
21
Example: Drawing Background Texture
protected override void Draw(GameTime gameTime) {
Vector2 loc = new Vector2(0, 0); // sprite position
float height = GraphicsDevice.Viewport.Height;
float width = GraphicsDevice.Viewport.Width;
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// draw our background tile in a grid
for (int y=0; y <= height/texture.Height+1; y++) {
loc.Y = y * texture.Height;
for (int x=0; x <= width/texture.Width+1; x++) {
loc.X = x * texture.Width;
spriteBatch.Draw(texture, loc, Color.White);
}
}
spriteBatch.End();
base.Draw(gameTime);
}
© VTC 2016
22
Example: Tiling the Background
© VTC 2016
23
Example: Tiling the Background
When drawing the sprite, we can tint the image using any color
In the previous example, Color.White means no tinting is used.
Colors in MonoGame are expressed using four components
RGBA – namely Red, Green, Blue and Aplha
Many different color constants have been given in MonoGame
Custom colors can also be created through various constructors, passing the component values as 0-255 byte values or 0-1 floating point values.
The fourth component is called “alpha”, which determines the opacity
1.0f means fully opaque, 0.0f means fully transparent
24
Color in MonoGame
© VTC 2016
In the Update() and Draw() methods, a GameTime object is passed as a parameter into the methods
This GameTime object counts the time elapsed between frames and total time since the start of the game
ElapsedGameTime - The amount of elapsed game time since the last update.
ElapsedRealTime - The amount of elapsed real time (wall clock) since the last frame.
TotalGameTime - The amount of game time since the start of the game.
TotalRealTime - The amount of real time (wall clock) since the start of the game.
25
Time Ticking
© VTC 2016
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// use sine function to pulse the tint and transparency
double radians = gameTime.TotalGameTime.TotalSeconds * Math.PI;
float bias = (float)Math.Sin(radians);
// clamp the output of sine (-1 .. 1) to the (0 .. 1) range
bias = (bias + 1.0f) / 2.0f;
Color color1 = new Color(1.0f, bias, bias); // tint color: red
Color color2 = new Color(1.0f, 1.0f, 1.0f, bias);
batch.Draw(texture, new Vector2(100, 100), color1);
batch.Draw(texture, new Vector2(300, 100), color2);
spriteBatch.End();
base.Draw(gameTime);
}
26
Example –
Tinting and Transparent Sprite
© VTC 2016
Creating a series of connected sprites that contain the individual frames, you can make an animation
The different sprites of course can be stored in individual sprites
However, more usually, the series of connected sprites will be stored into a single texture. We called it a tiled sprite.
When you want to play your animation, you simply select the appropriate frame from the tiled sprite and draw it to the screen in its proper position
27
Animated Sprites
© VTC 2016
You will need to declare variables for tracking your animation, which may include:
total number of frames in texture
number of rows and columns if multiple row is applied
current animation frame number
delay between animation frames
time since last frame change
Width and height of the sprite
© VTC 2016
28
Animated Sprites
float frameCount = 10;
float frameWidth = texture.Width/frameCount;
float frameHeight = texture.Height;
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int frame = (int)
(gameTime.TotalGameTime.TotalSeconds*20) % 10;
spriteBatch.Draw(texture, new Vector2(100, 100),
new Rectangle(frame*frameWidth, 0,
frameHeight, frameWidth), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
29
Example – Animated Sprites
© VTC 2016
Advanced versions of SpriteBatch.Draw() function can have more control on the drawing of the sprite
changing the scale of a sprite
rotating the sprite
sorting the sprite by their distance from the player
this requires other spriteBatch setting.
spriteBatch.Draw(texture, // the sprite texture
location, // Vector2 location
rectangle, // null (whole texture) or source rect
color, // tinting color
rotation, // rotating angle in radians
origin, // Vector2 location of rotation center
scale, // float or Vector2 scaling factor
effect, // flipping factor
layerDepth); // sorting depth of sprite
// 0 means front, 1 means back
© VTC 2016
30
Scaling, Moving and Rotating
protected override void Draw(GameTime gameTime) {
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// use sine function to animate the scale
double radians = gameTime.TotalGameTime.TotalSeconds * Math.PI;
float scale = (float)Math.Sin(radians);
// clamp the output of sine (-1 .. 1) to the (0.5 .. 1.5) range
scale = (scale + 1.0f) / 2.0f + 0.5f;
batch.Draw(
texture, // the sprite texture
new Vector2(100, 100), // location to draw the smiley
null, // bounds of texture to be drawn
Color.White, // no tinting
0.0f, // no rotation (zero radians)
new Vector(32,32), // the center of the texture
scale, // our calculated scale factor
SpriteEffects.None, // draw sprite normally
0.5f); // constant layer depth
spriteBatch.End();
base.Draw(gameTime);
}
© VTC 2016
31
Example – Scaling Sprites
Vector2 speed;
float rotateSpeed = 0.01f;
float rotateAngle;
Vector2 loc = new Vector2(
GraphicsDevice.ViewPort.Width/2,
GraphicsDevice.ViewPort.Height/2);
Vector2 smileyCenter = new Vector2(
texture.Width/2, texture.Height/2);
protected override void Initialize() {
Random r = new Random();
speed.X = (float)(r.nextDouble());
speed.Y = (float)(r.nextDouble());
base.Initialize();
}
© VTC 2016
32
Example – Bouncing and Rotating Sprite
private void Update(GameTime gameTime) {
float timeLapse = (float)gameTime.ElapsedGameTime.Milliseconds;
if (loc.X > GraphicsDevice.ViewPort.Width-smileyCenter.X) {
loc.X = GraphicsDevice.ViewPort.Width-smileyCenter.X; // move back
speed.X *= -1.0f;
} else if (loc.X – smileyCenter.X < 0) {
loc.X = smileyCenter.X; speed.X *= -1.0f; // move back
} else loc.X += speed.X * timeLapse;
if (loc.Y > GraphicsDevice.ViewPort.Height-smileyCenter.Y) {
loc.Y = GraphicsDevice.ViewPort.Height-smileyCenter.Y; // move back
speed.Y *= -1.0f; // reverse direction
} else if (loc.Y – smileyCenter.Y < 0) {
loc.Y = smileyCenter.Y; speed.Y *= -1.0f; // move back
} else loc.Y += speed.Y * timeLapse;
rotateAngle += rotateSpeed * timeLapse;
rotateAngle = rotateAngle % (Math.PI * 2.0f); // 0 .. 2PI
}
© VTC 2016
33
Example – Bouncing and Rotating Sprite
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
batch.Draw(
texture, // the sprite texture
loc, // location to draw the smiley
null, // whole texture is to be drawn
Color.White, // no tint
rotateAngle, // rotation
smileyCenter, // the center of the rotation
1.0f, // no scaling
SpriteEffects.None, // draw sprite normally
0.5f); // constant layer depth
spriteBatch.End();
base.Draw(gameTime);
}
© VTC 2016
34
Example – Bouncing and Rotating Sprite
Advanced overloaded version of SpriteBatch.Begin() contains two parameters:
SpriteBatch.Begin Method (SpriteSortMode, BlendState);
SpriteSortMode represents the sprite drawing order
BlendState represents the color blending option
Available SpriteSortMode:
Deferred, Immediate, BackToFront, FrontToBack, Texture
Available BlendState:
Additive, AlphaBlend, Opaque, NonPremultiplied
© VTC 2016
35
SpriteBatch State Settings
When multiple Draw() function calls are made after the default spriteBatch.Begin() function call, the sequence of the drawings seems uncontrolled
The images sequence comes random even if you have passed in the sprite depth parameter in calling the Draw() function.
If you want to make the image to have a sequence according to the sprite depth, you need to set the sort mode inside the spriteBatch.Begin() function call
spriteBatch.Begin(SpriteSortMode.FrontToBack, null);
The above setting will made the front textures (the ones with smaller depth) place on the screen first – that is at the back of other images.
© VTC 2016
36
Using Sprite Depth
Deferred
Default mode for SpriteBatch
Sprites are not drawn until End() is called
Device setting will be applied when End() is called
The sprites will be drawn in one batch, in the sequence of calls to Draw() were received (not the sequence of calls)
Immediate
One active SpriteBatch instance only. Begin() will apply new graphics device settings
Sprites will be drawn within each Draw() call
Immediate mode is similar to but faster than Deferred mode
© VTC 2016
37
SpriteSortMode
BackToFront and FrontToBack
Device setting will be applied when End() is called
When we draw our sprites we can set the layer depth of those sprites to a value is a float between 0.0 (front) and 1.0 (back)
The sprites will draw in the order specified by the two modes
BackToFront is typically used for transparent sprites
FrontToBack is typically used for opaque sprites
Texture
Same as Deferred mode, except sprites are sorted by texture prior to drawing.
Sprites within the same texture will be drawn in a batch
© VTC 2016
38
SpriteSortMode
for (int i = 0; i < 4; i++)
spriteBatch.Draw(texture[i],
new Vector2(50 + (50*i), 50 + (50*i)), location[i],
Color.White, 0.0f, Vector2.Zero, 1.0f,
SpriteEffects.None, i * 0.1f);
© VTC 2016
39
Example – Sprite Depth
Blend state controls how multiple images combined
AlphaBlend
Blending the source (image to be drawn) and destination (image already on screen) using source alpha data
Default value (i.e., when you are using default Begin() function, or when you enter null in the setting)
Opaque
Overwriting the destination image using the source image.
No alpha value will be considered.
Additive
Adding the destination data to the source data without using alpha.
NonPremultiplied
Similar to AlphaBlend, non-premultipled alpha is used if color data does not contain alpha.
© VTC 2016
40
Blend States
You can import a SpriteFont into a game project and draw text using DrawString() method in SpriteBatch.
In your Contente Pipeline Tool, select the Content and right-click your solution explorer. Choose Add > New Item > Sprite Font. Give your sprite font a meaningful name.
An XML file containing font description will be created. Double-click it and choose your text editor to edit the file.
You can modified the fields to alter your font.
FontName
Size – float value, font size in points.
Spacing – float value, amount of spacing in between characters
Style – “Regular”, “Bold”, “Italic” or “Bold, Italic” (case sensitive)
CharacterRegion – specifies which characters in the font are rendered (numbers representing Unicode values)
41
Displaying Text Using SpriteFont
© VTC 2016
42
SpriteFont File (comments removed)
© VTC 2016
To actually draw the text on screen, we need to
Create a SpriteFont in additional to the default SpriteBatch object
SpriteFont Font1;
In your LoadContent() method, call Content.Load(), specifying the SpriteFont class and the asset name of the imported font.
Font1 = Content.Load
In your Draw() method, after calling Begin() of your SpriteBatch object, call DrawString() to draw your text
spriteBatch.DrawString( Font1, “output text”,
FontPos, Color.LightGreen);
Using the SpriteFont object, we can know the size of a string when it is output to the screen using such font.
Vector2 stringSize = font.MeasureString(“XNA Game Studio”);
© VTC 2016
43
Displaying Text Using SpriteFont
SpriteBatch.DrawString (
SpriteFont sf, String output,
Vector2 pos, Color color)
SpriteBatch.DrawString (
SpriteFont sf, String output,
Vector2 pos, Color color,
float rotate, Vector2 origin,
float/Vector2 scale,
SpriteEffects se, float depth)
© VTC 2016
44
SpriteBatch.DrawString()
Reference
Wikipedia topics
DirectX (http://en.wikipedia.org/wiki/DirectX)
OpenGL (http://en.wikipedia.org/wiki/OpenGL)
Comparison of OpenGL and Direct3D (http://en.wikipedia.org/wiki/Comparison_of_OpenGL_and_Direct3D)
Microsoft XNA (http://en.wikipedia.org/wiki/Microsoft_XNA)
MonoGame Documentation (http://www.monogame.net/documentation/)
Tom Miller and Dean Johnson,
XNA Game Studio 4.0 Programming –
Developing for Windows Phone 7 and Xbox 360,
Addison-Wesley, 2011.
Appendix G
45
© VTC 2016