You can do this with the full spriteBatch overload.
I wrote two additional DrawRectangle methods wrapping up the full version to show you as a example. I included a properly center rotating version.
Sprite batch has rectangle overloads that specify…
The destination area in the drawing window to plot pixels to.
The source area to take texels out of the image from.
The origin parameter relates to the source area texels.
The offset is the way xna did it but it isn’t done right so this example below corrects for that.
The monogame guys didn’t correct it as that is how xna did it and they were trying to keep it the same.
This example shows 2 rectangles under rotation one is centered to rotate on its top left point.
The other at its properly positioned center.
You don’t need to load a image for this example.
You can copy paste it over a newly created projects game1 text and run it.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D createdCheckerBoardTexture;
float imageRotationInUnits = 0;
float imageRotationInRadians = 0f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
createdCheckerBoardTexture = CreateCheckerBoard(GraphicsDevice, 8, 8, Color.Moccasin, Color.Green);
}
/// <summary>
/// Created a texture programmatically so you can just copy paste and run it.
/// </summary>
public static Texture2D CreateCheckerBoard(GraphicsDevice device, int w, int h, Color c0, Color c1)
{
Color[] data = new Color[w * h];
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int index = y * w + x;
Color c = c0;
if ((y % 2 == 0))
if ((x % 2 == 0)) c = c0;
else c = c1;
else
if ((x % 2 == 0)) c = c1;
else c = c0;
data[index] = c;
}
}
Texture2D tex = new Texture2D(device, w, h);
tex.SetData<Color>(data);
return tex;
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
float rotationSpeed = .25f;
imageRotationInUnits += (float)gameTime.ElapsedGameTime.TotalSeconds * rotationSpeed;
if (imageRotationInUnits > 1.0f)
imageRotationInUnits -= 1.0f;
imageRotationInRadians = imageRotationInUnits * MathHelper.Pi * 2f;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
SamplerState ss = new SamplerState() { Filter = TextureFilter.Point };
spriteBatch.Begin(SpriteSortMode.Immediate, null, ss, null,null,null,null);
// Define both the position and the size in a rectangle.
Rectangle imagesDrawingRectangle = new Rectangle(200, 200, 200, 150);
// Draw the rectangle using a wrapped up draw method.
DrawRectangle(createdCheckerBoardTexture, imagesDrawingRectangle, Color.White, imageRotationInRadians, false, false);
// Draw a properly centered rotated rectangle using a wrapped up draw method.
DrawRectangleCenteredRotation(createdCheckerBoardTexture, imagesDrawingRectangle, Color.Blue, imageRotationInRadians, false, false);
spriteBatch.End();
base.Draw(gameTime);
}
/// <summary>
/// A wrapped up draw method.
/// </summary>
public void DrawRectangle(Texture2D textureImage, Rectangle rectangleAreaToDrawAt, Color color, float rotationInRadians, bool flipVertically, bool flipHorizontally)
{
SpriteEffects seffects = SpriteEffects.None;
if (flipHorizontally)
seffects = seffects | SpriteEffects.FlipHorizontally;
if (flipVertically)
seffects = seffects | SpriteEffects.FlipVertically;
// This is a full spriteBatch.Draw method it has lots of parameters to fully control the draw.
spriteBatch.Draw(textureImage, rectangleAreaToDrawAt, new Rectangle(0, 0, textureImage.Width, textureImage.Height), color, rotationInRadians, Vector2.Zero, seffects, 0);
}
/// <summary>
/// A additional method which shows how to offset the drawing.
/// </summary>
public void DrawRectangleCenteredRotation(Texture2D textureImage, Rectangle rectangleAreaToDrawAt, Color color, float rotationInRadians, bool flipVertically, bool flipHorizontally)
{
SpriteEffects seffects = SpriteEffects.None;
if (flipHorizontally)
seffects = seffects | SpriteEffects.FlipHorizontally;
if (flipVertically)
seffects = seffects | SpriteEffects.FlipVertically;
// We must make a couple adjustments in order to properly center this.
Rectangle r = rectangleAreaToDrawAt;
Rectangle destination = new Rectangle(r.X + r.Width /2, r.Y + r.Height /2 , r.Width, r.Height);
Vector2 originOffset = new Vector2(textureImage.Width / 2, textureImage.Height / 2);
// This is a full spriteBatch.Draw method it has lots of parameters to fully control the draw.
spriteBatch.Draw(textureImage, destination, new Rectangle(0, 0, textureImage.Width, textureImage.Height), color, rotationInRadians, originOffset, seffects, 0);
}
}
}
If however you don’t want a true origin rotation you can just pass half the image width and height to the offset in a regular spritebatch.Draw however that will make things much more complicated.