November 28
Lesson 9: Improving the BouncingBall Class Using Properties
Lesson 9 starts with the code as it was at the end of Lesson 8.
Source code after the Lesson 9 changes: http://www.bluerosegames.com/brg/XnaLesson9.zip
IMPORTANT NOTE: As I was writing this lesson and doing some research on the topic, it seems I've stepped into a bit of a hornet's nest on this one. There are some fairly heated debates in the C# community about the the benefits and drawbacks of using Properties, so as you can see, I struck out the first sentence in the lesson, and I'll replace it with "Using Properties may make sense depending on the specific needs of the class".
In C# programming, it is considered a best practice to not provide direct access to member variables of a class to other objects. C# provides a nice alternative to accessing Fields directly from outside the class using something called Properties which are more like a method call, but look to other objects like public Fields.
The benefits of Properties over direct access to Fields include but are not limited to:
- Sanity checks, the object can check if a value is valid before it accepts the change.
- Ability to combine Field values to make things easier for the calling object.
- The underlying structure of the data can be changed without requiring changes to the calling object.
- Properites can be made read only or write only.
- Easier to accomodate future needs of the class.
There are also some more advanced benefits having to do with packaging a class library as an assembly and maintaining compatability across versions.
In the case of the BouncingBall class, there are 2 public Fields that we will convert to Properties. Here is a sample property definition which can replace the previously public Field Position:
private Vector2 _position;
public Vector2 Position
{
get { return _position; }
set { _position = value; }
}
Notice the "get" and "set" blocks. If you remove the "set" block, the property would be read only. Likewise, if you remove the "get" block, the property would be write only. Since _position is declared private, other objects will not be able to access the value of _position directly, only through the property Position. Go ahead and replace the declaration of Velocity as follows:
private Vector2 _velocity;
public Vector2 Velocity
{
get { return _velocity; }
set { _velocity = value; }
}
In the "set" block, notice that there is a reference to a field named value. This is a special keyword that is used when setting a property and always contains the value that is being assigned to the property. It has the same data type as the property definition, or in this case, Vector2. So in the case of the BouncingBall class, if we had the following line in our Game1 class:
ball2.Velocity = new Vector2(10, 5);
then in the Propery setter for Velocity, "value" would contain a Vector2 object with X of 10 and Y of 5.
In most classes, the methods of the class will probably deal directly with the private Fields instead of going through the property logic, although in some cases it will make sense to access the data through the Properties as well, if some of the same reasons listed above apply to these values. In the BouncingBall class, it probably makes sense to access the Fields directly from inside the class, so in the Update method and the constructor, change all references to the properties to the Field names instead.
So change the BouncingBall.Update() method to use the private Fields instead of the public Properties:
public void Update()
{
// TODO: Add the BouncingBall update logic here
_position = _position + _velocity;
if (_position.X < 0 || _position.X > GraphicsViewport.Width - Texture.Width)
{
// If we get in here, we've hit a vertical wall
_velocity.X = -_velocity.X;
_position.X = _position.X + Velocity.X;
}
if (_position.Y < 0 || _position.Y > GraphicsViewport.Height - Texture.Height)
{
// If we get in here, we've hit a horizontal wall
_velocity.Y = -_velocity.Y;
_position.Y = _position.Y + _velocity.Y;
}
}
So run the program again, and it should behave exactly as it did before the changes.
So it's really up to you and up to the situation. Use Properties if they help you with whatever you're trying to accomplish. In most cases, you can change a Field to a Property later if you need to.