Pre-requisite: it is assumed
that you have read through
the prior tutorials, and are familiar with the concepts covered in those
tutorials.
It may be useful to refer to refer to
the diagram illustrating the Draw-Update loop
(which explains that your
initialization code will be called once, and then the XNACS1Lib will repeatedly call your Update method
(after which it will Draw the screen) ), in order to have a clear picture of how your game executes.
Goals:
In this tutorial, we will:
Examine how to work with a rectangle via the
XNACS1Lib
library
1. Obtain the example code
Here is the
zip file
to the source
files and compiled executable of this example.
Download and unzip the zip file and you will see an
ExampleProgram
folder. Open the
ExampleProgram
folder, the
EXE
folder contains the compiled program and you can double click on the
.sln
file to work with the source code.
Once we compile and run this project, the program displays "
Rectangle
Center at {X:40 Y:30}
" at the top of the screen, and "
Rectangle
Lower-Left Corner at: {X:20 Y:20}
" at the bottom of the screen, along
with a rectangle near the middle of the window. The rectangle is labeled
with it's width and height, like so:
Other than exiting when the player presses the 'Back' button (or the keyboard
equivalent), the program does not respond to user input.
2. Background
:
The tutorials that follow this one will begin to make
greater use of the graphical capabilities of XNACS1Lib. The goal of this tutorial is to show you the
basics of drawing a Rectangle on-screen so that in future tutorials you can
focus on other topics in computer programming, without having to simultaneously
learn about graphics.
3. Examining The Program:
Let's examine the
C# source code that produces the behavior we see on-screen
Declaring the instance variables
public
class Game1 :
XNACS1Base
{
private
XNACS1Rectangle
MyRectangle;
// A
Rectangle
Since we want the rectangle to exist throughout our program, we'll
declare the rectangle as an
instance variable
.
Since we want to have access to the rectangle, we'll need to declare a reference to
a rectangle
object
. We do this with the line
private
XNACS1Rectangle
MyRectangle;
.
As discussed in the tutorial on instance variables, the word
private
is
basically boilerplate text, the word
MyRectangle
is the name that we've
chosen to give the rectangle, and the semi-colon at the end is required by C#.
What's new is the word
XNACS1Rectangle
. As you
might guess from the '
XNACS1
'
part of the word, this type of rectangle is not a normal rectangle that's
built into basic XNA, but instead is a new, enhanced, and easier-to-use
rectangle built into the XNACS1Lib library. The XNACS1Lib is already
included in the project that you can download for this tutorial.
In this particular program, the rectangle will never change, but in most
games, it normally would be changed. So even though we could get away
with declaring
MyRectangle
to be a
local variable inside, say, the Update method, we have decided instead to make
it into an instance variable. Again, we're setting things up so you
will be familiar with how things are normally done, even if there's a
slightly better approach that could have been used in this particular,
contrived example.
For now, we're just going to
use
the rectangle, and not worry
about to
create
our own types of objects (creating multiple objects,
and the multiple classes that define them, are at the core of
object-oriented programming, and will be left till later).
InitializeWorld():
We told C# to create instance variables for our Game1. It's
important that we give our variables well-defined values before we use them,
like so:
protected
override
void
InitializeWorld()
{
World.SetWorldCoordinate(
new
Vector2
(0,0),
100.0f);
// Initialize Rectangle
MyRectangle =
new
XNACS1Rectangle
();
MyRectangle.LowerLeft =
new
Vector2
(20.0f,
20.0f);
The first thing that InitializeWorld does is to call SetWorldCoordinate
using the same parameters that we used in prior tutorials, since we want the
lower-left corner to still be at (0,0), and since we want the width of the
window to be 100 units wide:
SetWorldCoordinate(
new
Vector2
(0,0),
100.0f);
At this point you've seen this line of code several times, so unless we
use different coordinates for the window, we will not mention this line of
source code again in these tutorials.
Much like in the previous tutorial on instance variables, we will first
initialize the rectangle, before we use it. However, you'll notice
that unlike initializing the
float
s
,
there is an extra step here:
MyRectangle =
new
XNACS1Rectangle
();
For now, it's enough to simply memorize that all the new data types that
you'll see in the XNACS1Lib will need two steps to use them:
Declare a variable of the right type (for example, the instance
variable
private
XNACS1Rectangle
MyRectangle;
)
Create a new object of the right type (for example,
MyRectangle =
new
XNACS1Rectangle
();
in the InitializeWorld method)
In case you're curious, where's what's going on: Data types in C# can be
divided into 2 broad categories:
value types
, and
reference types
.
A value type is any variable holds a value directly. A
float
is a value
type because
float
variables holds a single, floating point number itself. A
Vector2
is a value type because
Vector2
variables directly holds a pair of
float
s - one to
store the
X
value, and one to store the
Y
value.
(Technically, value types can be further subdivided into
simple types
,
like
float
s, and
regular,
struct
, value types, like
Vector2
s). With a
reference type
, on the other
hand, the variable does NOT store a value directly. Instead, the
variable holds a
reference
to an object. This will
actually be really handy later on, but for right now, we just need to
remember that for a reference type, we need to go through two steps, rather
than just one: (1) declare the variable, and (2) create a
new
object to use. Given the following code (which,
technically, creates 3 local variables):
float
aNumber;
aNumber = 3.14f;
Vector2
aPoint;
aPoint.X = 3f;
aPoint.Y = 2f;
XNACS1Rectangle
aRectangle;
aRectangle =
new
XNACS1Rectangle
();
Here is a picture of what the computer's memory would look like after
the above code has run:
The key point to note is that the
value types
store their values
(essentially) directly inside the variable, while a variable for a
reference type
actually contains a memory reference (a reference to a
different location in memory) to the actual object, which is located
elsewhere in memory.
You may be asking yourself "Based on what was just explained, it's
really important that I remember to create a
new
XNACS1Rectangle
object.
But in that prior tutorial, why did we use
new
with the
Vector2?" We're going to omit a detailed discussion, but instead
just tell you that with reference types, you
have
to use
new
, but with value
types, you have the
option
of using
new
.
Having created a 'blank' rectangle (one that is composed of a number of
different properties (a.k.a. data fields), each of which has the default
value (this is why there are all those zero's in the rectangle object in the
above picture)), we need to go on to initialize each of the different
properties.
MyRectangle.LowerLeft =
new
Vector2
(20.0f,
20.0f);
By setting the LowerLeft property, you set location of the
bottom-left corner of the rectangle. Notice that since since the
location of that corner is a point, we can conveniently set that location by
creating and initializing a temporary
Vector2
variable:
MyRectangle.LowerLeft =
new
Vector2
(20.0f,
20.0f);
and then copying an entire
Vector2
directly into the LowerLeft property:
MyRectangle.LowerLeft =
new Vector2
(20.0f,
20.0f);
Notice that this is a great example of
using
new
to initialize (but not
create) a value type - the Vector2 the represents the lower-left corner of
the rectangle.
MyRectangle.Width = 40.0f;
MyRectangle.Height = 20.0f;
Once we have positioned the rectangle, we then need to tell the
rectangle how wide, and how high, it should be. We do that by
assigning floating point numbers to the Width and Height properties, as
demonstrated above.
Lastly, we set the message that we want
to display on the rectangle. You'll notice that we use the same
approach here, that we used with the EchoToTopStatusBar message: we have
textual messages that we enclose in double-quotes, concatenated with numbers
using the + symbol.
Unlike the EchoToTopStatus command, here we do not put the message
inside parentheses. Instead, we assign the message to the Label
property, which tells the rectangle to remember the message until it's time
to draw itself.
One quick note: Since the output never changes, we never need to (re)adjust
anything after we've initialized it. So for this tutorial, it is
sufficient to initialize everything, and then let the XNACS1Lib take care of drawing the
rectangle for us.
UpdateWorld():
At this stage, we'll make use of the UpdateWorld
method in order to have our Update step actually do something.
protected
override
void
UpdateWorld()
{
if
(GamePad.ButtonBackClicked())
this
.Exit();
EchoToTopStatus(
"Rectangle
Center at:"
+ MyRectangle.Center);
Since we don't want to change anything, we don't need to update
anything.
Notice the rectangle is drawn automatically! This is true for all both
rectangle and circles, that once created, they will be drawn automatically
in the specified positions.
Notice that
our UpdateWorld never actually changes the rectangle in any way.
FURTHER EXERCISES::
Start from a blank starter project (1000.201, if you need it), and re-do
the code from memory as much as possible. On your first try, do what
you can, and keep the above code open so that when you get stuck, you can
quickly look up what you forgot (and that after you finish a line, so that
you can compare your line to the 'correct' line). On the next try, do
the same thing, but try to use the finished code less. Repeat this
until you can type everything, without referring the tutorial's code.
Repeat this exercise daily for several days, so that you really get the
hang of this. As you go on, periodically review this by re-doing this
exercise.
Understanding the program: Object Creation
As a starting point, use the project from the above tutorial. Try removing the line that creates the rectangle object, and see what
error message it generates. One way to do this would be to comment
this line out:
MyRectangle =
new
XNACS1Rectangle
();
Make sure that you remember this error message, because it's a very
distinctive error message - it (basically) only happens when you've
forgotten to create an object. Also make sure that you
remember whether this error occurred at compile-time, or when the
program was running.
Understanding the program before you code
By hand, calculate the location of the center of the rectangle, for each of
the following situations. Note: the center is the point that is
halfway up the rectangle, and halfway across the rectangle.
the LowerLeft corner is set to (20, 20), and the width of the rectangle
is 20, and the height is 20
the LowerLeft corner is set to (20, 20), and the width of the rectangle
is 100, and the height is 17
the LowerLeft corner is set to (-5, -5), and the width of the rectangle
is 10, and the height is 10
Understanding the program before you code
By hand, calculate the location of the LowerLeft corners of each of the
following rectangles, given their centers, widths, and heights.
Center = (20,20), width = 10, height = 10
Center = (50,20), width = 25, height = 7
Center = (-2, 20), width = 20, height = 2
Using rectangles on your own: positioning and sizing a rectangles
Start this exercise using
Exercise_
5
's starter project
,
which is a nearly identical copy of the project that was used in the above
tutorial.
Change the program so that your program looks like the following picture
(details of where stuff needs to go is listed after the picture)
The rectangle's lower left corner is now at (30,35), the rectangle's
width is now 60, and the rectangle's height is now 10
The rectangle's label should be set to "Rectangle with Width=60
Height=10"
Using rectangles on your own: positioning and sizing a rectangles
Start this exercise using
Exercise_
6
's starter project
,
which is a nearly identical copy of the project that was used in the above
tutorial.
Change the program so that your program looks like the following picture
(details of where stuff needs to go is listed after the picture)
The rectangle is now flush with the bottom and left edges of the screen.
The rectangle's width is now 55, and the rectangle's height is now 15
The rectangle's label should be set "Rectangle with Width=55
Height=15"
Using rectangles on your own: positioning and sizing a rectangles
Start this exercise using
Exercise_
7
's starter project
,
which is a nearly identical copy of the project that was used in the above
tutorial.
Change the program so that your program looks like the following picture
(details of where stuff needs to go is listed after the picture)
The rectangle is now flush with the bottom and right edges of the
screen. The rectangle's width is now 45, and the rectangle's height is
now 27
The rectangle's label should be set "Rectangle with Width=45
Height=27"
Using rectangles on your own: coloring a rectangle
Start this exercise using
Exercise_
8
's starter project
,
which is a nearly identical copy of the project that was used in the above
tutorial.
Change the program so that your program looks like the following picture
(details of where stuff needs to go is listed after the picture)
The rectangle is in the same place as in the tutorial, and has the same
width and height.
The rectangle's label should be set "Rectangle with Width=40
Height=20"
In order to get the same colors as used in the picture, you can use the
following code, in the InitializeWorld method (putting this after the line
that assigns the label is good)
MyRectangle.CenterColor =
Color
.Black;
MyRectangle.OutsideColor =
Color
.Chartreuse;
MyRectangle.LabelColor =
Color
.Blue;
For this exercise, you must choose new colors for the center color of the
rectangle, the outside color of the rectangle, and the color of the label.
Choose whatever you want. You can do this most easily in (at least)
two ways:
Go to the line
MyRectangle.CenterColor
=
Color
.Black;
,
and delete the
.
Black
.
Don't forget to delete the period!! Then type in ., and let IntelliSence
offer you a lot of choices.