The Draw method, version 2

The version of the Draw method that we have been using to place images on the screen looks like this:

spriteBatch.Draw(image,rectangle,color);

But there is another version with 9 arguments:

spriteBatch.Draw(

Texture2Dtexture,// image to draw

Vector2position,// the XY position to draw the image

RectanglesourceRectangle,// the source rectangle

Colorcolor,// use White for original color

floatrotation,// rotation angle in radians

Vector2origin,// origin of the image

floatscale,// scale factor. 1=original size

SpriteEffectseffects,// FlipHorizontally, FlipVertically, or None

floatlayerDepth// layer depth

);

Let's discuss the arguments.

Texture2D texture. This is the same as in the other version of the Draw method. It is an image file (jpeg, png, etc.) that you want to appear on the screen. For the following examples, we will use this 300x300 pixel image:

Vector2 position. In the other version of the Draw method, we specified a Rectangle where we wanted the image to appear. This rectangle gave both the position (X, Y) of the image and the scale (Width, Height) of the image. A Vector2 can only specify a position. This argument specifies where the origin of the image will be located. We have always used the upper-left corner of the image as its origin. Another common location to choose for the origin is the center of the image. More on that below.

Rectangle sourceRectangle. The Rectangle argument in the other version of the Draw method specified the destination rectangle (where we wanted the image to appear on the screen). This argument, however, specifies the source rectangle. This allows us to select part of the image to display rather than the entire image. For example, with the picture above, if we specified the source rectangle as (0, 0, 300, 300) we would get the entire picture:

But if we specified the source rectangle as (150, 150, 150, 150), we would get this:

And if we specified the source rectangle as (0, 0, 150, 150), we would get this:

If you want to display the entire image, just pass the value null for this argument.

Color color. This is the same as the other version of Draw. We will normally use Color.White here to display the image without any tint.

float rotation. This allows us to rotate an image on the screen. The value of this argument must be in radians, not degrees. And, unlike trigonometry, where the angle 0 is usually pointing east, the angle 0 in XNA points north. East is 90 degrees (pi/2 radians), south is 180 degrees (2pi/2 = pi radians), and west is 270 degrees (3pi/2 radians). If you are more comfortable with degrees, keep track of the rotation angle in degrees and convert it to radians when necessary using the following function: MathHelper.ToRadians(float degrees). The number of degrees must be passed to the function and it will return the equivalent angle in radians. Note that this is usually not necessary.

Vector2origin.The origin is the point about which the image will be rotated, and it is relative to the original source rectangle. If you are rotating an image on the screen, you probably do not want to rotate it around the point (0, 0). You probably do want to rotate it around the center of the image. Whatever value you specify here is the point in the image that will be used to position it on the screen. Note that theoriginisspecifiedrelativetotheoriginalsource rectangle. So if you scale your image to twice its original size, you do not have to double the values of the origin. Consider the following 300 x 300 image.

If we specify the source rectangle as 0, 0, 300, 300 (the whole picture) and the origin as 0, 0, it will rotate around the upper-left corner. See the white dot in the upper-left corner of the image (but the center of the time-lapse images below).

If we specify the source rectangle as 0, 0, 300, 300 (the whole picture) but the origin as 150, 150, it will rotate around the center of the picture. See the white dot between her eyes.

It gets more interesting if your source rectangle is only part of the original image. If we chose the rectangle 150, 150, 150, 150, which would be the lower right quadrant of the picture, and chose the origin as 0, 0, and rotated the picture, this is what we would get:

Note that the (0,0) that we selected for the origin is relative to the part of the source that we selected.

If we chose the rectangle 150, 150, 150, 150, which would be the lower right quadrant of the picture, and chose the origin as 75, 75, and rotated the picture, this is what we would get:

And if we chose the same rectangle (150, 150, 150, 150), which would be the lower right quadrant of the picture, and chose the origin as 150, 150, and rotated the picture, this is what we would get:

And if you put the origin outside of the image, you can get something like this:

floatscale. This argument allows the programmer to scale the image. If 1 is specified, the image will be its actual size in pixels. For example, if we have an image that is 100 by 100 pixels, it will take up an area that is 100 by 100 pixels on the screen if the scale factor is 1. If 0.5f (note that it must be a float value, not a double; this is why the "f" is needed here) is used, the same image will take up an area that is 50 by 50 pixels on the screen. If 2.0f is used, the 100 by 100 image will occupy an area that is 200 by 200 pixels on the screen.

SpriteEffects effects. This argument allows the programmer to flip the image either horizontally or vertically. You may specify one of the following arguments: SpriteEffects.FlipHorizontally, SpriteEffects.FlipVertically, or SpriteEffects.None.

