1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft XNA Game Studio Creator’s Guide- P7 pps

30 294 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Microsoft Xna Game Studio Creator’s Guide
Trường học Microsoft
Chuyên ngành Game Development
Thể loại Hướng dẫn
Định dạng
Số trang 30
Dung lượng 306,63 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

There are several overrides for this method, but for ourneeds, all you have to do is pass in the array of indices: ref-SetDataT[] data; Managing Vertex Data with Index Buffers and Vertex

Trang 1

Once the indices have been defined, theSetData()method stores the index erences in the index buffer There are several overrides for this method, but for ourneeds, all you have to do is pass in the array of indices:

ref-SetData<T>(T[] data);

Managing Vertex Data with Index Buffers and Vertex

Buffers

By themselves, theVertexPositionColor,VertexPositionColorTexture,

VertexPositionTexture, and VertexPositionNormalTexture objectsthat you have used will not permit live updates to the position, color, texture, andnormal data.DynamicVertexBufferobjects in combination with index buffers,

on the other hand, will permit updates to large amounts of vertex data You are going

to want a structure like this when creating an effect such as water

When initialized, the constructor for the vertex buffer takes parameters for thecurrent graphics device, vertex type, element count, and buffer usage for memory al-location:

VertexBuffer( GraphicsDevice graphicsDevice,

Type vertexType, int elementCount, BufferUsage usage);

As explained above,BufferUsageoptions areNoneas the default,WriteOnly

for efficient writes to memory and for efficient drawing, andPointsfor point sprites.After the vertex data is loaded into an array, the vertex data is moved into the ver-tex buffer with theVertexBufferobject’sSetData()method There are severalvariations of this method The method used here only passes the array of vertices:SetData(VertexBuffer[] vertexBuffer)

Rendering Vertex Buffers with

an Index Buffer ReferenceThe draw method you use for dynamic vertex buffers—using index buffers—differs

in three ways from the draw methods you have used until now:

1. TheSetSource()method is used to set the vertex buffer that stores thegrid, the starting element, and the size of the vertex type in bytes:

graphics.GraphicsDevice.Vertices[0].SetSource(

VertexBuffer vertexBuffer, int startingElement, int sizeOfVertex );

Trang 2

2. TheGraphicsDevice’sIndicesobject is set with the corresponding

IndexBufferobject you defined during the program setup:

graphics.GraphicsDevice.Indices = indexBuffer;

3. TheDrawIndexedPrimitives()method is used to reference a series of

vertex subsets that are rendered in succession to draw the entire polygon or

surface.DrawIndexedPrimitives()is called for each vertex subset

graphics.GraphicsDevice.DrawIndexedPrimitives(

PrimitiveType primitiveType, int startingPointInVertexBuffer, int minimumVerticesInBuffer, int totalVerticesInBuffer, int indexBufferStartingPoint, int indexBufferEndPoint);

Grid Using Index Buffer Example

This code will implement an index buffer and dynamic vertex buffer to draw a

rect-angle from a set of vertices that is three vertices wide and five vertices long (see Figure

11-3) Drawing a rectangle with a set of vertices that uses index buffers might seem

like a lackluster chore, but don’t be fooled Index buffers have grit This little

exam-ple serves as the foundation for creating water waves in Chapter 12, creating terrain

with height detection in Chapter 25, and enabling better lighting across primitive

surfaces in Chapter 22

This example begins with either the MGHWinBaseCode or MGH360BaseCode

project in the BaseCode folder on this book’s website

Trang 3

To make this vertex reference system work, an index buffer to reference a grid ofvertices is required Also, a vertex buffer object is needed to store the vertices A ver-tex declaration type is used to set up the buffer when it is being initialized Add theseobject declarations to the top of your game class:

private IndexBuffer indexBuffer; // reference vertices

private VertexBuffer vertexBuffer; // vertex storage

The rows and columns used to draw the rectangle will be referenced with ers to help explain how the vertices are arranged Add these identifiers to the top ofthe game class

