- Open your existing Flood Control project in Visual C# Express if it is not already active.
- Add a new class to the project called "RotatingPiece".
- Add "
using Microsoft.Xna.Framework;
" to theusing
area at the top of the class. - Update the declaration of the class to read
class RotatingPiece : GamePiece
. - Add the following declarations to the RotatingPiece class:
public bool clockwise; public static float rotationRate = (MathHelper.PiOver2 / 10); private float rotationAmount = 0; public int rotationTicksRemaining = 10;
- Add a property to retrieve the current rotation amount:
public float RotationAmount { get { if (clockwise) return rotationAmount; else return (MathHelper.Pi*2) - rotationAmount; } }
- Add a constructor for the RotatingPiece class:
public RotatingPiece(string pieceType, bool clockwise) : base(pieceType) { this.clockwise = clockwise; }
- Add a method to update the piece:
public void UpdatePiece() { rotationAmount += rotationRate; rotationTicksRemaining = (int)MathHelper.Max( 0, rotationTicksRemaining-1); }
In step 2, we modified the declaration of the RotatingPiece class by adding : GamePiece
to the end of it. This indicates to Visual C# that the RotatingPiece class is a child of the GamePiece class.
The clockwise variable stores a "true" value if the piece will be rotating clockwise and "false" if the rotation is counter-clockwise.
When a game piece is rotated, it will turn a total of 90 degrees (or pi/2 radians) over 10
animation frames. The MathHelper class provides a number of constants to represent commonly used numbers, with MathHelper.PiOver2
being equal to the number of radians in a 90 degree angle. We divide this constant by 10
and store the result as the rotationRate
for use later. This number will be added to the rotationAmount
float, which will be referenced when the animated piece is drawn.
Tip
Working with radians
All angular math is handled in radians from XNA's point of view. A complete (360 degree) circle contains 2*pi radians. In other words, one radian is equal to about 57.29 degrees. We tend to relate to circles more often in terms of degrees (a right angle being 90 degrees, for example), so if you prefer to work with degrees, you can use the MathHelper.ToRadians()
method to convert your values when supplying them to XNA classes and methods.
The final declaration, rotationTicksRemaining
, is reduced by one each time the piece is updated. When this counter reaches zero, the piece has finished animating.
When the piece is drawn, the RotationAmount
property is referenced by a spriteBatch.Draw()
call and returns either the rotationAmount
property (in the case of a clockwise rotation) or 2*pi (a full circle) minus the rotationAmount
if the rotation is counter-clockwise.
The constructor in step 7 illustrates how the parameters passed to a constructor can be forwarded to the class' parent constructor via the :base
specification. Since the GamePiece class has a constructor that accepts a piece type, we can pass that information along to its constructor while using the second parameter (clockwise) to update the clockwise member that does not exist in the GamePiece class. In this case, since both the clockwise member and the clockwise parameter have identical names, we specify this.clockwise
to refer to the clockwise member of the RotatingPiece class. Simply clockwise
in this scope refers only to the parameter passed to the constructor.
Tip
this notation
You can see that it is perfectly valid C# code to have method parameter names that match the names of class variables, thus potentially hiding the class variables from being used in the method (since referring to the name inside the method will be assumed to refer to the parameter). To ensure that you can always access your class variables even when a parameter name conflicts, you can preface the variable name with this.
when referring to the class variable. this.
indicates to C# that the variable you want to use is part of the class, and not a local method parameter.
Lastly, the UpdatePiece()
method simply increases the rotationAmount
member while decreasing the rotationTicksRemaining
counter (using MathHelper.Max()
to ensure that the value does not fall below zero).