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

Microsoft XNA Game Studio Creator’s Guide- P18 potx

30 206 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 đề Adding Audio to Your Game
Trường học Microsoft Corporation
Chuyên ngành Game Development
Thể loại sách hướng dẫn tạo game
Định dạng
Số trang 30
Dung lượng 264,85 KB

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

Nội dung

The Viewport class is used to create a viewport object: sim-Viewport viewport = new sim-Viewport; Each viewport object has several properties to set the position and area covered inthe g

Trang 1

in a SoundEffect object A SoundEffectInstance is created from this SoundEffect ject which gives you the ability to loop, pause, and resume your individual sound ef-fects The firing audio is loaded into a SoundEffect object which is used later forplayback whenever theBbutton is pressed.

ob-// load and play background audio

backgroundAudio = Content.Load<Song>("Audio\\telemetricBeep"); MediaPlayer.Play(backgroundAudio);

MediaPlayer.IsRepeating = true;

// load and play engine as SoundEffectInstance for playback control

engineSound = Content.Load<SoundEffect>("Audio\\engine0");

engineInstance = engineSound.Play(VOLUME, PITCH, PAN, LOOP);

// load fire sound effect for playback later

fireSound = Content.Load<SoundEffect>("Audio\\fire");

Lastly, inside Update(), you can add this code to trigger the firing audio whenevertheBbutton is pressed This code will also allow your players to pause and resume theship engine and telemetric beep whenever they press the center of the Zune pad.// get new game pad states

GamePadState gpCurrent = GamePad.GetState(PlayerIndex.One);

// play fire sound at each new B button press event

if (gpCurrent.IsButtonDown(Buttons.B)&& gpPrevious.IsButtonUp(Buttons.B)) fireSound.Play(VOLUME, PITCH, PAN, !LOOP);

// toggle engine audio pause and resume states for DPad.Down events

