XNA Tutorials/Rotating a Sprite
by Misael Cojtin and Rae Melton
Luckily for us, the XNA spriteBatch.Draw function comes equipped with a "rotation" argument, so the actual process of rotating the sprite on screen is trivial. The only coding that the programmer needs to do involves the rate at which the sprite rotates, done by figuring out a nifty algorithm to adjust the parameter passed in as the "rotation" variable.
Start off by completing the Setup Tutorial, this will give you an idea of how the functions work while programming in XNA.
There are some significant differences between the code for making the sprite bounce, the code for making the sprite rotate in any given point of the screen, and the code for combining them.
As we can see on the next picture, the code used, in the LoadContent() function, to make the sprite bounce from side to side, its commented at the top of the new code. We have also added two new variables:
- The variable "Origin" its the point that will serve as the origin of the rotation, By default, the origin of a sprite is (0,0), the upper-left corner, here we initialized it to be the center of the sprite. - The variable "spritePosition", which was originally named "screenpos", which keeps track of the position of the sprite.
As mentioned before, the function that actually takes care of the rotation, is the Draw() function, as we can see on the next picture, all we need to do is call the Draw function with the sprite, angle, screen position, and origin of the texture.
After setting up the code, the rest of the code has to do with the math logic behind the rotation.
Rotating in Radians
The argument that the SpriteBatch.Draw() function takes for rotation is in terms of Radians. A complete rotation of 360 degrees is equivalent to 2*pi radians, so the parameter passed in for "rotation" should lie somewhere between 0 and 2*pi (as anything larger would be redundant for rotation).
Now that you know about the rotation argument, you have to know how to handle it. You can't just pass the Draw function any value between 0 and 2*pi or you won't achieve a fluid spinning animation. Instead, you're going to want the RotationAngle argument to scale from 0 to 2*pi smoothly with time.
The following code, which should be included in your Update() function, executes this smooth adjustment of the RotationAngle argument:
// The time since Update was called last. float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; //Calculate rotation angle based on time elapsed float circle = MathHelper.Pi * 2; RotationAngle += elapsed % circle;
The first portion gets the amount of time since the Update() function was called last and stores it in a new variable called "elapsed."
The second portion stores the 2*pi value in a new variable called circle; this is to define a value for our upper bound of 2*pi radians. Then you take the modulus of the value in elapsed by circle (the result is a value between 0 and 2*pi) and add it to the RotationAngle, thus slowly incrementing the RotationAngle from 0 to 2*pi.
Similarly to how the sprite moves 50 pixels a second in either direction, now the sprite rotates at 1 radian a second, making a complete rotation in about 6.28 seconds (2x3.14 or 2*pi).
Making the Sprite Spin Counter-Clockwise
- To make your sprite spin counter-clockwise, all you have to do is change the portion of the code adjusting the RotationAngle from += to -= as follows:
float circle = MathHelper.Pi * 2;//To define an upper bound of 2*pi radians RotationAngle -= elapsed % circle;
Increasing or Decreasing the Speed of Rotation
- To adjust the speed of rotation, simply add the following code beneath the definition of the "elapsed" variable in your Update function:
//NOTE: adjust the following variable to control rotation speed- // < 1: slower // > 1: faster float rotationSpeed = 1; elapsed *= rotationSpeed;
Adjusting the Bounce Margin
- To change the margin or boundaries for the sprite to move around in (aka how close it can get to the edges of the window before it "bounces"), just update the following variables in the UpdateSprite function:
int MaxX = graphics.GraphicsDevice.Viewport.Width - (myTexture.Width / 2); int MinX = (myTexture.Width / 2); int MaxY = graphics.GraphicsDevice.Viewport.Height - (myTexture.Width / 2); int MinY = (myTexture.Width / 2);
- This defines the area available to the sprite to be within half of it's size to the maximum size of the window minus half of the sprite's size. Initially the origin of the sprite is set to be in its upper left-hand corner, so the Mins and Maxes are set to be the top and left edges of the window and the sprite's height and width away from the right and bottom edges of the window; this allows the sprite to just bump into the edges before changing direction.
- When you update the game for rotating, you have to adjust the sprite's origin to be its center, so the you have to adjust the margins accordingly. The origin is now half the sprite's dimensions from its edges, so the bounce margin can be set to half the sprite's dimensions.
Increasing or Decreasing the Sprite Movement Speed
- In your code (assuming you have completed the setup tutorial), there should be a line that looks like this:
Vector2 spriteSpeed = new Vector2(50.0f, 50.0f);
- This essentially defines the movement speed of the sprite to be 50 pixels in the x-direction and 50 pixels in the y-direction every second (the "f" character casts the values as single-point float types). To increase the speed of the sprite, increase the values; similarly, decrease the values to decrease the speed of the sprite.