XNA 2D Game Tutorial (Part 1)

Transcription

XNA 2D Game Tutorial (Part 1)
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 1)
I like creating games. In fact, thatʼs what drew me into the computer world back in 1983. Itʼs amazingly satisfying seeing
one of your creations looking like itʼs alive, making decisions and reacting to the playerʼs actions. Back then I used to
create games for the legendary Commodore 64, with itʼs 64KB of RAM (of which about 39K was free for the
programmer), 1MHz 6510 CPU (yes, 1 mega-hertz!), its video chip (VIC) that supported 8 hardware sprites (more on
that in a bit) and its sound chip (SID) that supported 3 independent voices including white noise. It was a mean gaming
machine for its time, leaving computers such as Apple II and ZX Spectrum eating dust.
Days and years went by… the PC took over all other machines, mainly because of its open architecture. Now fast
forward to 2010. We have monstrous CPUs and GPUs, the latter capable of handling many graphic tasks that used to
be handled by CPUs alone.
There are many libraries and frameworks for writing games these days. Most of them are capable graphic engines,
written in C++ for C++ consumption. There are others, however. One of them is the Microsoft XNA framework, born a
few years back and now in itʼs 4th major version. This framework allows programming games in .NET, targeting the PC,
XBox 360, Zune (up until version 3.1) and now the Windows Phone 7, all with high source code compatibility.
Although Windows Phone 7 is the big hype at the moment, I want to present a tutorial that uses the plain old PC as the
gaming platform. Changing it to WP7 or XBOX is not too difficult and maybe Iʼll tackle that in the last part of this series.
Note that there are plenty of tutorials out there… but this is mine.
Getting started
To get started, youʼll need Visual Studio 2010 (any edition, including Express), XNA Game Studio 4, and (if you want to
develop for Windows Phone 7) the tools for Windows Phone 7. All these are free downloads (VS 2010 express version
only), so go ahead and download and install the bits.
Open VS 2010 and select File->New Project. In the new project dialog box, navigate to Visual C#. You should see a
sub-node named XNA Game Studio 4.0. Select the Windows Game (4.0) option in the right side and enter a name for
the project. Weʼll call it AlienRaid and it will be a pretty classic shooter, that will allow me to show XNA stuff, while
walking in familiar territory. This will be a 2D game (I may tackle 3D in a later time) – donʼt underestimate 2D – we can
create fun games with whatever technology or game type!
The complete game will look something like this:
1/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
The dialog box should look something like this:
Click OK.
Youʼll see 2 projects created, named “AlienRaid” and “AlienRaidContent”. Weʼll get to the reason for the two projects
later. The main project hosts the Game1.cs fi le. For now, just press F5 or Ctrl+F5 to run the game. If everything is
setup ok you should see something like this:
2/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
Not an amazing game yet, but itʼs a start!
Notice that the mouse cursor disappears when hovering over the window. Close the window using the X button or press
Alt+F4.
Letʼs explore some of the code generated by the wizard. The Game1.cs class hosts a Game1 class inheriting from the
XNA Game class. This is the main class of any XNA game. A single instance of it is created in the Main method (look at
program.cs):
static void Main(string[] args) {
using(Game1 game = new Game1()) {
game.Run();
}
}
The Run method only returns when the game exits.
First, weʼll do some simple refactoring and change the name of the game class to something more appropriate. In the
Solution Explorer, rename Game1.cs to AlienRaidGame.cs. This will also change the class name from Game1 to
AlienRaidGame.
Every game must have a game loop. A game loop is some code thatʼs run over and over again, each and every frame
at some frame rate. XNA uses 60 frames per second (FPS) by default. That means the game loop runs every 16.66667
milliseconds. Where is the game loop located? Thatʼs the two methods named Update and Draw of the game class.
First, letʼs look at Draw:
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
3/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
Right now, it doesnʼt do very much. The first instruction simply clears the drawing buffer to some color (thatʼs the color
in the previous snapshot). If we are to create a space shooter, we probably want a black background, so letʼs change
the color to black:
GraphicsDevice.Clear(Color.Black);
Run the game and note the black background.
Generally, the Draw method is the placing all drawing code thatʼs needed to render the scene. This means the playerʼs
ship, the alien enemies, the score, the various projectiles – everything must be drawn somewhere within this method.
And itʼs all drawn 60 times a second! This is how a game works. A game is never idle. Itʼs always doing something.
We still havenʼt drawn anything... weʼll do that in part 2.
Letʼs examine the Update method:
protected override void Update(GameTime gameTime) {
// Allows the game to exit
if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
The first thing happening is the checking of the XBOX game pad for a Back button press, and if pressed, the game
exist by calling the Game.Exit method. Since weʼre using the PC, we may not have a game pad available, letʼs add
code that exits the game when the ESC key is pressed. We can replace the existing code or simply add to it, so that
both options are available.
To accomplish this, weʼll use the Keyboard.GetState static method, that will allow us to examine the state of any key
we desire:
if(Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
The code tests to see if ESC is pressed and if so, calls the Exit method. Nothing to it!
What is that GameTime object weʼre getting in Update and Draw? This object has two uses: the first, it indicates how
much time has passed since the last call (to Update or Draw) in the ElapsedGameTime property (of type TimeSpan).
These allows for timing thing more accurately, regardless of the actual frame rate. Weʼll see examples of this in a later
part. The second use is the IsRunningSlowly property. If true, it indicates XNA canʼt keep up with the desired frame
rate, so it may call Update more times (and not call Draw) to compensate. This is an advanced property and we wonʼt
deal with it now. In a typical 2D game, it should be rare to get to a slowly running game, and even if we do get there, itʼs
usually very temporary.
In the next part weʼll start drawing something. Until then, the resulting project is attached.
AlienRaid.zip
Published Nov 01 2010, 10:30 AM by pavely
4/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
‫תגים‬:.NET, XNA, DEV, Fun, Graphics, VS 2010, .NET 4, Tutorial
Comments
Madara said:
when you'll post Part 2? thanks
November 1, 2010 8:27 PM
Pavel's Blog said:
Previous posts in this series: Part 1 , Part 2 , Part 3 . Our sprite ship is moving with the help of
November 6, 2010 12:06 AM
Pavel's Blog said:
Previous parts in this series: Part 1 (Getting Started), Part 2 (Showing Something), Part 3 (Input
Handling
November 7, 2010 10:17 PM
Pavel's Blog said:
Previous parts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 9, 2010 1:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
MVP published 11 part XNA 2d tutorial « Ruari's Chaos said:
Pingback from MVP published 11 part XNA 2d tutorial « Ruari's Chaos
November 25, 2010 10:29 AM
5/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 1) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/01/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 5, 2010 3:55 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
6/6
2011/4/29 上午12:20
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 2)
In the fi rst partwe just created a black window. Itʼs time to see something more interesting.
The first thing weʼll do is change the window size. The window size is important for practical purposes – all our sprites
(soon to be drawn) need to be with a good relative size, the space for movement must be sufficient, etc. The other
thing is full screen mode. In a typical game, immersion is the keyword. To immerse the player inside the game, she
should not see the taskbar, messenger popping up, etc. The game needs to run full screen. For debugging and
development purposes, however, weʼll run the game windowed.
So, how do we set the window size, and whether we want a full screen game? Simple, set some properties in the game
constructor:
graphics.PreferredBackBufferHeight = 600;
graphics.PreferredBackBufferWidth = 800;
graphics.IsFullScreen = false;
Window.Title = "Alien Raid Demo Game";
This should suffice. The game will run at a resolution of 800x600, windowed (for now). I also set the Window title to
something more appropriate.
Drawing Sprites
The term “sprite” is pretty old, dating back to the golden era of personal computers during the 80s. As I mentioned in
the first part, the Commodore 64 had 8 hardware sprites. What this meant was, that I could set their shape (which need
not be rectangular and could have transparent areas), set their position and not worry that a sprite will disturb the text,
graphics or other sprites while moving. There was no need to “delete” it from its previous location when moving. All this
was incredibly useful back in those days.
There are no sprites today in the way it was back then. But we donʼt actually need that same support. CPUs and GPUs
are so powerful, that the typical game redraws its graphics from an empty window each and every frame. So, no need
to worry about “deleting” old images. Transparency support is also inherent and does not require anything special,
except preparing the images with transparent regions (weʼll see how to do that in a moment).
The Playerʼs Space Ship
Our game hero controls a spaceship that will battle the evil aliens. To draw the ship, we first need to add it as an asset,
or content, to the game. Then, weʼll load it in code and draw it.
The playerʼs ship will have (for now) a single image. You can download it here.
1/6
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
The AlienRaidContent project will hold all our game assets (images, audio files, fonts, etc.). First, right click the project
and select Add –> New Folder. Name it Images. Then right click the newly created folder and select Add –> Existing
item. Navigate to the location where you saved the ship.png file and select it.
Images in XNA are represented by the Texture2D class. Weʼll need to load the image into a Texture2D object and then
we can move on to drawing.
Add a private field to the game class named _playerShip of type Texture2D. Loading content is done in the
LoadContent method of the game class. Currently it has code that creates a SpriteBatch, which weʼll need soon
enough for drawing. Add the following code to LoadContent:
_playerShip = Content.Load<Texture2D>("Images/ship");
Note that when building the project, the ship.png fi le turns into aship.xnb fi le. XNB is XNAʼs internal format for game
assets (all assets turn into XNBs). Note also that you donʼt specify the extension of the asset name (in this example,
just “ship”).
The ContentManager.Load<> generic method just used can be (and will be) used for other assets as well.
Now that we have an image, we can draw it. Drawing images (effectively sprites) is done inside the gameʼs Draw
method using a SpriteBatch. A SpriteBatch is a kind of manager for drawing a series of sprites. It can set some default
behaviors for all drawing operations within it. Add the following code to the Draw method, after the call to Clear:
spriteBatch.Begin();
spriteBatch.Draw(_playerShip, new Vector2(400, 500), Color.White);
spriteBatch.End();
The spriteBatch instance was created in the LoadContent method by the VS 2010 wizard.
Running the game produces this output (clipped):
A call must be made to Begin, followed by calls to Draw (as many as needed) and finally a call to End sends drawing
instructions to the graphic card (not exactly, but conceptually true).
The SpriteBatch.Draw has 7 overloads. In the previous snippet, Iʼve used the simplest possible overload, supplying
the texture to draw, the position to draw at (by default, the position of the upper-left corner of the texture) and
something curious of type Color.
Color is the type that represents a color, with Red/Green/Blue components (RGB) and an Alpha component
(transparency, more on that in a later part). So, what does a Color parameter has to do in here? I mean, the image has
its colors, why should we supply any color at all? And why did I supply a White color (where R=G=B=255, the
maximum)?
2/6
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
The color parameter is a kind of filter. For example, if I change the color to Color.Red (meaning R=255,G=0,B=0), this
what we get:
That means the red component went through, while green and blue where filtered out. Letʼs try Color.Green:
This time the green component is the sole survivor. Letʼs try something like new Color(128, 255, 92):
We get a mixture: red component passes through with about half power (128/255), green is fully existing, and blue
passes with 96/255 power.
Overall, this parameter allows us to customize each and every drawing for some special effect. Weʼll use that in later
parts. For now, reverting to Color.White preserves the original image.
What about transparency? The ship is clearly non-rectangular, but the ship image is. How can we specify transparent
areas? There are two ways. The first is to use an image format that is capable of carrying transparency information,
e.g. PNG. Our ship is indeed a PNG file, but the PNG file was drawn in a way that paints the relevant pictures with
transparent pixels. This can be done with appropriate software, for example the free Paint.NET. Note that MS paint
cannot handle transparency, so saving a PNG through paint will always be opaque.
The other way to make transparent pixels is to paint them with the “special” color whose R=255,G=0,B=255 (a kind of
appalling pink). This color was selected because itʼs highly unlikely youʼd want it in a normal image… so any supported
format (BMP, JPG, etc.) that uses this color will be considered transparent for transparency purposes.
Weʼll talk about the other variations of SpriteBatch.Draw in later parts.
This wraps up the second part. Enjoy your sprites!
AlienRaid2.zip
Published Nov 02 2010, 12:18 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics
3/6
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
Comments
Pavel's Blog said:
Previous posts in this series: Part 1 , Part 2 , Part 3 . Our sprite ship is moving with the help of
November 6, 2010 12:06 AM
Pavel's Blog said:
Previous parts in this series: Part 1 (Getting Started), Part 2 (Showing Something), Part 3 (Input
Handling
November 7, 2010 10:17 PM
Pavel's Blog said:
Previous parts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 9, 2010 1:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Kit said:
I just started following along on your tutorial. You might want to note that a Content project is created
(from Part 1), and that the Images folder needs to be added to the content project, not the main one in
the solution. This tutorial is a great way to quick-start. Thanks!
November 22, 2010 6:04 AM
MVP published 11 part XNA 2d tutorial « Ruari's Chaos said:
Pingback from MVP published 11 part XNA 2d tutorial &laquo; Ruari&#039;s Chaos
November 25, 2010 10:29 AM
4/6
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 5, 2010 3:55 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Koto said:
Excellent tut man, I'm eager to read next ones!
December 23, 2010 10:28 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
5/6
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 2) - Pavel's Blog
6/6
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/02/xna-2d-...
2011/4/29 上午12:21
XNA 2D Game Tutorial (Part 3) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/04/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 3)
In part 2 we finally saw something other than a black window. Our ship sprite is just standing there: pretty boring. We
want to move it a bit – perhaps using the arrow keys, so that the player has some control over her ship.
XNA supports several input devices: the keyboard, the mouse and the game pad (usually with the XBOX). Accessing
all those devices is pretty straightforward and surprisingly similar. Weʼll use the keyboard in our game.
To access the keyboard, we call the Keyboard.GetState static method, getting back a KeyboardState structure. This
structure holds some simple methods, IsKeyDown and IsKeyUp that we can leverage.
letʼs set up for moving the playerʼs ship right and left. First, weʼll replace the hard-coded ship position with a variable of
type Vector2. Weʼll manipulate that variable when the right or left keys are pressed. Querying the keyboard state and
manipulating the position is done inside the Update method (remember, anything that is not a drawing operation
belongs in Update). Hereʼs the updated Update method:
protected override void Update(GameTime gameTime) {
// Allows the game to exit
if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
KeyboardState ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Escape))
Exit();
if(ks.IsKeyDown(Keys.Right))
_pos.X += 5;
else if(ks.IsKeyDown(Keys.Left))
_pos.X -­‐= 5;
base.Update(gameTime);
}
Letʼs update the Draw method to use the new Vector2 object named _pos:
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.Draw(_playerShip, _pos, Color.White);
1/4
2011/4/29 上午12:22
XNA 2D Game Tutorial (Part 3) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/04/xna-2d-...
spriteBatch.End();
base.Draw(gameTime);
}
Every press of the right or left key moves the ship 5 pixels. Moving far to the right or to the left makes the ship
disappear. No bounds checking is performed by XNA – itʼs up to you to check and act appropriately if needed. Hereʼs
some code that bounds the ship to the right and left edges of the window:
if(_pos.X < 0) _pos.X = 0;
else if(_pos.X > Window.ClientBounds.Width -­‐ _playerShip.Width)
_pos.X = Window.ClientBounds.Width -­‐ _playerShip.Width;
This code is a bit awkward to write. Saving the width of the window in a field would be better (and faster, too, as weʼre
accessing two properties to get to the Width; very expensive in game terms). Note that the code assumes the position
is of the top-left corner of the sprite. Weʼll see how we can change that in a moment.
More on SpriteBatch.Draw
As we saw in part 2, there are several overloads to SpriteBatch.Draw. Up until now, we used the simplest – just specify
the texture, position and the “color”.
A more interesting overload allows scaling the sprite, rotating the sprite and setting a different origin (as opposed to 0,0
– the top-left corner).
Letʼs first make the sprite bigger – it seems too small for our selected resolution of 800x600. Weʼll change the Draw call
to the following:
spriteBatch.Draw(_playerShip, _pos, null, Color.White, 0, Vector2.Zero, 2, SpriteEffects.None,
0);
The null parameter indicates a Rectangle (Nullable<Rectangle> or Rectangle? to be precise) that we can use as a
source inside the texture. This means we can have a large image and only extract a part of it. In this example, the
entire image is the ship, so null indicates the entire image texture. The zero after the color indicates the rotation angle
(in radians). Here we specify no rotation. This is quite handy, and can save us the trouble of pre-rotating an image to
various angles – we can simply specify the angle and be done with it. Note that the rotation point is the next parameter
indicating where any positioning or rotation originates. in this example, its Vector2.Zero or simply X and Y of zero (this
is the default). if we specify something like new Vector2(_playerShip.Width / 2, _playerShip.Height / 2), that would
make the center point of the ship as the (0,0). This affects the position setting and the rotation point.
The next argument is the scaling factor – here I specify 2. This means the sprite will be drawn at twice its width and
height. Note that this disrupts our bound checking code and we need to change that:
if(_pos.X < 0) _pos.X = 0;
else if(_pos.X > Window.ClientBounds.Width -­‐ _playerShip.Width * 2)
_pos.X = Window.ClientBounds.Width -­‐ _playerShip.Width * 2;
Note the multiplication by 2 factor. This is becoming really awkward – and begs some refactoring – perhaps some
Sprite class that would take care of all those little details? Weʼll add something like this in a later part. For now, just be
2/4
2011/4/29 上午12:22
XNA 2D Game Tutorial (Part 3) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/04/xna-2d-...
aware of the nuances.
The next argument is a SpriteEffects. None does nothing (dah), but you can flip horizontally (FlipHorizontally) or
vertically (FlipVertically).
The last argument is a Z layer index. That means, sprites may be drawn in any order and their actual Z order will be
based on that parameter. The accepted range is 0.0 to 1.0, where 0.0 is in front and 1.0 is way back. The default is 0.0.
Weʼll see some usage of that in a later part.
Where are we?
We have a player-controlled sprite, with bounds checking. Whatʼs next? Perhaps some stars passing by, so we may
feel like weʼre actually moving. Thatʼs in the next part.
AlienRaid3.zip
Published Nov 04 2010, 08:59 AM by pavely
‫תגים‬:XNA, C#, DEV, .NET 4
Comments
KooKiz said:
I really like the trial and error approach of your XNA tutorial. I'm looking forward for reading the next parts
:)
November 4, 2010 10:46 AM
Pavel's Blog said:
Previous parts in this series: Part 1 (Getting Started), Part 2 (Showing Something), Part 3 (Input
Handling
November 7, 2010 10:17 PM
Pavel's Blog said:
Previous parts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 9, 2010 1:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
3/4
2011/4/29 上午12:22
XNA 2D Game Tutorial (Part 3) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/04/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
4/4
2011/4/29 上午12:22
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 4)
Previous posts in this series: Part 1, Part 2, Part 3.
Our sprite ship is moving with the help of the arrow keys. But it doesnʼt seem to be travelling through space. Perhaps
we should add some starts going by, as the ship travels forward at incredible speeds…
We could continue with the same basic idea we use with the playerʼs ship: Add appropriate variables, update stars
position in the Update method and draw them all in the Draw method. This will cause some bloating of Update and
Draw, not to mention the alien enemies weʼll add later, the bullets the player and the aliens fire, etc.
There must be a better way to segregate the different parts of the game, adding some control along the way. For
example, in the title screen that every game should have, you donʼt expect the enemy aliens swooping in, shooting the
player. In fact, the player ship should not be visible or controllable at that point. How can we achieve all that order and
control? Enter game components.
In XNA parlance, a game component is an object, whose class derives from GameComponent or
DrawableGameComponent. These components can be added or removed at will by using the Game.Components
property. Furthermore, each game component can be enabled or disabled (Enabled property). This is very handy, as
various game states require different participating components.
A GameComponent represents an entity with no drawable parts, and contains an Update method (very similar to the
Game.Update method, and in fact called by that base implementation). A DrawableGameComponent adds a Draw
method that is called by the Game.Draw base implementation. Also added is a Visible property, which allows control of
whether that DrawableGameComponentʼs Draw method should actually be called.
With these ideas in mind, letʼs add a starfield to the game as a component. This allows separating the main game class
from other game entities and allows further control of specific components.
To add a GameComponent quickly, right click the project and select Add –> New Item…. In the “Add New Item” dialog
box, navigate to “Visual C#” –> “XNA Game Studio 4.0”. Select Game Component and in the Name textbox, type
StarfieldComponent:
1/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
Click Add.
The created StarfieldComponent class derives from GameComponent. As the starfield clearly has to draw the stars,
weʼll change the base class to DrawableGameComponent. The class looks like this (all XML comments removed):
public class StarfieldComponent : DrawableGameComponent {
public StarfieldComponent(Game game)
: base(game) {
// TODO: Construct any child components here
}
public override void Initialize() {
// TODO: Add your initialization code here
base.Initialize();
}
public override void Update(GameTime gameTime) {
// TODO: Add your update code here
base.Update(gameTime);
}
}
To actually draw something, weʼll have to manage a bunch of stars, keeping track of their position. Also, weʼd want a
different color for each star (perhaps selected randomly). Letʼs create a simple Star class that will hold all that info:
2/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
class Star {
public Vector2 Position;
public float Speed;
public Color Color;
}
Note that I use public fields rather than properties. This may be a bit disturbing, as weʼre used to have properties (even
if they are auto-implemented) as an abstraction level that allows (perhaps later) adding validation rules, etc. But when
writing games, “cutting corners” is kind of allowed. Accessing a field will always be at least as fast as accessing a
property (depending on optimizations and other factors), and we want to get as much speed as we can. This may not
be too important for most 2D games (unless they have some complex AI logic or something), but still, itʼs good to keep
this in mind. We want performance. Little things can matter a lot.
Should the Star class be a value type (struct)? In this case, maybe it can. Weʼre going to create those stars upfront
anyway, so as to minimize the chance of garbage collection along the way. This is another very important point: XNA is
running on the .NET platform. This means, there is a garbage collector, and we donʼt to wake it up. One way to
minimize GC is to create everything we can upfront, so that during normal game play the GC would not have the need
to wake up. There is no sure way to avoid GC. There is XNA behind the scenes after all, and we are unaware of all that
itʼs doing. But we can at least play our part. Sometimes itʼs feasible to call GC.Collect explicitly where it may not be
problematic, such as when moving to the next game level.
Letʼs get back to the starfield. The StarfieldComponent should hold a collection or an array of Star objects and
configure them accordingly:
Star[] _stars = new Star[128];
Random _rnd = new Random();
public override void Initialize() {
for(int i = 0; i < _stars.Length; i++) {
Star star = new Star();
star.Color = new Color(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256), 128);
star.Position
=
new
Vector2(_rnd.Next(Game.Window.ClientBounds.Width),
_rnd.Next(Game.Window.ClientBounds.Height));
star.Speed = (float)_rnd.NextDouble() * 5 + 2;
_stars[i] = star;
}
base.Initialize();
}
The Initialize method is called automatically by the game object for all “registered” components. How do you add a
component to the game? User the Components propertyʼs Add method inside the game constructor:
Components.Add(new StarfieldComponent(this));
A GameComponent can always access the game object itself through the inherited Game property (you may need to
cast it to the actual game class).
Note that the starʼs color contains an alpha (transparency) component with the value 128 (half transparent). This will
help make the stars less pronounced, so they donʼt distract too much from the main entities (such as the playerʼs ship
3/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
and the aliens). The starʼs position and speed is selected at random, although a more “intelligent” choices could have
been made, this will suffice for now.
How do we move the stars? As anything that is not a direct drawing operation, this is done in the GameComponentʼs
overridden Update method:
public override void Update(GameTime gameTime) {
int height = Game.Window.ClientBounds.Height;
for(int i = 0; i < _stars.Length; i++) {
var star = _stars[i];
if((star.Position.Y += star.Speed) > height) {
// "generate" a new star
star.Position = new Vector2(_rnd.Next(Game.Window.ClientBounds.Width), -­‐_rnd.Next(20));
star.Speed = (float)_rnd.NextDouble() * 5 + 2;
star.Color = new Color(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256), 128);
}
}
base.Update(gameTime);
}
Each star is “moved” by its current speed in the Y direction (down the screen). if itʼs out of bounds, a “new” star is
generated by placing it in a random X position and somewhere above the visible area of the screen, selecting a new
random color and a new random speed.
Next up is drawing the stars. This must be done in the Draw override of the DrawableGameComponent. This method
needs to be added manually, as the wizard created a GameComponent-derived class that has no Draw method. First,
we need a star image, which I created by firing up Paint and drawing a 2 by 2 white square, saving it, and adding it to
the Images folder of the content project (just the way we did with the ship image).
Now we need to load it as a Texture2D object, prepare a SpriteBatch for drawing and then do the actual drawing.
Weʼll start by overriding another method named LoadContent, very similar in concept to the same method in the game
class:
protected override void LoadContent() {
_starTexture = Game.Content.Load<Texture2D>("Images/star");
_batch = new SpriteBatch(Game.GraphicsDevice);
base.LoadContent();
}
We load the texture and create a SpriteBatch for later use. We could theoretically use the SpriteBatch created by the
game class, but this gives us more freedom to initialize the SpriteBatch differently and independently (more on that in a
moment). The Draw method looks like this:
public override void Draw(GameTime gameTime) {
_batch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
foreach(var star in _stars)
_batch.Draw(_starTexture, star.Position, null, star.Color, 0, Vector2.Zero, 1.0f,
4/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
SpriteEffects.None, 1.0f);
_batch.End();
base.Draw(gameTime);
}
A few things to note here. A more complex SpriteBatch.Begin method overload is called. This allows selecting how
sprites are sorted (the Deferred value is actually the default), this is not that important at the moment. The second
value (of type BlendState) is more significant. The default value (in an empty Begin call is BlendState.AlphaBlend)
means that sprites are drawn considering their transparent areas (e.g. with PNG images or the areas colored with
RGB=(255,0,255)). In our case, no transparency is relevant for the stars, as they are opaque squares. However,
remember we set an alpha value of 128 to the color itself. We would like the stars to be semi-transparent as a whole.
With AlphaBlend.NonPremultiplied we can achieve that (try removing it and see what happens – the stars are much
more pronounced, a bit distracting).
Generally speaking, we can assemble other BlendState objects, but there are some predefined static fields in the
BlendState class that seldom require us to do so. This is also why we need a different SpriteBatch than the one used
in the game class for the playerʼs ship. And in any case, itʼs easier to just create a separate SpriteBatch in each
drawable component.
Run the game and watch the stars blaze through the empty space! We have stars! Cool.
In the next part, weʼll talk about animation and do some basic refactoring.
AlienRaid4.zip
Published Nov 06 2010, 12:06 AM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics
Comments
Pavel's Blog said:
Previous parts in this series: Part 1 (Getting Started), Part 2 (Showing Something), Part 3 (Input
Handling
November 7, 2010 10:17 PM
Pavel's Blog said:
Previous parts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 9, 2010 1:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
5/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
Eduardo said:
This document helped me out figuring out how to use the DrawableGameComponent. Thank you !
November 14, 2010 2:18 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
RealTime - Questions: "When did we start using zip codes? Area codes?" said:
Pingback from RealTime - Questions: "When did we start using zip codes? Area codes?"
November 30, 2010 7:57 AM
Koto said:
When I tried to add a component I right clicked the wrong (Content) project :), another excellent tut ...
December 23, 2010 11:13 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
6/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 4) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/06/xna-2d-...
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
7/7
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 5)
Previous parts in this series: Part 1 (Getting Started), Part 2 (Showing Something), Part 3 (Input Handling), Part 4
(Game Components).
What do we have at the moment? A ship we can control with keyboard and stars flying by, implemented as a
DrawableGameComponent for flexibility and modularity. Although the ship seems to move, itʼs still too static. Its
engines are not changing. What we want is some animation. Perhaps toggling between two images such that the
engine would seem to fluctuate?
Animation (in the 2D world, at least) means changing the shape of a sprite with respect to time or some other factor. In
this case, weʼll have two shapes for the ship that we would want to swap every so and so milliseconds. Hereʼs the new
playerʼs ship image (enlarged):
Changing the ship.png in the project to the above image and running produces something like this:
Not exactly what we were hoping for…
We want to show one image at a time. This requires some code modifications when drawing the playerʼs ship.
Currently, our drawing code for the ship looks like this:
spriteBatch.Draw(_playerShip, _pos, null, Color.White, 0, Vector2.Zero, 2, SpriteEffects.None,
0);
1/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
The null third parameter is the key to animation. The null means “use the entire image” – thatʼs where the “double ship”
effect comes from. if we change this to a Rectangle object that only uses the left half of the image, weʼll see a normal
image again:
spriteBatch.Draw(_playerShip, _pos, new Rectangle(0, 0, 15, 20), Color.White, 0, Vector2.Zero,
2, SpriteEffects.None, 0);
The 15 is half the width, as is evident when opening the file in some image editor. The 20 is the height of the image. All
we have to do now is keep track of the current frame (0 or 1) and change the rectangle accordingly. Letʼs add a simple
integer to the game class that would indicate the current frame:
int _currentFrame;
Now we can use the current frame to modify the displayed rectangle:
spriteBatch.Draw(_playerShip, _pos, new Rectangle(_currentFrame * 15, 0, 15, 20), Color.White,
0, Vector2.Zero, 2, SpriteEffects.None, 0);
Changing _currentFrame from 0 to 1 switches the active image. How do we make that switch? We need to toggle
_currentFrame from 0 to 1 and back after some period (say 0.5 seconds). To do that weʼll use a TimeSpan object that
will accumulate the elapsed time. If 0.5 second pass by, we'll make the switch. All this happens in the Update method:
if((_shipAnimElapsed += gameTime.ElapsedGameTime) > TimeSpan.FromMilliseconds(500)) {
_currentFrame = 1 -­‐ _currentFrame;
_shipAnimElapsed -­‐= TimeSpan.FromMilliseconds(500);
}
We use the GameTime.ElapsedGameTime property that indicates the elapsed time since the last call to Update
(should be a constant 16.666667 msec by default, but can vary because of slowdown or changes in the frame rate).
when half a second passes, we switch the current frame and subtract 0.5 seconds from our elapsed time counter. Now
we have proper animation!
Some Refactoring
This capability – animation – is probably useful for many sprites. It seems appropriate to factor all this out to a separate
Sprite class, that can animate along several frames, and can provide other services, such as drawing, position
updating, collision detection and more.
Letʼs create a new Sprite class. Right-click the project, and select Add –> Class. Name it Sprite:
2/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
Click Add.
We want our Sprite class to encapsulate as much common functionality as we can, so we can leverage it for the alien
enemies, the various projectiles, etc. Here are some basic attributes the Sprite class should hold:
public class Sprite {
public Texture2D Texture { get; private set; }
public Vector2 Position;
public Vector2 Velocity;
public Vector2 Origin;
public bool Active = true;
public float Scale = 1;
public float Rotation;
public float ZLayer;
public int TotalFrames { get; private set; }
public TimeSpan AnimationInterval;
The Texture property is the image from which the sprite is drawn. Position and Velocity are self evident – Velocity will
be added to Position on each update. Velocity can be zero if so desired.
Origin, Scale, Rotation and ZLayer, mimic the parameters to SpriteBatch.Draw that will be used in the Draw call.
Active is a simple boolean flag indicating whether the sprite is “alive”. This will help us a little later. TotalFrames
indicates the number of animation frames and AnimationInterval controls the animation speed.
Now for the constructor:
public Sprite(Texture2D texture, Rectangle? firstRect = null, int frames = 1, bool horizontal =
true, int space = 0) {
Texture = texture;
3/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
TotalFrames = frames;
if(firstRect != null) {
_rects = new Rectangle[frames];
Rectangle first = (Rectangle)firstRect;
for(int i = 0; i < frames; i++)
_rects[i] = new Rectangle(first.Left + (horizontal ? (first.Width + space) * i : 0),
first.Top + (horizontal ? 0 : (first.Height + space) * i), first.Width,
first.Height);
}
}
The only required parameter is the texture – without it there is nothing to draw. Note that there is no error handling at
this time – itʼs left as an exercise for the reader – I want to concentrate on the practical XNA stuff, not the things that are
always relevant.
The fi rstRectargument indicates the coordinates and sizes of the first frame within the image texture. If itʼs null, that
means the entire texture is the single frame. If not, we need to calculate the rectangles of the other frames. I wanted to
support frames laid out horizontally as well as vertically – thatʼs the horizontal argument. The space argument
indicates whether there is some space between frames in the texture. The rectangles are calculated accordingly, in
preparation for drawing.
Next up are the Update and Draw methods. Update should take care of the animation (if any) and move the sprite if
Velocity is non-zero:
public virtual void Update(GameTime gameTime) {
if(Active) {
if(TotalFrames > 1 && (_animElapsed += gameTime.ElapsedGameTime) > AnimationInterval) {
if(++_currentFrame == TotalFrames)
_currentFrame = 0;
_animElapsed -­‐= AnimationInterval;
}
Position += Velocity;
}
}
_animElapsed is of type TimeSpan and serves a similar purpose to the _shipAnimElapsed variable from the
previous code. Note that nothing happens if the sprite is not active.
The final piece of the puzzle (at this time) is the Draw method:
public virtual void Draw(GameTime gameTime, SpriteBatch batch) {
if(Active) {
batch.Draw(Texture, Position, _rects == null ? null : (Rectangle?)_rects[_currentFrame],
Color, Rotation, Origin, Scale, SpriteEffects.None, ZLayer);
}
}
It uses the various fields declared previously and a Color fi eld (initialized to Color.White) – changing this could be
beneficial for the starfield, for example. Notice the selection of the current rectangle frame based on the
_currentFrame field.
4/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
All thatʼs left to do right now is modify the game to use the new Sprite class instead of the manual drawing and
animating done previously:
Add a Sprite fi eld called _player to the game class. Remove the animation and frame related fi elds. In the Initial
ize
method, create the sprite:
protected override void Initialize() {
base.Initialize();
_player = new Sprite(_playerShip, new Rectangle(0, 0, 15, 20), 2);
_player.Position = new Vector2(400, 530);
_player.AnimationInterval = TimeSpan.FromMilliseconds(500);
_player.Scale = 2;
}
Modify the Update method to use the new sprite:
if(ks.IsKeyDown(Keys.Right))
_player.Position.X += 5;
else if(ks.IsKeyDown(Keys.Left))
_player.Position.X -­‐= 5;
if(_player.Position.X < 0) _player.Position.X = 0;
else if(_player.Position.X > Window.ClientBounds.Width -­‐ _player.FrameWidth * _player.Scale)
_player.Position.X = Window.ClientBounds.Width -­‐ _player.FrameWidth * _player.Scale;
_player.Update(gameTime);
FrameWidth is a helper properties that return the width of each frame:
public int FrameWidth { get { return _rects == null ? Texture.Width : _rects[0].Width; } }
There is room for some optimization here. Multiplying by the scale is not fun. Weʼll improve that later.
Now we need to change the Draw method to use our new sprite:
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
_player.Draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
And thatʼs about it! We have a decent Sprite class and weʼve converted the playerʼs ship to use it. We can do a similar
thing to the Star class, which is now obsolete. We can directly use the new Sprite class instead. Iʼll leave that as an
exercise for the reader. The attached ZIP replaces the Star with a Sprite.
AlienRaid5.zip
5/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
Published Nov 07 2010, 10:17 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics
Comments
Pavel's Blog said:
Previous parts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 9, 2010 1:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Chris said:
I'm missing something at this step. Initialize is called before LoadContent; therefore the Sprite is created
- with a null texture - and then the texture variable (_playerShip) has its content loaded (when it's too
late).
I could make the Sprite's Texture setter public and just set that during LoadContent, but that's probably
not the 'right' answer.
Can you tell me how you got the texture loaded before Initialize? Or am I missing something?
November 12, 2010 3:02 AM
Chris said:
Easiest fix seems to be just moving the Sprite initialization into LoadContent...
November 12, 2010 3:11 AM
pavely said:
Actually, the call to base.Initialize calls LoadContent, so the texture is not null.
November 12, 2010 7:14 AM
Chris said:
Ah - that was my problem then - I had the call to base.Initialize last. Thanks!!
November 13, 2010 3:25 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
6/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Zane said:
I am following your tutorials but using vs2008 and Xna 3.1. Everything has worked great but my ship is
not showing up. I think my code matches yours exactly and I have handle the difference between .net
4.0 and 3.1. Do you have any suggestion as to why the ship is not appearing.
December 9, 2010 5:24 AM
pavely said:
No. Please send me a ZIP of your project - I'll try to help.
December 9, 2010 6:13 AM
Koto said:
I had the same problem as Chris with Initialize called before LoadContent. I'll dig the msdn to find out the
exact usage of these methods.
I'm wondering why the Sprite is not derived from DrawableGameComponent ?
December 23, 2010 11:39 PM
pavely said:
Hi Koto,
Technically, you could derive Sprite from DrawableGameComponent, but that may hint that sprites
should be added to the Components collection of the Game class. I believe this is too much overhead
per sprite, as you may be dealing with dozens of sprites (such as the AliensComponent described at a
later post). It's easier to handle all sprites that share a common logic (such as aliens) and not add them
individually.
The other reason may have to do with what you actually gain by derivation. We want to keep the Sprite
class as small as possible.
December 24, 2010 10:51 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
7/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 5) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/07/xna-2d-...
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
8/8
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 6)
Previous parts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
In the previous part, we added animation capabilities to a general Sprite class. Our next step is to add firing capabilities
to the player.
The first thing weʼll do is move the player logic to its own component. This would make it flexible (allowing us to disable
it in a title screen, for example) and easier to maintain.
Add a new Game Component named PlayerComponent using the Add –> New Item context menu (as we did with the
starfield component). Change the base class to DrawableGameComponent, as the player clearly has something to
draw.
Letʼs move the keyboard input handling and all other player related logic to the new game componentʼs Update method
and the player drawing code to the Draw method of the component. This requires moving the playerʼs Sprite object to
the component as well:
public class PlayerComponent : DrawableGameComponent {
Texture2D _playerShip;
Sprite _player;
SpriteBatch _batch;
public PlayerComponent(Game game)
: base(game) {
}
public override void Initialize() {
base.Initialize();
_player = new Sprite(_playerShip, new Rectangle(0, 0, 15, 20), 2);
_player.Position = new Vector2(400, 530);
_player.AnimationInterval = TimeSpan.FromMilliseconds(500);
_player.Scale = 2;
1/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
}
protected override void LoadContent() {
base.LoadContent();
_playerShip = Game.Content.Load<Texture2D>("Images/ship");
_batch = new SpriteBatch(Game.GraphicsDevice);
}
public override void Update(GameTime gameTime) {
var ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Right))
_player.Position.X += 5;
else if(ks.IsKeyDown(Keys.Left))
_player.Position.X -­‐= 5;
if(_player.Position.X < 0) _player.Position.X = 0;
else if(_player.Position.X > Game.Window.ClientBounds.Width -­‐ _player.FrameWidth *
_player.Scale)
_player.Position.X = Game.Window.ClientBounds.Width -­‐ _player.FrameWidth *
_player.Scale;
_player.Update(gameTime);
base.Update(gameTime);
}
public override void Draw(GameTime gameTime) {
_batch.Begin();
_player.Draw(gameTime, _batch);
_batch.End();
base.Draw(gameTime);
}
}
All thatʼs left to do for this to work as before is add the new component to the game (in the game constructor):
Components.Add(new PlayerComponent(this));
This leaves us with the same functionality, but the player handling logic and drawing is separated into its own
component class.
The next feature I want to add is to allow the player to shoot some kind of projectiles or bullets. This will all be handled
in the PlayerComponent class, as itʼs the one responsible for all player capabilities, including firing bullets. I want to
allow several bullets to travel at the same time across the screen. In very old games only one bullet could be on the
screen at any one time, so the player had to wait (in case of a bullet miss) for the bullet to disappear from the screen
before he could fire again. This was usually done because of performance reasons (keeping track and drawing many
bullets is hard), but on todayʼs hardware thatʼs not an issue. So, for a fun game, weʼll allow more than one bullet at a
2/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
time, perhaps limiting firepower to some maximum rate. This rate can later be modified because of power ups, for
example. But weʼll get to that later.
Handling Projectiles
Projectiles, such as various bullets, cannon balls, lasers, etc. are handled much the same way as any sprite. The
difference is of control. These entities are started at a specific time (e.g. when pressing a certain key), but have “a life
of their own”. For the playerʼs projectiles weʼll create an array of sprites – preparing them up-front (so as to minimize
the chance of garbage collection during the actual game action), and selecting the first “available” bullet when the
space bar is pressed. Letʼs begin with adding some fields:
Texture2D _bulletTexture;
Sprite[] _bullets = new Sprite[16]; // assume no more than 16 active bullets
TimeSpan _minForBullet = TimeSpan.FromMilliseconds(400);
TimeSpan _totalForBulletElapsed;
int _lastBulletIndex;
_bulletTexture is the image for the bullet (added to the Images folder of the content project as usual). _bullets is the
array of sprites (to be initialized later) for a maximum of 16 concurrent bullets. Of course, we can change that number if
the need arises. _minForBullet is the minimum time between starting a new bullet. That is, this limits the firing rate.
_totalForBulletElapsed accumulates passing game time and when itʼs larger than _minForBullet (and the player
presses space), will initiate a new bullet. _lastBulletIndex will help in finding the next (inactive) available bullet sprite to
use.
In the Initialize method, weʼll set up the bullets:
for(int i = 0; i < _bullets.Length; i++) {
Sprite bullet = new Sprite(_bulletTexture);
bullet.Active = false;
bullet.Scale = 2;
bullet.ZLayer = .7f;
bullet.Origin = new Vector2(bullet.FrameWidth / 2, 0);
_bullets[i] = bullet;
}
Most of the code should be familiar. Weʼre creating all bullets up-front (to minimize creation during play, thus reducing
garbage collection chance) in an inactive state. When the player presses space and enough time has passed since
initiating the last shot, weʼll start a bullet (all in the Update) method:
if((_totalForBulletElapsed
+=
gameTime.ElapsedGameTime)
>
_minForBullet
&&
ks.IsKeyDown(Keys.Space)) {
_totalForBulletElapsed = TimeSpan.Zero;
CreateBullet();
}
foreach(var bullet in _bullets)
if(bullet.Active) {
bullet.Update(gameTime);
if(bullet.Position.Y < -­‐10) {
// out of bounds
3/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
bullet.Active = false;
}
}
Regardless, we must update the position of all active bullets. If a bullet moves beyond the screen bounds, we
de-activate it.
The CreateBullet is a small helper that actually activates the bullet, placing it in the right location and giving it proper
velocity:
private void CreateBullet() {
while(_bullets[_lastBulletIndex].Active)
_lastBulletIndex = (_lastBulletIndex + 1) % _bullets.Length;
Sprite bullet = _bullets[_lastBulletIndex];
bullet.Position = _player.Position;
bullet.Active = true;
bullet.Velocity.Y = -­‐6;
}
The first thing it does is find an inactive bullet that we can re-activate. Then it places it, gives it speed and activates it.
All thatʼs left is to draw the active bullets (in the Draw method):
foreach(var bullet in _bullets)
if(bullet.Active)
bullet.Draw(gameTime, _batch);
Thatʼs basically it. The only missing code is the loading of the bullet texture, done in LoadContent:
_bulletTexture = Game.Content.Load<Texture2D>("Images/bullet");
In the next part, weʼll play some sound effects, so the game feels more alive.
AlienRaid6.zip
Published Nov 09 2010, 01:20 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics
Comments
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 11, 2010 10:25 AM
Internet telephoney voip | voip equipment said:
Pingback from Internet telephoney voip | voip equipment
November 12, 2010 8:33 AM
4/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
‫ דני‬said:
‫ מדובר בסדרת פוסטים נפלאה שבאופן אישי אני לומד ממנה המון‬,‫היי פאבל‬
‫אני רואה איזושהי בעייתיות בשורה הזו בפונקציה לייצירת קליע‬
while(_bullets[_lastBulletIndex].Active)
_lastBulletIndex = (_lastBulletIndex + 1) % _bullets.Length;
‫מכיוון שבמידה ויתאפשר שבמשחק יהיו יותר קליעים בו זמנית מאשר מה שמוקצה במערך המשחק יתקע‬.
‫ניתן לראות זאת קורה אם מקטינים הזמן האפשרי בין יריה ליריה‬.
‫? האם יש לך רעיון לפתרון טוב (ובטוח) יותר‬
November 12, 2010 12:06 PM
pavely said:
‫הי דני‬,
‫ הדרך הפשוטה לפתור את זה היא להשתמש במערך דינמי‬.‫ המשחק בתנאים קיצוניים עלול להתקע‬.‫( בעיקרון אתה צודק‬List), ‫ובמקרה של‬
‫מספר חדורים גדול מידי להקצות חדש‬.
‫ אבל‬.‫ כך שמצב כזה לא יקרה‬,‫ מה שמקובל זה לקחת מרווח ביטחון‬.‫ בגלל ההקצאה הדינמית‬,‫ זה לא כל כך מקובל‬,‫אפילו שזה בטוח יותר‬
‫ להקצות מראש כמות מסוימת ועדיין לשמור על הגמישות של הרשימה‬:‫בהחלט ניתן לשלב‬.
(‫)!אני שמח שאתה נהנה ולומד‬
November 12, 2010 7:58 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
RealTime - Questions: "SQL update statement to change integer to have a 1 in front of it?" said:
Pingback from RealTime - Questions: "SQL update statement to change integer to have a 1 in front of
it?"
December 1, 2010 2:14 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
5/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 6) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/09/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
6/6
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 7) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/11/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 7)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
The game as it is now is not yet challenging – there are no enemies to threaten the player – she simply flies through
space, shooting at nothing. Weʼll deal with some enemies in the next part, but first letʼs consider sound.
Sound is a critical part of any game. Just for kicks, play your favorite action game with the volume off – youʼll get bored
or irritated pretty quickly. Sound is not just for fun, though; sometimes itʼs a critical ingredient, indicating to the player
that something important has happened without the player needing to focus in any particular point on the screen.
So how do we play sound effects or music in XNA? There are basically two ways: the first is to use XACT (Microsoft
Cross Platform Audio Creation Tool), which allows great control over the sounds you want to play. The second route is
to use a (pretty) simple API provided originally for the Zune (which does not support XACT), but can be used with any
XNA supported device. Weʼll take the second approach in this tutorial.
The first order of business is to add audio assets to the content project, much the same way we added images. XNA
supports playing WAV files (and some other less frequently used formats) as a sound effect. It also supports playing
MP3 files (more suitable for background music).
Add a folder named “Audio” to the content project (sibling of “Images”). Right click the new folder and select Add –>
Existing Item and navigate to a WAV file. For our purposes, weʼll add a WAV file that would be the sound when the
player fires one of its missiles/bullets.
Next, we need to load that sound into a SoundEffect object, very similar to other assets using the
ContentManager.Load<> generic method (in the LoadContent method of the PlayerComponent class for our
purposes):
_bulletSound = Game.Content.Load<SoundEffect>("Audio/bullet");
Where _bulletSound is a field of type SoundEffect.
The SoundEffect type has a Play method, and itʼs tempting to simply use it to play the sound. However, thatʼs not
recommended. The reason is that a call to Play is a kind of “singleton”; that is, a single sound instance can be played at
1/3
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 7) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/11/xna-2d-...
one time. So, if the player fires two bullets in close succession (and the sound effect is not too short), a second Play
would not create a separate, independent sound. The proper way to do this is use the SoundEffect.CreateInstance
method that returns a SoundEffectInstance object, representing an independent sound instance.
Each SoundEffectInstance can be separately played and configured (e.g. different volume).
The easiest way to handle the sound effect for the playerʼs bullets (although a bit wasteful) is to create a same length
array of SoundEffectInstance references, initialize them using SoundEffect.CreateInstance and playing when
appropriate (e.g. in the CreateBullet helper method).
_bulletSoundInstance[i] = _bulletSound.CreateInstance();
_bulletSoundInstance[i].Volume = .7f;
This initializes the sound effect instances inside the loop that creates the bullet sprites. To play, weʼll call
SoundEffectInstance.Play in CreateBullet after the new bullet has been setup properly:
_bulletSoundInstance[_lastBulletIndex].Play();
Thatʼs about it! We have sound!
AlienRaid7.zip
Published Nov 11 2010, 10:25 AM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Tutorial
Comments
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 13, 2010 2:46 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
2/3
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 7) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/11/xna-2d-...
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
3/3
2011/4/29 上午12:23
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 8)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
What do we have so far? A player controlling a ship capable of firing missiles (with sound), flying through space with a
backdrop of passing stars. Clearly, no real challenge for the player yet. Itʼs time to add some enemies to challenge the
player. In this part, weʼll handle setting up the data, and in the next part weʼll implement the actual enemies.
Creating enemy sprites and managing them is no different in principal than dealing with the player and her missiles. Itʼs
just a matter of creating and initializing sprites, managing their movements (if any) and drawing them. The real
challenge is designing the enemies for versatility, challenge, balance and re-playability. For this demo game, Iʼd like to
have levels the player goes through. In each level, she must destroy a certain number of enemies. Before moving to
the next level, Iʼd like to have a “boss” alien – this is classic (although somewhat a cliché). Difficulty will increase in
each level simply by force of numbers: more enemies, more frequent firing, faster speeds, etc. This is not an
“intelligent” way to go, but itʼs simple; and weʼre taking the simple approach in this tutorial.
The concept of “intelligence” is a complex one, and weʼll not deal with “Artificial Intelligence” techniques in this tutorial.
Weʼll focus on XNA stuff and simply use randomness and shear numbers to give the player a sense of some kind of
intelligent behavior from the enemy aliens.
The first order of business is to define various alien enemy types with properties, such as their texture, animation
parameters, maximum speed, score if hit, etc. This allows us to select aliens to be used in each level, gradually using
“stronger” aliens. Letʼs define a simple alien type class that holds all that info:
class AlienType {
public TimeSpan AnimationRate = TimeSpan.FromMilliseconds(500);
public string Name;
public int Score;
public int Space;
public float MaxXSpeed;
public float MaxYSpeed;
1/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
public Texture2D Texture;
public int Frames = 1;
public bool IsHorizontal = true;
public Rectangle? FirstFrame;
}
This simple class uses fields only for performance reasons discussed a previous post. Some fields are technical
(Texture, Space, Frames, etc.) and some functional (MaxXSpeed, MaxYSpeed). The Name fi eld will be used as a key
to access a particular alien as weʼll see shortly.
How do we get data into a collection of AlienType objects? One simple way is to create a collection and populate it in
code. This works, but not the best approach. one of the important issues on creating a game is the question of balance.
Itʼs fairly difficult to get a game to be “quite right” in terms of difficulty. You want it to be diffi cult, but not too diffi cult. if itʼs
easy, the player is bored. If itʼs too difficult, the player might give up. And yes, itʼs very tricky, as players themselves are
different. And no, your perception is not sufficient, as you may not be a typical player.
What this all means, is that various game parameters will have to be tweaked quite a bit. If this is all in code, every
tweak requires a recompilation, meaning time consumption, and more importantly – a developer must be at the seat.
Why should this be? A game designer (in a simple case, a friend) may want to balance the game by tweaking
parameters, but she may not have a Visual Studio or something. Thatʼs why itʼs better to put all possible parameters
outside the code, in some data files (e.g. XML). This is the approach weʼll take.
Add a new folder to the project named Data. Right-click the new folder and select Add –> New Item. Navigate to the
Visual C#->Data node and select “XML file”. Type AlienTypes in the Name box and click “Add”.
Right click the resulting file and select properties. Change the “Build action” to “None” and the “Copy to output
directory” to “Copy if newer”. This will ensure the file is located with the project output and is always up to date.
Now letʼs fill some alien types within the newly created XML file:
<AlienTypes>
<AlienType Name="alien1" Score="10" MaxXSpeed="3" MaxYSpeed="2"
Texture="Images/sprites" Frames="2" Space="1"
FirstFrame="104,84,16,13" AnimationRate="500" />
2/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
<AlienType Name="alien2" Score="15" MaxXSpeed="4" MaxYSpeed="3"
Texture="Images/sprites" Frames="2" Space="0"
FirstFrame="36,82,16,15" AnimationRate="400" />
<AlienType Name="alien3" Score="20" MaxXSpeed="5" MaxYSpeed="4"
Texture="Images/sprites" Frames="2" Space="0"
FirstFrame="2,81,16,15" AnimationRate="400" />
<AlienType Name="alien4" Score="25" MaxXSpeed="5" MaxYSpeed="5"
Texture="Images/sprites" Frames="2" Space="1"
FirstFrame="36,123,16,14" AnimationRate="400" />
<AlienType Name="alien5" Score="30" MaxXSpeed="4" MaxYSpeed="6"
Texture="Images/sprites" Frames="2" Space="0"
FirstFrame="37,143,13,9" AnimationRate="300" />
<AlienType Name="boss1" Score="500" MaxXSpeed="5" MaxYSpeed="0"
Texture="Images/sprites" Frames="2" FirstFrame="186,85,54,36" AnimationRate="1000"
/>
<AlienType Name="boss2" Score="800" MaxXSpeed="6" MaxYSpeed="0"
Texture="Images/sprites" Frames="2" FirstFrame="2,1,63,38" AnimationRate="900" />
<AlienType Name="boss3" Score="1000" MaxXSpeed="7" MaxYSpeed="0"
Texture="Images/sprites" Frames="2" FirstFrame="133,0,66,40" AnimationRate="800" />
<AlienType Name="boss4" Score="1500" MaxXSpeed="8" MaxYSpeed="0"
Texture="Images/sprites" Frames="2" FirstFrame="138,43,52,36" AnimationRate="600"
/>
</AlienTypes>
The “Images/sprites” asset name is a new image file that holds all the alien images (and some other things like
explosion images weʼll use later).
To read all this data, weʼll create a Dictionary in the game class and read the data in the Initialize method. Weʼll expose
the Dictionary as property for any interested party. The reading of data is done using LINQ to XML. If youʼre not familiar
with LINQ in general, or LINQ to XML, you should head out to the web and study it. Itʼs one of those things that once
you really understand – youʼll use it time and time again and never go back. If youʼre feeling unsure, you can read the
data using the old XML API (in System.XML – XmlDocument, XmlElement, XmlAttribute, etc. This API is way too
verbose for my taste
):
protected override void Initialize() {
base.Initialize();
_alienTypes = (from at in XElement.Load("data/alientypes.xml").Descendants("AlienType")
select new AlienType {
Name = (string)at.Attribute("Name"),
Score = (int)at.Attribute("Score"),
MaxXSpeed = (float)at.Attribute("MaxXSpeed"),
MaxYSpeed = (float)at.Attribute("MaxYSpeed"),
Texture = Content.Load<Texture2D>((string)at.Attribute("Texture")),
FirstFrame = ParseRectangle((string)at.Attribute("FirstFrame")),
Space = (int)at.Attribute("Space"),
Frames = (int)at.Attribute("Frames"),
AnimationRate
=
TimeSpan.FromMilliseconds((int)at.Attribute("AnimationRate"))
3/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
}).ToDictionary(t => t.Name);
}
The ToDictionary extension method turns the created list into a dictionary, keyed by the name of the AlienType. The
resulting data is exposed as a simple method from the game class:
internal AlienType GetAlienType(string name) {
return _alienTypes[name];
}
The next step is to create some data that represents whatʼs going on in each game level. Weʼll add another XML file
called Levels.Xml to the Data folder. Letʼs create some levels:
<Levels>
<Level Number="1" MaxActiveAliens="7" TotalAliensToFinish="15" Boss="boss1"
AlienGenerationTime="800" ChangeDirChance="2" FireChance="2" MaxAlienBullets="5">
<AlienTypes>
<AlienType Name="alien1" Chance="25" />
<AlienType Name="alien2" Chance="20" />
<AlienType Name="alien3" Chance="20" />
<AlienType Name="alien4" Chance="5" />
</AlienTypes>
</Level>
<Level Number="2" MaxActiveAliens="10" TotalAliensToFinish="25" Boss="boss2"
AlienGenerationTime="600" ChangeDirChance="2" FireChance="3" MaxAlienBullets="7">
<AlienTypes>
<AlienType Name="alien1" Chance="20" />
<AlienType Name="alien2" Chance="20" />
<AlienType Name="alien3" Chance="20" />
<AlienType Name="alien4" Chance="15" />
<AlienType Name="alien5" Chance="10" />
</AlienTypes>
</Level>
</Levels>
These are just 2 levels, but we can add as many as we want. The downloadable source has 4 levels defined.
A level has some attributes, such as the maximum number of active aliens, the number of aliens needed to advanced
to the next level, the name of the boss alien, etc. The most interesting part is the AlienTypes element that lists the
chance of each alien type to be generated during game play.
Similarly to the AlienType class, weʼll create some data structures that can hold the information for a particular level:
class AlienSelectionData {
public AlienType Alien;
public int Chance;
}
class LevelData {
public int Number;
4/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
public TimeSpan AlienGenerationTime;
public int MaxActiveAliens;
public int TotalAliensToFinish;
public AlienType Boss;
public List<AlienSelectionData> SelectionData;
public int ChangeDirChance;
public int FireChance;
public int MaxAlienBullets;
}
Although we can read all levels data in one swoop – this is unnecessary. We just need to read a single level,
corresponding to the current level.
First weʼll add a Level field to the game and create a helper method named InitLevel that reads the current level data
– in preparation for a new level. That data is exposed through a method, similarly to what we did with alien types:
private void InitLevel(int levelNum) {
Level = levelNum;
_levelData = (from level in XElement.Load("Data/Levels.xml").Descendants("Level")
where (int)level.Attribute("Number") == levelNum
select new LevelData {
Number = levelNum,
ChangeDirChance = (int)level.Attribute("ChangeDirChance"),
MaxActiveAliens = (int)level.Attribute("MaxActiveAliens"),
TotalAliensToFinish = (int)level.Attribute("TotalAliensToFinish"),
Boss = _alienTypes[(string)level.Attribute("Boss")],
FireChance = (int)level.Attribute("FireChance"),
MaxAlienBullets = (int)level.Attribute("MaxAlienBullets"),
AlienGenerationTime
=
TimeSpan.FromMilliseconds((int)level.Attribute("AlienGenerationTime")),
SelectionData = (from sel in level.Descendants("AlienType")
select new AlienSelectionData {
Chance = (int)sel.Attribute("Chance"),
Alien = _alienTypes[(string)sel.Attribute("Name")]
}).ToList()
}).SingleOrDefault();
Debug.Assert(_levelData != null);
}
internal LevelData GetCurrentLevelData() {
return _levelData;
}
The technique used here is the same used for the alien types data. Itʼs a bit more complex, as we need to read a
collection within the level data, indicating the chance a certain alien type should be created.
The InitLevel method should be called when the game starts, and when advancing to a new level. Weʼll add a call in
the AlienRaidGame.Initialize method, setting the level to 1:
InitLevel(1);
5/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
Now that we have all the right data set up, when can move on to actually creating and managing the aliens. Weʼll do
that in a separate component, for the same reasons we created separate components for the stars and the player. Add
a new DrawableGameComponent named AliensComponent by right-clicking the project, selecting Add->New Item,
navigating to XNA/Game Component, setting the name to AliensComponent and clicking Add. Then change the base
class from GameComponent to DrawableGameComponent.
In the next part, weʼll fill the newly created component with some live aliens!
AlienRaid8.zip
Published Nov 13 2010, 02:46 PM by pavely
‫תגים‬:.NET, XNA, LINQ to XML, C#, LINQ, DEV, Fun, Tutorial
Comments
‫ דני‬said:
‫ בקבצי ה‬XML ‫ חסרים ערכים לשדה ה‬Space
‫בעבור הבוסים שבמשחק‬
November 14, 2010 12:06 PM
pavely said:
‫ כנראה שצריך לעדכן את ה‬...‫ חשבתי שתיקנתי את זה‬,‫צודק‬-ZIP.
November 14, 2010 12:40 PM
pavely said:
‫דני‬,
‫זה מופיע ב‬-ZIP, ‫אבל לא בפוסט עצמו‬...
November 14, 2010 12:42 PM
‫ דני‬said:
‫ אני מחכה בקוצר רוח לפוסט הבא‬,‫תודה‬
November 14, 2010 2:11 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 14, 2010 10:20 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
how long from start to finish does it take to make money making video games if you started from
scratch? | money making blog said:
Pingback from how long from start to finish does it take to make money making video games if you
started from scratch? | money making blog
6/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 8) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/13/xna-2d-...
November 18, 2010 4:20 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
7/7
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 9) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/14/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 9)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
In the previous post we prepared the data for the aliens and for the game levels. In this post, weʼll put that data to
action.
The first thing weʼll do is create a custom Alien class, that extends the Sprite class and adds some specific alien
attributes. This will make our lives a little bit easier when we managed all those aliens. Add a new class named Alien
and derive it from Sprite. Weʼll need a constructor that satisfies the requirements of Sprite – weʼll get all the needed
information from an AlienType:
class Alien : Sprite {
public readonly bool IsBoss;
public readonly AlienType Type;
public Alien(AlienType type, bool isBoss)
: base(type.Texture, type.FirstFrame, type.Frames, type.IsHorizontal, type.Space) {
IsBoss = isBoss;
Type = type;
Origin.X = type.FirstFrame.Value.Width / 2;
AnimationInterval = type.AnimationRate;
}
}
The IsBoss fi eld indicates whether this alien is, in fact, a boss alien. A more “object oriented” approach wouldbe to
create an AlienBoss class, derive it from Alien, thus customizing its behavior. Iʼll leave that as an exercise for the
reader. Iʼll take the (somewhat) simpler approach here, but if I had wanted to make the boss behave very differently
from that of a regular alien, I would have done that with the derived class approach.
1/5
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 9) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/14/xna-2d-...
Now weʼll create an array of Alien references in the AlienComponent class (created in the previous part), somewhat
similar to the missiles array we created for the player. In this case, however, as every alien may look different, we may
have to create aliens dynamically as needed. Another possible approach would be to allow the Texture of a sprite to be
changed after the sprite has been initialized. Currently, the Texture of a sprite is passed via the constructor, and is read
only since.
In the Update method, weʼll update all existing aliens (for animation and movement purposes), and in the Draw method
weʼll draw them. Nothing has been created at this time:
public override void Update(GameTime gameTime) {
foreach(var alien in _aliens)
if(alien != null && alien.Active)
alien.Update(gameTime);
base.Update(gameTime);
}
public override void Draw(GameTime gameTime) {
_batch.Begin();
foreach(var alien in _aliens)
if(alien != null && alien.Active)
alien.Draw(gameTime, _batch);
_batch.End();
base.Draw(gameTime);
}
_aliens is the array declared in the AliensComponent class. Next, weʼll add the component to the gameʼs
Components collection in the gameʼs constructor (as usual for game components):
Components.Add(new AliensComponent(this));
Running the game at this time has no special effect. Our next task would be to actually create an alien (based on some
random factor and the game level). The Update method is the proper place for this:
// get current level data
LevelData data = AlienRaidGame.Current.GetCurrentLevelData();
if((_elapsedTime += gameTime.ElapsedGameTime) > data.AlienGenerationTime) {
_elapsedTime = TimeSpan.Zero;
if(CreateAlien() != null)
_currentLiveAliens++;
}
We first get the current level data by calling the gameʼs GetCurrentLevelData method we developed in the previous
part. Note that to get to the game object itself Iʼve added a static property called Current that is set in the gameʼs
constructor. The alternative is to cast the Game property back to the actual AlienRaidGame type, which I find
annoying (and like all casts – is applied at runtime, which is slower).
_elapsedTime is incremented by the elapsed time since the last frame and compared to the alien generation time
obtained from the level data. This indicates when itʼs time to attempt creation of a new alien. CreateAlien is a helper
2/5
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 9) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/14/xna-2d-...
method that does the actual creation and setting up of the alien:
private Alien CreateAlien() {
var data = AlienRaidGame.Current.GetCurrentLevelData();
if(_currentLiveAliens > data.MaxActiveAliens) return null;
int chance = 0;
int value = _rnd.Next(100);
foreach(var sd in data.SelectionData) {
if(value < sd.Chance + chance) {
// selected
while(_aliens[_currentAlienIndex] != null && _aliens[_currentAlienIndex].Active)
_currentAlienIndex = (_currentAlienIndex + 1) % _aliens.Length;
Alien alien = new Alien(sd.Alien, false);
alien.Position
=
new
Vector2((float)(_rnd.NextDouble()
*
Game.Window.ClientBounds.Width), -­‐50);
alien.Velocity = new Vector2((float)(_rnd.NextDouble() * alien.Type.MaxXSpeed * 2 -­‐
alien.Type.MaxXSpeed),
(float)(_rnd.NextDouble() * alien.Type.MaxYSpeed + 2));
alien.Scale = 2;
_aliens[_currentAlienIndex] = alien;
return alien;
}
chance += sd.Chance;
}
return null;
}
_currentLiveAliens counts the total aliens currently active and compared to the data from the current level prevents too
many aliens to be present at any one time. Then the SelectionData collection is used to select an alien type at
random, based on probabilities in the current SelectionData. If selected, a free index is located and a new alien
instance is placed there. The alienʼs position is set randomly in the X direction and at Y=-50 (just above the visible
screen, so it can make an entrance). Speed is set based on maxima read from the alien type. The alien is now active!
Running the code as is causes various aliens to move in a certain direction and disappear. After a while, aliens stop
appearing. This is because we increment the current live aliens but never decrement it. There is no checking for going
off the screen. Letʼs take care of that.
First, if an alien moves off the screen in the X axis, I want it to simply change direction (bounce back). This we can do
in the Alien.Update override (of the same Sprite method):
public override void Update(GameTime gameTime) {
if(Active) {
if(Position.X < 0 || Position.X > AlienRaidGame.Current.Window.ClientBounds.Width)
Velocity.X = -­‐Velocity.X;
}
base.Update(gameTime);
}
3/5
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 9) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/14/xna-2d-...
Although the bounds checks are not exact, they are good enough. The aliens now bounces off the right and left edges
of the game screen.
Now for the Y position: if itʼs beyond the screen, then mark the alien as inactive and decrement the active alien count.
Itʼs a bit problematic to do that in the same Update method, as we donʼt have access to the parent AliensComponent,
and we wouldnʼt want a direct access anyway. One option is to check all that in the AliensComponent.Update method.
This is somewhat awkward, but possible. Another alternative is to use an event. The alien can fire an event when itʼs Y
position is out of bounds. Any interested party (the AliensCompoenent object) can handle that event appropriately. For
the sake of versatility, letʼs use an event. First, letʼs declare it in the Alien class:
public event Action<Alien> OutOfBounds;
In “classic” .NET an event delegate should be of type EventHandler or EventHandler<T> (that accept an object and a T
that must derive from EventArgs). Here weʼre cutting another corner, as we prefer type safety and fewer arguments.
Raising (or firing the event) should be done during Update:
if(Position.Y > AlienRaidGame.Current.Window.ClientBounds.Height + 40) {
Active = false;
if(OutOfBounds != null)
OutOfBounds(this);
}
Subscribing to the event is conveniently done in the CreateAlien helper. A simple lambda expression (or anonymous
delegate if you prefer, or a regular method) can be used:
alien.OutOfBounds += a => {
_currentLiveAliens-­‐-­‐;
};
If thatʼs a bit scary, we can write it like this instead:
alien.OutOfBounds += delegate {
_currentLiveAliens-­‐-­‐;
};
If thatʼs still scary, then we could write that as a separate method and do the _currentLiveAliens—in there.
If the anonymous delegate or lambda expression is unfamiliar, or you chose to stay from those “complications”, I
strongly suggest you read about those and get comfortable with that. Theyʼre not going away any time soon.
Running the game now shows a bunch of aliens that keep flying, changing direction at the seams, while the player
moves her ship and fires at the aliens. Didnʼt hit them, did you? The upside is the aliens couldnʼt hit you, either.
Why? There is no collision detection or handling of such collisions. Thatʼs the topic of the next part.
AlienRaid9.zip
AlienRaid9.zip
Published Nov 14 2010, 10:20 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics
Comments
4/5
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 9) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/14/xna-2d-...
Learn How To Play Guitar | guitar book said:
Pingback from Learn How To Play Guitar | guitar book
November 16, 2010 12:58 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
5/5
2011/4/29 上午12:25
XNA 2D Game Tutorial (Part 10) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/16/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 10)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
Part 9: Creating Aliens
In the previous part we created a bunch of alien enemies that are moving down the screen. Currently, if they hit the
playerʼs ship – nothing happens. If the playerʼs missiles hit an alien – nothing happens. We need some collision
detection.
Collision detection in a 2D world is usually done with a simple approximation: that all sprites are rectangular. Although
itʼs possible (at least in theory) to use the actual “shape” of sprites to locate overlapping areas, this is impractical – itʼs
computationally expensive, and the benefits are too small. Collision detection may be used hundreds times per frame,
so it must be quick. Weʼll compare bounding rectangles of sprites and look for an intersection. To be less sensitive to
“false positives” (non collisions flagged as collisions), we can reduce the bounding rectangles by some amount (say, 10
percent). If you ever played a game where you thought you hit something but you didnʼt – well, maybe you did, and it
just didnʼt take because of that reduction (“false negative”). or you were sure you were hit, but survived – for the very
same reason. This is a well known compromise that we can live with.
Weʼll start by adding a property to the Sprite class that returns the bounding rectangle of a sprite:
public Rectangle BoundingRect {
get {
return new Rectangle(
(int)(Position.X -­‐ Origin.X * Scale), (int)(Position.Y -­‐ Origin.Y * Scale),
(int)(_rects[0].Width * Scale), (int)(_rects[0].Height * Scale));
}
}
The bounding rectangle formula is a bit complex because of the possibility of a different Origin (other than 0,0) and the
Scale. Hopefully, this is correct enough…
Now weʼll add a simple Collide method to the Sprite class that checks intersecting rectangles:
1/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 10) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/16/xna-2d-...
public virtual bool Collide(Sprite other) {
return BoundingRect.Intersects(other.BoundingRect);
}
No shrinking factor is used here – Iʼll leave that as an exercise for the reader. The method is marked virtual in case a
derived class wants to check collisions in some other way. The XNA Rectangle type provides a simple Intersects
method that we can leverage.
With this infrastructure in place, we can move on to the actual collision checking. There are several combinations we
need to check: playerʼs missiles against aliens, aliens against player, aliens missiles (donʼt exist yet) against player.
Letʼs start with the playerʼs missiles against aliens. This allows the player to actually kill an alien. Collision detection is
done in the relevant Update method. In this case weʼll check that in the PlayerComponent class where the bullets are
handled. We could have reversed that, checking collisions in the alien movement loop against all playerʼs missiles.
To gain access to the aliens from the PlayerComponent class, weʼll have to expose the aliens collection as a property
from the AliensComponent class:
internal IEnumerable<Alien> Aliens { get { return _aliens; } }
To gain access to the AliensComponent instance in the first place (from the PlayerComponent class, or any other
component class for that matter), weʼll add a field to the game class that would be set to point to the
AliensComponent:
public readonly AliensComponent AliensComponent;
In the constructor of the game, weʼll set the field while adding the component:
Components.Add(AliensComponent = new AliensComponent(this));
Itʼs time to do the actual checking from the PlayerComponent while moving active bullets:
foreach(var bullet in _bullets)
if(bullet.Active) {
bullet.Update(gameTime);
if(bullet.Position.Y < -­‐10) {
// out of bounds
bullet.Active = false;
}
else {
foreach(var alien in AlienRaidGame.Current.AliensComponent.Aliens)
if(alien != null && alien.Active && bullet.Collide(alien)) {
// alien hit!
bullet.Active = false;
}
}
}
The actual collision check is in bold. In case of a collision we deactivate the bullet. The next logical step would be to
2/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 10) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/16/xna-2d-...
make the alien explode or something. We could create an explosion sprite, but letʼs do something else: weʼll make the
alien disappear gradually with shades of red. But, first thingʼs first: How would we know the actual alien is dead?
Perhaps itʼs a boss alien and is more resilient? The simplest approach would be to notify the alien itself that it has been
hit and it figure out what to do with this.
Letʼs add a Hit method to the Alien class, and call it in case a player missile collides with an alien:
public virtual void Hit(int power = 1) {
if((HitPoints -­‐= power) <= 0) {
// alien killed, start death sequence
_isDying = true;
Color = new Color(255, 0, 0);
if(Killed != null)
Killed(this);
}
}
HitPoints is a field indicating the “health” of the alien. Itʼs initialized to 1 for normal aliens (and to a larger value for a
boss, not done yet). We can even vary the power of the playerʼs shot by changing the power argument. This could be
(for example) as a result of some powerup (weʼll talk about those in a later post). Killed is another event an alien may
fi re to any interested parties:
public event Action<Alien> Killed;
_isDying is a boolean indicating whether the alien is in a dying process. An IsDying property exposes this publicly. The
Color is changed to use the red component only. Instead of some kind of explosion, weʼll change the “redness” of the
alien gradually down to black. This is all done in the modified Alien.Update method:
public override void Update(GameTime gameTime) {
if(Active && !_isDying) {
if(Position.X < 0 || Position.X > AlienRaidGame.Current.Window.ClientBounds.Width)
Velocity.X = -­‐Velocity.X;
if(Position.Y > AlienRaidGame.Current.Window.ClientBounds.Height + 40) {
Active = false;
if(OutOfBounds != null)
OutOfBounds(this);
}
}
else if(_isDying) {
if(Color.R > 4)
Color.R -­‐= 4;
else {
Active = false;
}
return;
}
base.Update(gameTime);
}
3/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 10) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/16/xna-2d-...
The code to test for collisions between the aliens and the playerʼs bullets is now modified to call Alien.Hit and to
disregard dying aliens:
foreach(var alien in AlienRaidGame.Current.AliensComponent.Aliens)
if(alien != null && alien.Active && !alien.IsDying && bullet.Collide(alien)) {
// alien hit!
bullet.Active = false;
alien.Hit();
}
Thatʼs about it! Run the game and kill some aliens!
No score is incremented yet, no sound is heard when an alien explodes. Feel free to add one!
In the next part weʼll add more collision detection (so the player can be killed too) and some explosions. Weʼll also add
some stats, such as score and the number of lives remaining.
AlienRaid10.zip
Published Nov 16 2010, 10:45 AM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun
Comments
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
November 17, 2010 7:25 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
4/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 10) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/16/xna-2d-...
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
5/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 11) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/17/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 11)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
Part 9: Creating Aliens
Part 10: Collision Detection
In the previous part we did some collision detection between the playerʼs missiles and the aliens. If hit, the alien
disappeared gradually (as opposed to a big explosion). Letʼs add some more collision detection.
First, a small bug fix: if we keep killing aliens, eventually new one wonʼt be generated. The reason is the Killed event is
not handled and so the number of current “live” aliens never decreases…
This is fixable by adding handling of the Killed event like so:
alien.Killed += a => {
_currentLiveAliens-­‐-­‐;
};
Currently, the player is invincible – she cannot be killed or hurt in any way. Itʼs time to change that. We need to check
each “live” alien with the player. If thereʼs a hit, weʼll create an explosion.
Where should we do the collision check? As usual in these cases, we can do that from either the aliens side or the
player side. Which one is “better”? In this case Iʼd prefer doing it from the aliens side. Why? Because weʼre already
iterating over the aliens – all we need is add one additional check for collision with the single player sprite. If weʼd go
the other way around, weʼd have to create another loop for checking against all aliens – less efficient.
First, we need access to the player component from the aliens component. weʼll do that similarly to the way we
exposed the aliens component – by exposing it via a readonly field:
public readonly PlayerComponent PlayerComponent;
1/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 11) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/17/xna-2d-...
and setting it in the gameʼs constructor while creating the component:
Components.Add(PlayerComponent = new PlayerComponent(this));
The next thing we need to prepare is to expose the playerʼs sprite for external access (currently itʼs a private field):
public Sprite Player { get { return _player; } }
Now we can actually implement the collision check in AliensComponent.Update:
var pc = AlienRaidGame.Current.PlayerComponent;
foreach(var alien in _aliens)
if(alien != null && alien.Active) {
alien.Update(gameTime);
if(!alien.IsDying && pc.Player.Active && alien.Collide(pc.Player)) {
// player hit!
alien.Hit(5); // alien hit, too!
pc.Player.Active = false; // deactivate for now
}
}
If we run the game now, any alien that hits the player causes the ship to disappear, never to appear again. Only one life
right now!
Letʼs add some explosion sprite when the playerʼs ship explodes and an explosion sound, too. Weʼll use the 6 frame
explosion inside the file sprites.png, which is already one of our game assets.
First, weʼll add a PlayerHit method to PlayerComponent, so that the player can handle its own hit logic:
public void PlayerHit(int power = 1) {
// player always dies
_player.Active = false;
// setup explosion
_playerExplodeSound.Play();
}
The player is simply deactivated. Iʼve also added an explosion sound (in the usual way). When an alien collides with the
player, this method should be called:
if(!alien.IsDying && pc.Player.Active && alien.Collide(pc.Player)) {
// player hit!
alien.Hit(5); // alien hit, too!
pc.PlayerHit();
}
This shifts the responsibility of handling hitting the player to the PlayerComponent, where itʼs most appropriate.
Now for the explosion: weʼll add a Sprite field to hold it, and initialize it in a deactivated state:
_playerExplosion = new Sprite(_explosionTexture, new Rectangle(0, 153, 65, 66), 6, true, 1);
2/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 11) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/17/xna-2d-...
_playerExplosion.Active = false;
_playerExplosion.Origin.X = _playerExplosion.FrameWidth / 2;
_playerExplosion.AnimationInterval = TimeSpan.FromMilliseconds(400);
_explosionTexture is Texture2D object, created in LoadContent as usual. To make the explosion visible and animating,
we need to add appropriate code to the Update and Draw methods (like we do with any sprite). Now we just need to
activate the explosion when the player is hit:
public void PlayerHit(int power = 1) {
// player always dies
_player.Active = false;
// setup explosion
_playerExplodeSound.Play();
_playerExplosion.Position = _player.Position;
_playerExplosion.Active = true;
}
If we run now, we find out the when the player is hit, the explosion animation plays repeatedly instead of just once. We
need to add this capability to the Sprite class. Add two fields to indicate whether one shot animation is enabled:
public bool OneShotAnimation;
public bool DeactivateOnAnimationOver = true;
DeactivateOnAnimationOver indicates if the sprite should automatically deactivate when the animation sequence is
done (true by default). We need to update the Sprite.Update method to use these new fields:
public virtual void Update(GameTime gameTime) {
if(Active) {
if(TotalFrames > 1 && (_animElapsed += gameTime.ElapsedGameTime) > AnimationInterval) {
if(++_currentFrame == TotalFrames) {
_currentFrame = 0;
if(OneShotAnimation) {
_currentFrame = TotalFrames -­‐ 1;
if(DeactivateOnAnimationOver)
Active = false;
}
}
_animElapsed -­‐= AnimationInterval;
}
Position += Velocity;
}
}
Now letʼs initialize the explosion to use one shot animation, and voila! We have explosions. The downloadable source
also includes explosion sound for the aliens (and some minor bug fixes).
Although I promised displaying stats in this part, Iʼll save that for the next part.
AlienRaid11.zip
3/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 11) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/17/xna-2d-...
AlienRaid11.zip
Published Nov 17 2010, 07:25 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun, Graphics, Games
Comments
how long from start to finish does it take to make money making video games if you started from
scratch? | money making blog said:
Pingback from how long from start to finish does it take to make money making video games if you
started from scratch? | money making blog
November 18, 2010 4:20 AM
‫ דני‬said:
‫בעיה בקול‬
‫ לא שומעים את הפיצוץ של החייזר השני אלא רק את של הראשון‬,‫ חייזרים בטווח זמן קצר‬2 ‫? למה במקרה שהורגים‬
‫הרי עפ"י מה שלימדת בפרקים הקודמים הצליל היה אמור להישמע בכל מקרה‬
November 21, 2010 10:02 PM
pavely said:
‫ ייתכן שהצליל הקודם שהיה שם כבר היה בנגינה וצריך לקרוא ל‬.‫ אני עדיין לא בטוח בסיבה‬.‫זה אכן קורה מידי פעם‬-Stop ‫ורק אח"כ‬
‫ל‬-Play. ‫אמשיך לחקור‬
November 21, 2010 10:52 PM
MVP published 11 part XNA 2d tutorial « Ruari's Chaos said:
Pingback from MVP published 11 part XNA 2d tutorial &laquo; Ruari&#039;s Chaos
November 25, 2010 10:29 AM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
4/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 11) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/11/17/xna-2d-...
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
5/5
2011/4/29 上午12:26
XNA 2D Game Tutorial (Part 12) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/05/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 12)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
Part 9: Creating Aliens
Part 10: Collision Detection
Part 11: More Collisions
Teched is over. Time to get back to XNA…
In our current project, we have a simple game in which the player can shoot aliens. They keep coming, and once the
player is killed – the game is technically over, although the alien enemies keep on coming. Whatʼs left? The aliens may
fi re perhaps, the player needs more than one “life”, we should display some score, we need to end aevel
l
sometime…
etc.
It seems thereʼs a lot to do, and there is. A game is a complex piece of software. In this part, weʼll take a look a
displaying some statistics, as we have not yet tackled text displays.
Displaying Text
To display some text, weʼre going to need a font. Unlike “regular” frameworks (e.g. WinForms, WPF), there is no direct
Font class, as XNA is adept at “blitting” sprites (in the 2D world) and nothing else. What we need is a sprite based font,
which is another content type we can use.
Right click the content project and select “Add New Folder…”. Name it Fonts. Right click the newly created folder and
select “Add New Item…”. Select the Sprite Font item, give it a name, such as Stats.SpriteFont and click “Add”:
1/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 12) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/05/xna-2d-...
The result is an XML file, describing a font, such as the font name, its size, spacing and more. This is your chance to
customize the resulting font. For example, letʼs change the font name to Arial:
<FontName>Arial</FontName>
Feel free to change other properties of the font.
To use the newly created sprite font we need to load the content in the usual way, and then use SpriteBatch.DrawString
to display a string with our font in a suitable position.
To make this more concrete, weʼll display a score for the player. To do that, weʼll add a Score fi eld to the
PlayerComponent class, and update that when an alien is killed:
if(alien != null && alien.Active && !alien.IsDying && bullet.Collide(alien)) {
// alien hit!
bullet.Active = false;
alien.Hit();
Score += alien.Type.Score * AlienRaidGame.Current.Level;
_explodeSoundInstance[i].Play();
break;
}
This is part of the PlayerComponent.Update method. First, weʼll load the font in PlayerComponent.LoadContent:
_statsFont = Game.Content.Load<SpriteFont>("Fonts/stats");
_statsFont is a private field in that class. To display the score, weʼll add an appropriate call in PlayerComponent.Draw:
2/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 12) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/05/xna-2d-...
_batch.DrawString(_statsFont, string.Format("Score: {0,5}", Score), new Vector2(30, 30),
Color.Yellow);
Thatʼs about it. We have text!
As another statistical item, letʼs add more “lives” for the player and display them as images of the space ship to indicate
the actual lives remaining. First, weʼll create a field called Lives to serve as our life counter. Then weʼll display that with
“regular” calls to SpriteBatch.Draw:
for(int i = 0; i < Lives; i++)
_batch.Draw(_playerShip, new Vector2(i * 30 + 30, 60), new Rectangle(0, 0, _playerShip.Width
/ 2, _playerShip.Height), Color.White);
This gives the following display:
The only remaining thing is to actually update Lives when appropriate. Iʼll leave that as an exercise for the reader (for
now).
In the next part weʼll take a look at game states and how to manage them.
Published Dec 05 2010, 03:55 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Fun
Comments
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 19, 2010 6:49 PM
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
3/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 12) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/05/xna-2d-...
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
4/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 13) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/19/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 13)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
Part 9: Creating Aliens
Part 10: Collision Detection
Part 11: More Collisions
Part 12: Displaying Text
In a typical game, when a user double-clicks the EXE file, the game does not start right away. At the very least, an
introduction screen is presented with some menu offering to start the game, maybe change some options, view high
scores, etc. At the very very least, the player needs to “press any key” or something similar to get into the action.
Furthermore, when a game is over, there is typically some ending screen with the total score, perhaps some ranking
system, a high score list or whatever.
To do all that, we need to manage game states. A simple game might need three states: Introduction, Playing and
Game over. Managing states is not difficult with XNA when working with game components, as we have. Each game
component can be “turned on” or “turned off”, so only a subset of game components are active at any one time.
Letʼs add an introduction component. Add a new GameComponent by selecting Add New Item from the project right
click
menu.
Name
it
IntroComponent.
As
usual,
change
the
base
class
from
GameComponent
to
DrawableGameComponent, as we need to draw some introduction stuff.
Letʼs add to that class a SpriteBatch, and two fonts, one big and one small (weʼll use the Stats font we added in a
previous post for the small version). Weʼll load the fonts as usual, and create the SpriteBatch as usual as well. Hereʼs
the Draw method we create:
public override void Draw(GameTime gameTime) {
_batch.Begin();
_batch.DrawString(_font, "ALIEN RAID", new Vector2(150, 120), Color.Yellow);
1/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 13) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/19/xna-2d-...
_batch.DrawString(_smallFont, "Press ENTER to play", new Vector2(280, 250), Color.Cyan);
_batch.End();
base.Draw(gameTime);
}
Next, weʼll add a readonly field to the game class (as we did with other components) and add the component to the
Components collection in the constructor:
Components.Add(IntroComponent = new IntroComponent(this));
Running the game now has a strange effect: the title is displayed but the game is playing…
What we want is to disable and hide the IntroComponent while the game is actually playing.
First, letʼs define some game states. Add the following code before the declaration of the AlienRaidGame class:
public enum GameState {
Intro, InPlay, GameOver
}
We have the three basic states: introduction, playing and game over. To switch between states, weʼll add a property
indicating the current state and create a helper method in the game class that switches on or off the appropriate
components:
public GameState State { get; private set; }
public void GotoState(GameState state) {
switch(state) {
case GameState.Intro:
IntroComponent.Enabled = IntroComponent.Visible = true;
AliensComponent.Enabled = AliensComponent.Visible = false;
PlayerComponent.Enabled = PlayerComponent.Visible = false;
GameOverComponent.Enabled = GameOverComponent.Visible = false;
break;
case GameState.InPlay:
IntroComponent.Enabled = IntroComponent.Visible = false;
AliensComponent.Enabled = AliensComponent.Visible = true;
PlayerComponent.Enabled = PlayerComponent.Visible = true;
GameOverComponent.Enabled = GameOverComponent.Visible = false;
break;
case GameState.GameOver:
IntroComponent.Enabled = IntroComponent.Visible = false;
AliensComponent.Enabled = AliensComponent.Visible = false;
PlayerComponent.Enabled = PlayerComponent.Visible = false;
GameOverComponent.Enabled = GameOverComponent.Visible = true;
break;
2/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 13) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/19/xna-2d-...
}
State = state;
}
Pretty straightforward. The more compute-science inclined might say that we need to build a full fledged state machine
with states and transitions and …
Forget it. Itʼs not worth the trouble, and a simple switch will do even if we need a few more states along the way.
The Enabled property of a GameComponent specifies whether Update should be called. The Visible property
specifies whether DrawableGameComponent.Draw should be called. Usually, both will be set to the same value. Note
that the starfield component is always visible and enabled (which is the default). I decided I want to see the starfield
even in the introduction screen.
Now that we have this in place, we can start with the “Intro” state by calling GotoState in the gameʼs constructor:
GotoState(GameState.Intro);
Running the game now makes the intro visible (along with the starfield) but the game does not go any further. We need
to make good on our promise and play the game when ENTER is pressed.
For this weʼll modify IntroComponent.Update to check for the appropriate key and transition to the new state when
needed:
public override void Update(GameTime gameTime) {
var ks = Keyboard.GetState();
if(_previousKS.IsKeyDown(Keys.Enter) && ks.IsKeyUp(Keys.Enter))
AlienRaidGame.Current.GotoState(GameState.InPlay);
_previousKS = ks;
base.Update(gameTime);
}
The _previousKS is a KeyboardState fi eld that keeps track of the previous state. This helps to wait when the ENTER
key is released after being pressed. Then we transition to the InPlay state.
Similarly, we can add a GameOverComponent and switch to that state when the player is killed (when Lives reach
zero). From there, we can override Update again, and wait for some key and return to the Intro state or even straight to
the InPlay state. The attached code has the GameOver state implemented (the player has currently one “life”).
That the idea of states and state management. Itʼs pretty convenient given the Components model.
In the next (and final) part Iʼll talk about some more features we can add, and discuss some philosophical issues
related to game development and XNA.
AlienRaid13.zip
Published Dec 19 2010, 06:49 PM by pavely
‫תגים‬:.NET, XNA, C#, DEV, Games
Comments
3/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 13) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/19/xna-2d-...
Pavel's Blog said:
Previous posts in this series: Part 1 : Getting started Part 2 : Drawing something Part 3 : Input handling
December 31, 2010 6:54 PM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
‫פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬/‫ התוכן אינו מטעם או בשליטת‬.‫התוכן המופיע באתר זה הינו תוכן גולשים‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
4/4
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 14–Last) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/31/xna-2d-...
MS Israel Community
Building a community
Pavel's Blog
Pavel is a software guy that is interested in almost everything software related... way too much for too little time
XNA 2D Game Tutorial (Part 14–Last)
Previous posts in this series:
Part 1: Getting started
Part 2: Drawing something
Part 3: Input handling
Part 4: Game Components
Part 5: Animation and Sprites
Part 6: Handling Projectiles
Part 7: Sound Effects
Part 8: Setting Up Data
Part 9: Creating Aliens
Part 10: Collision Detection
Part 11: More Collisions
Part 12: Displaying Text
Part 13: Game States
Over the past posts, weʼve created a game. A simple game, for sure, but the objective was learning XNA, not creating
the greatest game ever.
Creating a game is more than just using some technology, programming language or device. The more diffi cult part is
actually making the game fun. This is an art more than a craft, and involves game design, game play, artificial
intelligence and more. This post series concentrated on the mechanics of making a game with XNA, but this is
(relatively) the easy part.
Weʼve covered most of the XNA ground in 2D. We are now capable of creating a complete game. All thatʼs left to do is
start programming a unique game! This is no mean feat. It takes time, patience and creativity, as well as programming
skills that hopefully were developed throughout this series.
The final game source rounds off thing started in previous parts. Player lives are tracked, boss alien appears before
moving to the next level and aliens also fire missiles. Still more additions are possible, such as “power ups”, various
items falling from (e.g.) dead aliens that give out various abilities and disabilities, such as: faster fire power, a shield for
(say) 10 seconds, faster ship speed, slower ship speed, a bonus ship, etc. Iʼll leave that as an exercise for the reader.
Writing games is one of the most challenging programming tasks as it involves so many disciplines, such as graphics,
sound, animation, artificial intelligence, storytelling and more. This is one reason itʼs so challenging – and fun!
The series covered 2D games only. 3D games are quite different, requiring extended skills. The skills learned in this
series are not wasted in 3D. It just takes some extra ones. I will consider writing a similar series for an XNA 3D game if
demand is high enough.
1/3
2011/4/29 上午12:27
XNA 2D Game Tutorial (Part 14–Last) - Pavel's Blog
http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/31/xna-2d-...
Until then, happy game programming (oh, and a happy new year!)
AlienRaid - Final for now
Published Dec 31 2010, 06:54 PM by pavely
‫תגים‬:XNA, DEV, Fun, Games
Comments
Thanks said:
Thanks a lot. This is very good introduction for xna.
January 8, 2011 6:35 PM
Piero said:
Nice !
Waiting for the 3D !
January 10, 2011 11:25 AM
Brad said:
Wow, what a great tutorial! Thanks for sharing!!
January 19, 2011 7:00 AM
Leave a Comment
Name (required)
Your URL (optional)
Comments (required)
Remember Me?
Enter the numbers above:
About pavely
Pavel Yosifovich is currently the CTO of Matrix Global, and an instructor at Hi-Tech College. Previously, he was a senior
consultant at SELA Group. Earlier than that he was the CTO of Hi-Tech College. Before that he was the CTO and
co-founder of the startup Quiksee (TM) (www.quiksee.com) and the Software Division Manager at Hi-Tech College.
Pavel has more than 11 years of experience in professional software development. He has been lecturing throughout
the years on Microsoft and other technologies, in private courses and public conferences.
2/3
2011/4/29 上午12:27
‫‪http://blogs.microsoft.co.il/blogs/pavely/archive/2010/12/31/xna-2d-...‬‬
‫‪XNA 2D Game Tutorial (Part 14–Last) - Pavel's Blog‬‬
‫התוכן המופיע באתר זה הינו תוכן גולשים‪ .‬התוכן אינו מטעם או בשליטת‪/‬פיקוח מיקרוסופט והיא אינה אחראית לו בכל צורה או אופן‬
‫תנאי שימוש |סימנים מסחריים |הצהרת פרטיות‬
‫‪2011/4/29 上午12:27‬‬
‫‪3/3‬‬