if (gpCurrent.Buttons.A == ButtonState.Pressed &&

Trang 2

We are sure you will notice how much more enjoyable your games are when you

add audio using any of the alternatives provided in XNA

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

1. Implement the step-by-step example in this chapter to create your own

XACT audio project file Then load your audio and play it from code

2. Using the solution for the arcing projectiles example from Chapter 19, add

in audio to handle a launch sound and a 3D audio-enabled explosion

sound when the rocket hits the ground

3. Using the solution for “Adding a Car as a Third-Person Object” from

Chapter 14, add a looping noise that repeats to create a continuous engine

sound whenever the car moves forward or backward

Trang 4

CHAPTER 28

Multiplayer Gaming

Trang 5

You could actually split the screen into more than four sections, but the controllerlimit is four You might want additional dimensions, though, if you were to show dif-ferent views of the world For example, maybe you want to create a radar screen with

an aerial view of your entire world in addition to the main viewer for navigation Thesplit-screen technique offers many useful possibilities for dividing up the graphicsthat are rendered in your window

The code changes required to enable a split-screen game are surprisingly simple.TheViewportclass makes it easy to split your screen And if your camera is care-fully designed, as it is in the examples this book, you can easily create separate in-stances to give each additional player control over her own viewport

A viewport is a section of the window that you use to draw a scene from a specific

view As you’ll see, using theViewportclass to split the screen is actually very ple The Viewport class is used to create a viewport object:

sim-Viewport viewport = new sim-Viewport();

Each viewport object has several properties to set the position and area covered inthe game window Each section of the window is assigned values for the startingtop-left pixel, the width and height in pixels, and the depth for clipping, so your phys-ical game objects draw properly:

int viewport.X // top left pixel X coordinate

int viewport.Y // top left pixel Y coordinate

int viewport.Width // width in pixels

int viewport.Height // height in pixels

float viewport.MinDepth // minimum depth of clip volume (usually 0) float viewport.MaxDepth // maximum depth of clip volume (usually 1)

492

Trang 6

The bulk of the code changes needed to convert to a multiplayer game are in

han-dling a separate instance of the camera for each player However, even this task is

rel-atively simple

When your multiplayer games are rendered on the Xbox 360, your viewports may

be truncated on the televisions where they are played In fact, it is possible that up to

20 percent of the screen will be hidden This issue can be addressed by implementing

a routine to create margins that equal 10 percent of the window height at the top and

bottom and 10 percent of the window width for the left and right An example of

how to do this is presented in the demonstration later in this chapter

PLAYER

To give each user the ability to navigate through the world, a separate camera

in-stance is required for each player The camera inin-stance gives the players the ability to

change their position and view within the 3D world

Adjusting the View

For the graphics engine used in this book, whenever a player moves the mouse or

shifts the right thumbstick, he changes his view In other words, his position in the

world stays the same, but hisLookdirection changes as his view target changes A

separate view is needed for each player in the game For example, in a racing game

you might need to focus your camera to watch the contours of a hairpin turn so you

don’t crash Your friend might need to watch out for an oil slick to maintain control

of the car, and yet another player might be focused on the finish line

When you assign a separate viewport for each player, every object that is drawn in

the viewport must be rendered according to that player’s view Even the base code,

which draws nothing but ground, must draw the ground once for each viewport

ac-cording to the viewport owner’sLookdirection To handle this need for separate

views, the camera’s view matrix is updated separately for each player

Adjusting the Projection

The Projection matrix transforms vector coordinates into clip space (a cone that the

viewer sees through) In a split-screen window, you must also adjust the projection to

match the area in each viewport If you do not resize the perspective’s aspect ratio

properly, you could end up with a viewport(s) that displays everything in a bloated

manner—as if the scene were either viewed through a fish-eye lens or in a house of

mirrors The aspect ratio considers the viewport width relative to the viewport

height Until now we have used the window width over height to calculate this ratio

Now though, the current viewport’s width over height is needed

Trang 7

To implement this modification for a split-screen environment, for each differentviewport size on display, a Projection matrix is defined when the application beginswith the following syntax:

// parameters are field of view, viewport w/h, near clip, far clip

Matrix projection = Matrix.CreatePerspectiveFieldOfView(

float fieldOfView, float aspectRatio, float nearClip, float farClip)

If you divide the window into top and bottom viewports, the aspect ratio comes this:

be-Window.ClientBounds.Width/(Window.ClientBounds.Height/2)

It is possible to have up to four game controllers on one Xbox 360 or PC, so youcould write code to handle up to four different players and split the screen accord-ingly at run time For the PC, you can even use the mouse and keyboard as one ofthese inputs Handling the different controllers is easy with the GamePadState

class because each controller is referenced by a separate instance of the class Thestates for each control on the game pad can be obtained using the GetState()

method with aPlayerIndexattribute as a parameter to specify each player

This example demonstrates multiplayer 3D gaming in a split-screen environment.Two aliens will be rendered and controlled in two separate viewports Each playerhas her own viewport and is given control of one alien’s spaceship, which moves withher camera as she travels Figure 28-1 shows a split screen for two players Eachplayer can control her view and position inside the viewport and ultimately travelwithin the world independently of the other player

A multiplayer racing game or first-person shooter game uses the same code tion, so converting the logic to suit a different type of 3D multiplayer game is a simpletask Converting this logic to handle more than two players is also straightforward.When you run this code on the Xbox 360, you will be able to handle two players,each with her own controller When the code is run on the PC, you can handle eithertwo controllers, or one controller and a mouse/keyboard combination If you runthis code on the PC with only a mouse and keyboard, you will be able to control one

founda-of the viewports, but the other viewport will be disabled until a controller is nected

Trang 8

con-This example begins with either the MGHWinBaseCode or MGH360BaseCode

project, which can be found in the BaseCode folder in the download available from

this book’s website

To enable a two-player game, and to identify each player, you declare the

NUMPLAYERS,ALIEN0, andALIEN1definitions at the top of the game class:

const int NUMPLAYERS = 2;

const int ALIEN0 = 0; const int ALIEN1 = 1;

To give each player control to move through the 3D environment, and to allow

them to view it independently, you declare an array with two separate instances for

the camera Use this revision to replace the existing camera object declaration:

private Camera[] cam = new Camera[NUMPLAYERS];

Trang 9

When you’re initializing each camera, the starting position and view position foreach person needs to be different Otherwise, with just a default position and view,when the game begins, the players would all be positioned in the same place, one ontop of the other To set the players up at opposite ends of the world, and to have themlooking at their opponent, each instance of the camera is initialized with parameters

to set the position and view

An override to the camera constructor allows you to set the position and view ofthe camera when it is initialized for each player:

public Camera(Vector3 startPosition, Vector3 startView){

Vector3 position, view;

position = new Vector3( 0.5f, 0.9f, BOUNDARY - 0.5f);

view = new Vector3( 0.5f, 0.7f, BOUNDARY - 1.0f);

cam[0] = new Camera(position, view);

position = new Vector3(-0.5f, 0.9f,-BOUNDARY + 0.5f);

view = new Vector3(-0.5f, 0.7f,-BOUNDARY + 1.0f);

cam[1] = new Camera(position, view);

As mentioned earlier in this chapter, because both viewport heights are half the tual window height, the aspect-ratio parameter in the Projection matrix must be ad-justed The aspect ratio for the projection becomes (width/(height/2)) To apply this

ac-to the Projection matrix, after initializing each camera, replace the call ac-to initializethe Projection matrix in theInitialize()method:

for (int player = 0; player < 2; player++)

cam[player].SetProjection(Window.ClientBounds.Width,

Window.ClientBounds.Height/2);

Now that you have properly set up the projection matrix for a multiplayer ronment, you will need to comment out the original call statement to initialize theprojection matrix You can find this call statement inside the

envi-InitializeBaseCode()method of the game class:

Trang 10

// cam.setProjection(Window.ClientBounds.Width,

// Window.ClientBounds.Height);

A routine is needed in the game class to determine how many game controllers are

connected so it can assign control to both players accordingly The

TotalControllersUsed()method needed for this example only considers a

sit-uation where up to two controllers are used:

TheChangeView(),Move(),Strafe(), andDrawGround()methods inside

the game class need to be modified so they can be used for each player Since each

player is a viewport owner, these method headers must be adjusted to accept the

player number, as follows:

Vector2 ChangeView(GameTime gameTime, int player)

float Move(int player)

float Strafe(int player)

void DrawGround(int player)

TheChangeView(),Move(), andStrafe()methods are called once for each

viewport owner These methods must then select the correct input device to allow

each player to control their view and position

For this example, by default, aGamePadStateobject is set for the first player

us-ing the PlayerIndex.One parameter value regardless of whether a controller is

connected or not If zero or one controllers are connected on a PC, the mouse is

desig-nated for the first player to control their viewport If two game controllers are

con-nected on the PC, theGamePadStateobject is set for the second player using the

PlayerIndex.Twoparameter

The following code must be added in the ChangeView(), Move(), and

Strafe()methods after theGamePadStateobject,gp, is declared:

bool useMouse = false;

int totalControllers = TotalControllersUsed();

Trang 11

// when fewer than two controllers connected use mouse for 1st player

if (totalControllers <2 && player == 0)

useMouse = true;

// when 2 controllers connected use 2nd controller for 2nd player

else if (totalControllers == 2 && player == 1)

gp = GamePad.GetState(PlayerIndex.Two);

Also, to ensure that code for the game pad is executed on the PC when either one

or two controllers are connected, inside the ChangeView(), Move(), and

Strafe()methods, replace:

if(gp.IsConnected == true)

withif(!useMouse)

The code that sets the WorldViewProjection matrix insideDrawGround()mustalso be adjusted according to the player’s view This adjustment sets theWorldViewProjection matrix so it is drawn according to each viewport owner’sview:

textureEffectWVP.SetValue(world * cam[player].viewMatrix

* cam[player].projectionMatrix);

Because each player has a separate instance of the camera, each camera must beupdated separately; this gives the players the ability to travel independently in thegame world To enable this, insideUpdate(), replace the code that handles the cam-era’s time tracking, forward movement, backward movement, and strafing with thisrevision to update these values for each player:

for (int player = 0; player < NUMPLAYERS; player++){

// update timer in camera to regulate camera speed

When the viewports are being drawn (while your code is run on the Xbox 360), it

is possible that the full window may not be visible—it may fall outside the title-saferegion As discussed previously in examples where 2D graphics are used, on some

Trang 12

televisions, this nonvisible range may be as high as 20 percent To adjust for this

pos-sibility, the starting top-left pixel that is used as the viewport should allow for this

po-tential difference When viewports are used, you are going to want to account for this

possibility so that your 3D graphics do not appear to be off center if truncation

oc-curs To fix this, add this version of theTitleSafeRegion()method to obtain the

bounding margins for the top viewport These margins in turn will be used to

deter-mine the starting top-left pixel for each viewport in this demonstration:

Rectangle TitleSafeRegion(){

int windowWidth = Window.ClientBounds.Width;

int windowHeight = Window.ClientBounds.Height;

#if Xbox

// some televisions only show 80% of the window

Vector2 start = new Vector2(); // starting pixel X & Y

const float UNSAFEAREA = 0.2f; // 80% not visible on

// Xbox 360 start.X = windowWidth * UNSAFEAREA/2.0f;

start.Y = windowHeight * UNSAFEAREA/2.0f;

// ensure viewport drawn in safe region on all sides

return new Rectangle(

// PC show the entire region

return new Rectangle(0, 0, windowWidth, windowHeight/2);

}

The next method needed in your game class is the CurrentViewport()method to

set your viewport In a multiplayer game, theDraw()method must trigger rendering

of the entire scene for each viewport Before drawing each viewport, you must set the

top-left pixel where the viewport begins, the height and width properties for each

viewport, and the clip minimum and maximum If the clip minimum and maximum

values are not set between 0 and 1, your 3D models will not render properly:

Viewport CurrentViewport(int player){

Viewport viewport = new Viewport();

Rectangle safeRegion = TitleSafeRegion();

Vector2 startPixel = new Vector2((float)safeRegion.Left,

(float)safeRegion.Top);

Trang 13

// get starting top left pixel for viewport

if (player == 1) // 2nd player - bottom startPixel.Y += (float)safeRegion.Height;

// assign viewport properties

viewport.X = (int)startPixel.X; // top left pixel X viewport.Y = (int)startPixel.Y; // top left pixel Y viewport.Width = safeRegion.Width; // pixel width

viewport.Height = safeRegion.Height; // pixel height

viewport.MinDepth = 0.0f; // depth is between viewport.MaxDepth = 1.0f; // 0 & 1 so models

// appear properly return viewport;

}

When multiple viewports are used, each one is rendered separately In effect, thesame scene is drawn more than once With careful planning, the same methods can beused for drawing your primitive objects and models Note also that when drawingwith multiple viewports, the viewport is set first before the viewport is cleared Thedrawing is performed afterward

Replace the existingDraw()method with this revision to draw all objects in eachviewport according to the view and perspective of each player:

protected override void Draw(GameTime gameTime){

for (int player = 0; player < NUMPLAYERS; player++) {

// set the viewport before clearing screen graphics.GraphicsDevice.Viewport = CurrentViewport(player);

graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// draw objects DrawGround(player);

Trang 14

For this example, you can use the alien models in the Models folder in the book’s

download To do this, obtain the alien0.fbx, alien1.fbx, and spaceA.bmp files from

the Models folder Create a Models folder in your project and reference the fbx files

from the Solution Explorer

To load these models and to control their transformations, declarations for the

model objects and their bone-transformation matrices are required at the top of the

game class:

Model alien0Model; Model alien1Model;

Matrix[] alien0Matrix; Matrix[] alien1Matrix;

The code used to load these two models and their accompanying transformation

matrices is contained in the InitializeAliens()method To initialize the models, add

this method to your game class:

To load the aliens when the program begins, add the call statement

InitializeAliens()to theInitialize()method:

InitializeAliens();

For this two-player game, one alien and its spaceship are controlled by each

player Each alien’s spaceship moves with the player’s camera To rotate the alien

about the Y axis—so it always points in the direction it is traveling—use the

follow-ing method to calculate the angle of direction based on the camera’sLookdirection:

float RotationAngle(Vector3 view, Vector3 position){

Vector3 look = view - position;

return (float)Math.Atan2((double)look.X, (double)look.Z);

}

To save on code, the same method is used to draw both aliens When these items

are rendered in a viewport, this method is called once for each model This process is

Trang 15

repeated for each player For this example,alien0’s position and angle of tion is based on the first player’s camera.Alien1’s position and orientation is based

orienta-on the secorienta-ond player’s camera The view is adjusted for each player The rest of theroutine is identical to the routines you have already used in this book for drawingmodels

void DrawAliens(int player, Model model, int modelNum){

foreach (ModelMesh mesh in model.Meshes){

// 1: declare matrices Matrix world, scale, rotationY, translation, translationOrbit;

// 2: initialize matrices scale = Matrix.CreateScale(0.5f, 0.5f, 0.5f);

translation = Matrix.CreateTranslation(Vector3.Zero);

rotationY = Matrix.CreateRotationY(MathHelper.Pi);

translationOrbit = Matrix.CreateTranslation(0.0f, 0.0f, 1.0f); translation = Matrix.CreateTranslation( // one alien

cam[modelNum].position.X, // is located cam[modelNum].position.Y - 0.6f, // at each cam[modelNum].position.Z); // camera float angleY = RotationAngle(cam[modelNum].view,

cam[modelNum].position);

rotationY = Matrix.CreateRotationY(angleY);

// 3: build cumulative world matrix using I.S.R.O.T sequence // identity, scale, rotate, orbit(translate & rotate), translate world = scale * translationOrbit * rotationY * translation;

foreach (BasicEffect effect in mesh.Effects){

// 4: pass wvp to shader effect.View = cam[player].viewMatrix;

switch (modelNum){

case ALIEN0:

effect.World = alien0Matrix[mesh.ParentBone.Index] * world; break; case ALIEN1:

effect.World = alien1Matrix[mesh.ParentBone.Index] * world; break; }

effect.Projection = cam[player].projectionMatrix;

// 4b: set lighting effect.EnableDefaultLighting();

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

TỪ KHÓA LIÊN QUAN