identifi-const int NUM_COLS = 3;

const int NUM_ROWS = 5;

Indices for referencing the vertex buffer are initialized when the program begins.The index buffer array is sized to store the total number of vertices contained in onesubset of the vertex buffer The code that you need to set up the index reference iscontained in theInitializeIndices()method Add this method to set up yourindex reference:

private void InitializeIndices(){

short[] indices; // indices for 1 subset indices = new short[2 * NUM_COLS]; // sized for 1 subset

indexBuffer = new IndexBuffer(

graphics.GraphicsDevice,// graphics device typeof(short), // data type is short indices.Length, // array size in bytes BufferUsage.WriteOnly); // memory allocation

// store indices for one subset of vertices

// see Figure 11-2 for the first subset of indices

Trang 4

C H A P T E R 1 1

AVertexBufferobject is initialized to store the vertices used to build the

primi-tive surface TheVertexBufferobject in this example is static and only stores the

vertices that are used to draw the grid or surface Still, the vertex buffer works in

con-junction with the index buffer as a reference to reduce the total number of vertices

that build the grid or surface This type of static vertex buffer is especially useful for

drawing lit objects or even terrain where many vertices are needed for detail When

setting up a vertex buffer, the vertex data is generated and is stored in a temporary

ar-ray Once all of the vertex values have been assembled, the vertex data is then stored

in the vertex buffer using theSetData()method To set up your vertices in this

effi-cient buffer, addInitializeVertexBuffer()to your game class:

private void InitializeVertexBuffer(){

vertexBuffer = new VertexBuffer(

graphics.GraphicsDevice, // graphics device typeof(VertexPositionColorTexture), // vertex type NUM_COLS * NUM_ROWS, // element count BufferUsage.WriteOnly); // memory use

// store vertices temporarily while initializing them

VertexPositionColorTexture[] vertex

= new VertexPositionColorTexture[NUM_ROWS*NUM_COLS];

// set grid width and height

float colWidth = (float)2 * BOUNDARY/(NUM_COLS - 1);

float rowHeight = (float)2 * BOUNDARY/(NUM_ROWS - 1);

// set position, color, and texture coordinates

for (int row=0; row < NUM_ROWS; row++){

for (int col=0; col < NUM_COLS; col++){

// set X, Y, Z

float X = -BOUNDARY + col * colWidth;

float Y = 0.0f;

float Z = -BOUNDARY + row * rowHeight;

vertex[col + row * NUM_COLS].Position = new Vector3(X, Y, Z);

// set color

vertex[col + row * NUM_COLS].Color = Color.White;

// set UV coordinates to map texture 1:1

float U = (float)col/(float)(NUM_COLS - 1);

float V = (float)row/(float)(NUM_ROWS - 1);

vertex[col + row * NUM_COLS].TextureCoordinate

Trang 5

= new Vector2(U, V);

} }

// commit data to vertex buffer

private void DrawIndexedGrid(){

// 5: draw object - select vertex type, vertex source, and indices

Trang 6

// draw grid one row at a time

for (int Z = 0; Z < NUM_ROWS - 1; Z++){

graphics.GraphicsDevice.DrawIndexedPrimitives(

PrimitiveType.LineStrip, // primitive

Z * NUM_COLS, // start point in buffer for drawing

0, // minimum vertices in vertex buffer

NUM_COLS * NUM_ROWS, // total vertices in buffer

2 * (NUM_COLS - 1)); // end point in index buffer

When you run the program, the grid appears as shown earlier in Figure 11-3

However, if the grid is drawn with triangle strips, the output will fill in the area

be-tween the vertices and display a rectangle This will happen if you change

LineStriptoTriangleStripinDrawIndexedGrid()

Bystanders might not be impressed that you just created a rectangular surface, but

don’t let that bother you Let’s put this demo on the backburner for now We’ll return

to it in later chapters to let it rip

C HAPTER 11 REVIEW EXERCISES

To get the most from this chapter, try out these chapter review exercises

1. Try the step-by-step example in this chapter, but this time change the

number of rows to 125 and the number of columns to 55 View the

project using line strips and triangle strips

2. Compared to methods that are used in previous chapters for storing vertices

without an index reference, how many vertices are saved when using an

index buffer to draw a grid that is 60 rows high and 35 rows wide?

C H A P T E R 1 1

Trang 7

3. The example presented in this chapter shows how to use a static

VertexBufferobject with index buffers What is the advantage

of doing this? What type of vertex buffer permits updates to vertices

at run time?

4. List three ways that theDrawIndexedPrimitives()method is differentfrom theDrawUserPrimitives()method

164

Trang 8

CHAPTER 12

Combining Images for Better Visual Effects

Trang 9

THIS chapter demonstrates various ways of combining images to gen-erate compelling visual effects; more specifically, sprites andmultitexturing will be discussed By the end of the chapter, you will be able to use im-age files that store more than one image frame to create cool heads-up display (HUD)animations in your 2D or 3D games You will also be able to blend two textures to-gether to generate intricate detail for effects such as terrain or a water simulation Al-though games are not defined solely by their aesthetics, no one has ever complainedthat a game’s graphics looked too good Your players will appreciate any effort youput into maximizing your visual effects

S PRITES

As discussed in Chapter 4, a sprite is an animated 2D image You can animate sprites

by moving them in the window Also, if your sprite has more than one frame, you canswap frames to animate them

Image Frame Swapping for 2D Animations

Image frame swapping creates an animation similar to old-style page-flipping tions used to create simple cartoons The sprite is animated at run time by adjustingthe texture’s UV coordinates at fixed time intervals Sprites store multiple imageframes because adjusting UV coordinates at run time—to switch image frames—isfaster than switching to a different image file

anima-For 3D games, a 2D sprite offers a very simple way to customize and animate theheads-up display, or a game dashboard This type of sprite could be used to create ananimated radar scope on the console of a flight simulation game

SpriteBatch

For the 2D effect, a sprite object is created with theSpriteBatchclass:

SpriteBatch spriteBatch = new SpriteBatch(GraphicsDevice);

ASpriteBatchobject is actually already included in the XNA template projectcode that is generated using the New Project dialog box For our purposes this is theonly one you will need

Primitive objects are not needed to display the image when usingSpriteBatch

methods As a result, setting up the sprite is easier than setting up textured primitivesurfaces; theSpriteBatchobject draws the image on its own For the 2D object, alldrawing is done between theSpriteBatchobject’sBegin()andEnd()methods

Trang 10

The syntax for theDraw()method is designed for drawing on a 2D window The

first parameter references theTexture2Dobject that stores the image file; the

sec-ond parameter references the position, height, and width of a rectangle in the 2D

window; and the third parameter references the starting pixel’s X and Y position in

the image and the height and width—in pixels—to be drawn The fourth parameter

sets the color of the sprite in case you want to shade it differently from the colors

al-ready in the image

Be aware that there are several other overrides forSpriteBatch.Draw();

how-ever, this is the one that we’ll be using for our examples:

If your 3D game uses 2D sprites, you need to be aware of how this will impact your

drawing routines The 2D S p r i t e B a t c h automatically resets the

GraphicsDevice’s render states to draw 2D graphics in the window While this is

helpful, if the settings are not restored to enable 3D rendering, you may not see your

3D graphics—and if you do, they may not display properly Ideally, when rendering

yourSpriteBatchobjects, you should draw them last in theDraw()method so

that they layer on top of the 3D graphics

Trang 11

Your graphics device states should be reset to turn off transparency and to able 3D graphics after drawing with theSpriteBatch You must also reset the cull-ing option back to the default used by your game Culling designates the face of anobject that is not drawn, so it should be the face that is not visible to the user Cullingoptions include CullClockwiseFace, CullCounterClockwiseFace, and

re-en-None The base code usesCullMode.Noneto prevent your surfaces from pearing just in case you mistakenly arrange your vertices in the same order as yourculling option However, for performance gains, you definitely will want to cullnonvisible sides of your surfaces when you are rendering large groups of vertices, so

disap-be aware that you have this option

The following code for resetting the state belongs in theDraw()method right ter you draw withSpriteBatch:

af-graphics.GraphicsDevice.RenderState.CullMode = CullMode.None; // no cull graphics.RenderState.DepthBufferEnable = true; // enable 3D on Z graphics.RenderState.AlphaBlendEnable = false; // end transparent graphics.RenderState.AlphaTestEnable = false; // per pixel test

// enable tiling graphics.SamplerStates[0].AddressU = TextureAddressMode.Wrap;

graphics.SamplerStates[0].AddressV = TextureAddressMode.Wrap;

Instead of manually resetting the render states, you can add

SaveStateMode.SaveStateas a parameter for theSpriteBatchobject’sgin()instruction when drawing it This will restore the render states back to theiroriginal settings before the sprite is drawn It’s important to note that this saves andrestores all the render states, so it’s more costly than restoring the render states byhand:

Be-spriteBatch.Begin(SpriteBlendMode.AlphaBlend,

SpriteSortMode.Immediate,SaveStateMode.SaveState);

Rendering Sprites Within the Title Safe Region

of the WindowWhen running games on the Xbox 360, some televisions will only show 80 percent ofthe game window The PC shows 100 percent of the window, so some adjustmentsmay be needed to account for this platform difference Here is a routine that returnsthe bottom-left pixel in the window for drawing aSpriteBatchobject so that it ispositioned properly in the visible region of the window regardless of where the pro-ject runs:

168

Trang 12

Rectangle TitleSafeRegion(Texture2D texture, int numFrames){

int windowWidth = Window.ClientBounds.Width;

int windowHeight = Window.ClientBounds.Height;

// some televisions only show 80% of the window

const float UNSAFEAREA = 0.2f;

const float MARGIN = UNSAFEAREA / 2.0f;

// return bounding margins

int top, left, height, width;

left = (int)(windowWidth * MARGIN);

top = (int)(windowHeight * MARGIN);

width = (int)((1.0f - UNSAFEAREA) * windowWidth - texture.Width);

height = (int)((1.0f - UNSAFEAREA) * windowHeight

- texture.Height/numFrames);

return new Rectangle(left, top, width, height);}

I MAGE FRAME ANIMATIONS

TheSpriteBatchclass is limited to drawing images that are flat To perform image

frame swapping inside the 3D world, you must use textured primitives without the

SpriteBatch class to animate your textures Animating textures through image

frame swapping is useful for effects such as flashing signs and blinking lights inside

your world When a sprite is drawn in a 3D environment, the image frames are

swapped at regular intervals by adjusting the UV coordinates

Sprite on the Heads-Up-Display Example

This example animates a two-frame sprite In this example, theSpriteBatchclass

is used to swap frames within the image so that it appears in the 2D game window as

a blinking light Figure 12-1 shows the sprite image on the right and the warning light

animation on the left The two images on the left will be swapped at each interval To

the gamer, the light appears to blink on and off every 0.5 seconds

This example begins with either the MGHWinBaseCode project or the

MGH360BaseCode project found in the BaseCode folder on this book’s website A

Texture2Dobject is used to load and reference the image To try this example, first

add this declaration to the top of the game class:

private Texture2D spriteTexture;

Trang 13

A timer is used to trigger the frame change for the sprite, which creates the ing light animation To implement the timer, class-level declarations are required

blink-to sblink-tore the frame number (frameNum), the time spent in the current timer

inter-v a l (i n t e r v a l T i m e), and the time lapse since the last interval(previousIntervalTime):

int frameNum = 1;

private double intervalTime = 0; // time in current interval

private double previousIntervalTime = 0; // interval time at last frame

Next, theTimer()method is added to the methods section to check for the pletion of each 0.5-second interval TheTimer()method calculates the remainder

com-of the amount com-of time since the interval started, divided by 500 milliseconds Whenthe remainder has increased compared to the remainder calculated for the previousframe, the interval is incomplete When the remainder has decreased since the previ-ous frame, a new interval has been entered, and theTimer() method returns a posi-tive result The positive result triggers a frame swap for the sprite Checking theremainders in this manner prevents the variable from growing beyond the variable’sstorage capacity, because it is reset every interval Even though the remainder is usu-ally positive when a new interval is detected, the overshot from the interval start isminiscule, and tracking the remainder makes this algorithm self-correcting In thismanner, theTimer()implements animations that appear to be synchronized withreal time:

170

An animated sprite in the game window

Trang 14

bool Timer(GameTime gameTime){

bool resetInterval = false;

// add time lapse between frames and keep value between 0 & 500 ms

The warninglight.png file is also loaded by code into theTexture2Dobject in the

LoadContent()method The warninglight.png file can be obtained from the

Im-ages folder on this book’s website The image needs to be added to the ImIm-ages folder

in your project so it can be loaded by the content pipeline To reference this in your

project, right-click the Images folder in the Solution Explorer, choose Add, and then

select Existing Item A dialog will appear that allows you to navigate to the image and

select it Once the warninglight.png file is selected, it will appear in your project

within the Solution Explorer, and you can then load it with the following instruction:

spriteTexture = Content.Load<Texture2D>("Images\\warninglight");

To ensure that the sprite is positioned properly in the game window, add the

routine that was discussed earlier to retrieve the starting pixel for drawing in the

window:

Rectangle TitleSafeRegion(Texture2D texture, int numFrames){

int windowWidth = Window.ClientBounds.Width;

int windowHeight = Window.ClientBounds.Height;

// some televisions only show 80% of the window

const float UNSAFEAREA = 0.2f;

const float MARGIN = UNSAFEAREA / 2.0f;

// return bounding margins

int top, left, height, width;

left = (int)(windowWidth * MARGIN);

top = (int)(windowHeight * MARGIN);

Trang 15

width = (int)((1.0f - UNSAFEAREA) * windowWidth - texture.Width); height = (int)((1.0f - UNSAFEAREA) * windowHeight

- texture.Height/numFrames);

return new Rectangle(left, top, width, height);

}

The next method to add is DrawAnimatedHud() DrawAnimatedHud()

checks the timer to see if the set interval has completed If the timer returns atrue

value—indicating that it just ticked into a new interval—the frame in the image is cremented or reset TheSpriteBatchobject calls theBegin()method to start thedrawing Begin()allows the developer to set theSpriteBlendModeoption tospecify the type of blending This could include:

in- AlphaBlend For removing masked pixels

 Additive For summing source and destination colors

 None For standard rendering

If you want to remove the transparent pixels, you can use

SpriteBlendMode.AlphaBlendas a parameter in theSpriteBatch’sBegin()

method The picture in the warninglight.png file was created with a transparent ground, so the pixels will not appear when the image is drawn with alpha blending.TheSpriteBatch’sDraw()method applies four parameters The first parame-ter is thegameTimeobject, which is applied to ensure that the animation runs at aconsistent speed The second parameter is the X and Y position for the starting pixelwhere the sprite is to be drawn ATexture2Dobject is passed as a third parameter

back-to allow you back-to set the width and height of the area back-to be drawn The fourth ter is the total number of frames, which allows you to split up the image so it is drawnone section at a time To draw the sprite so it is positioned properly in the window,addDrawAnimatedHud()to your project:

parame-void DrawAnimatedHUD(GameTime gameTime, Vector2 startPixel,

Texture2D texture, int numFrames){

// get width and height of the section of the image to be drawn

int width = texture.Width; // measured in pixels

int height = texture.Height / numFrames; // measured in pixels

if (Timer(gameTime)){

frameNum += 1; // swap image frame frameNum = frameNum%numFrames; // set to 0 after last frame }

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

spriteBatch.Draw(

172

Ngày đăng: 02/07/2014, 06:20