float layerDepth. This argument allows the programmer to specify how close to the front or back of the image the sprite will appear. Normally, sprites are drawn on the screen in the order that the calls to the Draw method are executed. Images drawn first will appear behind images drawn later. This argument allows the programmer to bypass this default order and specify exactly where in the order of the images, this image will appear. If the value 0 is used here, all images will appear on the screen in the order in which they are drawn. We will just use the value 0 and draw elements in the order in which we want them layered on the screen.

Default values

In this class we will use the following default values unless otherwise specified:

  • Source rectangle: null (selects the entire image)
  • Color: Color.White
  • SpriteEffects: SpriteEffects.None
  • Layer depth: 0

This means that you only have to be concerned with the following 5 arguments:

  • Texture: will be set in the LoadContent method.
  • Position vector: will be updated in the Update method.
  • Origin: will be set once, probably in the LoadContent method.
  • Rotation: will be updated in the Update method.
  • Scale: will be set once, probably in the LoadContent method.

Probably the trickiest part of using this method is deciding what the scale value should be. We have always specified sizes in terms of the screen width or screen height. Now we need a scale factor (a floating point value). But it is pretty easy to do. Let's say that we want the image to be scaled so that its width is 10% of the screen width. It doesn't really matter what the screen width is (because we're using a variable) but to make it simple, let's assume that the screen is 600 pixels wide, our image is 300 pixels wide, and that we want the image to be 10% of the screen width.

We want the image to be 600 * 0.10f = 60 pixels wide.

What do we need the scale factor to be for our 300-pixel image? We want our image to be 60 pixels wide. It is actually 300 pixels wide. What do I have to multiply 300 by to get 60?

300 * imageScaleFactor = 60

imageScaleFactor = 60 / 300

imageScaleFactor = 0.20f

So, what is our formula to get the scale factor for the image?

imageScaleFactor = screen.Width * screenScaleFactor / imageTexture.Width

This should work for any image, any screen size, and any scale factor.

Try it

Create a new project called DrawRotate.

Copy the image of Marilyn Monroe from above into Paint.NET. Crop and/or resize it so that it is 300 pixels by 300 pixels. Import it into your Content folder.

Then add the following code to your program:

Texture2DmarilynTexture;

Vector2marilynPosition;

RectanglemarilynSourceRectangle;

floatmarilynRotation;

Vector2marilynOrigin;

floatmarilynScale, marilynScaleFactor;

RectanglescreenRectangle;

Texture2D screenTexture;

Initialize the image's properties in the Initialize method:

screenRectangle = newRectangle(100, 50, 600, 380);

// Put her in the middle of the screen

marilynPosition.X = screenRectangle.Left + screenRectangle.Width / 2;

marilynPosition.Y = screenRectangle.Top + screenRectangle.Height / 2;

marilynRotation = 0;

marilynOrigin.X = 0;

marilynOrigin.Y = 0;

marilynScale = 0.20f; // 20% of screen width

In the LoadContent method:

screenTexture = Content.LoadTexture2D>("WhiteRectangle");

marilynTexture = Content.LoadTexture2D>("Marilyn300x300");

marilynScaleFactor = screenRectangle.Width * marilynScale /

marilynTexture.Width;

// Pick the whole picture at first

marilynSourceRectangle.X = 0;

marilynSourceRectangle.Y = 0;

marilynSourceRectangle.Width = marilynTexture.Width;

marilynSourceRectangle.Height = marilynTexture.Height;

// Rotate around upper left corner.

marilynOrigin.X = 0;

marilynOrigin.Y = 0;

Display the image in the Draw method:

spriteBatch.Begin();

spriteBatch.Draw(screenTexture, screen, Color.White);

spriteBatch.Draw(marilynTexture, marilynPosition, marilynSourceRectangle,

Color.White, marilynRotation, marilynOrigin, marilynScale,

SpriteEffect.None,0);

spriteBatch.End();

Things to try:

  1. Change the marilynScale value to other values.
  2. Change the marilynRotationvalue to other values.
  3. Make it rotatearound the upper-left corner. Use 0.005f as the rotation increment.
  4. Make it rotate around its center. Set marilynOrigin relative to the selection.
  5. Select part of the image.
  6. Make part of the image rotate around its upper left corner.
  7. Make part of the image rotate around its center.

To select the lower right quadrant:

marilynSourceRectangle.X = marilynTexture.Width / 2;

marilynSourceRectangle.Y = marilynTexture.Height / 2;

marilynSourceRectangle.Width = marilynTexture.Width / 2;

marilynSourceRectangle.Height = marilynTexture.Height / 2;

In class:

Create a program that will create three asteroids and have them continually fall from the top of the playing area. Each time we re-position an asteroid at the top, we will generate a random scale value for it: a number between 5% and 15% of the screen width.

11/3/2018024-TheDrawMethod.docxPage 1 of 11