Subscribe

RSS Feed (xml)

Powered By

Powered by Blogger

Google
 
xnahelp.blogspot.com

Jumat, 04 April 2008

2D Basics

The XNA Framework not only provides easy ways for us
to utilize 3D objects, but it also provides excellent 2D
support. There are actually a couple of ways we can achieve
2D inside of XNA. There is true 2D, which is sprite manipulation.
We will discuss this kind of 2D. The other kind is
actually setting up a 3D environment, but locking the
camera so that it is always looking at the same angle and
cannot be moved—it is a 3D world with a stationary
camera.
Whereas 3D uses models to display our scene, 2D uses
images to create and animate our scene. The two dimensions
are x and y—there is no z in 2D. It is very common
to mix 2D and 3D into the same game. Scores, menus, and
timers are examples of things that are typically 2D in a 3D
world. Even if you are not interested in writing 2D games,
the next three chapters will prove beneficial, as there will
be things that can be incorporated into your 3D masterpieces.
Sprite Batches
First we need to understand the term sprite. A sprite is an
image. XNA represents sprites with a Texture2D object. We
load them just like we load textures for our 3D applications,
as they are both images and get processed the same
way. The difference is that in 3D we texture an object with
the image, whereas in 2D we draw the image (or part of the
image) on the screen. We saw an example of drawing part
of an image in the last chapter. We applied different parts
of an image to our skybox. The concept is the same, but
the process is a little different. Really, we just pass in whole
numbers instead of floats. Sprites are represented by x and
y and as such have int values. It is impossible to draw
something at pixel location 0.3, 0.3. If these types of values
172 CHAPTER 9 2D Basics
are passed in, XNA will do some anti-aliasing to make it appear that it is partially in the
pixel area but the actual image location is rounded to a whole number.
We discussed the 3D coordinate system earlier and now we discuss the 2D coordinate
system. The top left of the screen is the origin of the screen (0,0). The x axis runs horizontally
at the top of the screen and the y axis runs vertically down the left side of the
screen. It is identical to how a texture’s coordinate system is used. The difference is that
instead of running from 0.0 to 1.0 like in a texture, the values run from 0 to the width
and height of the screen. So if the resolution is 1024 x 768, the x values would run from
0,0 to 1024,0. The y values would run from 0,0 to 0,768. x runs from left to right and y
runs from top to bottom. The bottom right pixel of the screen would be 1024,768. This
can be seen in Figure 9.1.
x+
y+
(0,0) (1024,0)
(0,768) (1024,768)
FIGURE 9.1 The 2D coordinate system origin is the top left of the screen.
Although the origin of the screen is 0,0 the origin of a sprite may or may not be. The
default is 0,0 but the origin can be overridden if needed. When we draw sprites to the
screen we need to be aware of where the origin of the sprite is because when we pass in a
coordinate (via a Vector2 type), XNA will draw the object to that location starting with
the origin of the sprite. So if we drew the sprite at location 100,200 and we did not touch
the origin of the sprite, then the top left of the sprite would get drawn in 100,200. If we
wanted 100,200 to be the center then we would either need to define the origin of our
sprite or we would need to offset our position manually. When we rotate our sprites, they
will rotate around the origin of the sprite. When we need to rotate our sprites we will
typically set the origin of the sprite to be the center of the sprite. This way the sprite will
rotate around the center. Otherwise, the sprite would rotate around 0,0. The differences
between these two can be seen in Figure 9.2.
We can also scale a sprite. Scaling comes in three different flavors. We can either give a
number to scale the entire sprite by or we can just scale one portion of the sprite. The
final way we can scale is to specify a source rectangle and then specify a destination
rectangle. XNA can scale our source rectangle to fit into our destination rectangle.
Sprite batches are simply batches of sprites. When we draw a lot of sprites on the screen it
can put a load on the machine as we have to send a separate instruction to the graphics
card each time we draw something to the screen. With a sprite batch we have the ability
to batch up our draw functions to happen within the same settings and send one draw
call to the graphics card. When we create a SpriteBatch in our code we can pass in the
following values to its Begin method: SpriteBlendMode, SpriteSortMode, and
SaveStateMode.
Sprite Blend Modes
The blend mode can be set to AlphaBlend, Additive, and None. The default blend mode is
AlphaBlend. AlphaBlend does just that: It blends the sprites drawn (source) with the pixels
it is being drawn on (destination) based on the alpha value of both. This includes transparency
but can be used to create different effects depending on blend values we provide.
We will cover overriding the blending values in the next chapter. Additive is another
common blend mode that XNA provides support for with our sprite batches automatically.
Finally, None simply does not set any blending modes. It just overwrites the destination
area with the source sprite.
Alpha blending is used for normal translucent things like glass, windows, water, and
objects that fade in or out. Additive blending, on the other hand, is good to use when
creating glowing objects like explosions, sparks, and even magic effects. We will discuss
these two blending modes and even more that are not directly supported by sprite
batches in the next chapter.
Sprite Sort Modes
The sort mode determines how different sprites that are drawn actually get displayed on
the screen. In previous times, game developers had to take great care with how they
displayed images to the screen to make sure the background did overwrite their foreground
and that textures with alpha values rendered correctly. Although we still need to
take care as we approach this task, a lot of work has been done for us so that we need to
worry about it less. We still need to be aware of how XNA handles this for us so we can
use it effectively and keep our frame rates high.
Sprite Batches 173
9
FIGURE 9.2 The origin of the sprite determines how the sprite will be rotated.
The sort mode can be set to BackToFront, Deferred, FrontToBack, Immediate, and
Texture. The sort mode defaults to Deferred when we call Begin with no parameters.
Immediate is faster than Deferred. Immediate works a little different than the rest of the
sort modes. Immediate updates the graphics device settings immediately when the Begin
method is called. Then as sprites are drawn to the screen they immediately appear with
no sorting. This is the fastest method available, but it requires us to sort the images the
way we want them to be displayed. We draw the background images first and move up to
the foreground. An interesting thing we can do with immediate mode is change our
graphics device settings after Begin is called and before we actually draw our sprites to the
screen. We will discuss this in more detail in the next chapter.
The rest of the sort modes will update the graphics device settings when End is called on
the SpriteBatch instead of Begin. This means there is only one call out to the graphics
device. The Deferred sort mode is like Immediate in that it does not do any sorting, it just
defers talking to the graphics device until the end of the process.
The next two sort modes are BackToFront and FrontToBack. When we draw our sprites we
can set our layer depth of that sprite. That value is a float between 0.0 and 1.0. The sprites
will draw in this order for the two modes. BackToFront is typically used for transparent
sprites and FrontToBack is typically used for nontransparent (opaque) sprites.
Finally, we can pass in Texture as a sort mode to our sprite batch’s Begin method. The
Texture sort mode will check to see all of the draws that are required and will sort them
so that the graphics device does not need to have its texture changed for each draw if
possible. For example, if we have five sprites drawing and three of them use the same
texture (could be different parts of the same texture) then the graphics device is sent the
texture and then the three draws. Then the other two draws occur with their textures.
This can really help performance. However, we might need foreground and background
images in the same texture. Sorting by texture alone is going to give us good performance,
but we need to also sort by our layer depth. Fortunately, we can set up two sprite
batches at the same time (as long as we are not using Immediate sort mode).
So we could have our first batch sort by texture and our second batch sort by layer depth
(BackToFront or FrontToBack). We can then draw our items including the layer depth
value, and as long as we call End on our sprite batches in the appropriate order our screen
will display as we expect and the performance will be good as well. Because the End
method is what actually does the drawing, we need to make sure we call them in order
from background to foreground. It is best to draw our opaque sprites first in one batch
and then our transparent sprites after that.
Save State Modes
As we complete different tasks inside of our Draw method, we might need to change
settings on our graphics device. For example, we might want our depth buffer to be on
when we are drawing certain items and off when drawing other items. When the sprite
batch is executed (when Begin is called in Immediate sort mode, when End is called for all
others) the graphics device will have the properties in Table 9.1 modified. We might want
to save our properties so we can reset them when the sprite batch is done.
174 CHAPTER 9 2D Basics
SaveStateMode.SaveState does exactly that. The other option is SaveStateMode.None,
which is the default and does not save any state. It is quicker if we just reset the states
ourselves if needed, especially on the Xbox 360.
TABLE 9.1 The SpriteBatch.Begin Method Modifies These Graphics Device Properties
Property Value
RenderState.CullMode CullCounterClockwiseFace
RenderState.DepthBufferEnable False
RenderState.AlphaBlendEnable True
RenderState.AlphaTestEnable True
RenderState.AlphaBlendOperation Add
RenderState.SourceBlend SourceAlpha
RenderState.DestinationBlend InverseSourceAlpha
RenderState.SeparateAlphaBlendEnabled False
RenderState.AlphaFunction Greater
RenderState.ReferenceAlpha 0
SamplerStates[0].AddressU Clamp
SamplerStates[0].AddressV Clamp
SamplerStates[0].MagFilter Linear
SamplerStates[0].MinFilter Linear
SamplerStates[0].MipFilter Linear
SamplerStates[0].MipMapLevelOfDetailBias 0
SamplerStates[0].MaxMipLevel 0
When we mix 2D and 3D together we will definitely want to set the following properties
before drawing our 3D content:
GraphicsDevice.RenderState.DepthBufferEnable = true;
GraphicsDevice.RenderState.AlphaBlendEnable = false;
GraphicsDevice.RenderState.AlphaTestEnable = false;
GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;

0 komentar: