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

Microsoft XNA Game Studio Creator’s Guide- P12 potx

30 358 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
Thể loại Giáo trình hướng dẫn tạo trò chơi
Định dạng
Số trang 30
Dung lượng 291,89 KB

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

Nội dung

At the time of launch, the rocket is given a position and direction to start it on an outward journey from the tip of the rocket launcher.. To allow access to these variablesthroughout t

Trang 1

Figure 19-3 shows several rockets at various elevations (on the Y axis) and at ferent stages of flight Over time, the projectiles lose momentum and gravity pullsthem to the ground The overall effect creates a nice arcing projectile path.

dif-Game developers will often use real-world physics to create more realistic ics effects The physical properties that they consider may include gravity, friction,force, velocity, acceleration, viscosity, and much more In case you’re wondering,game development companies will often implement pseudo-physics in their algo-rithms As long as the effect looks correct and is efficient, an approximation of thelaws of physics is usually the faster and more effective alternative After all, as a simu-lation approaches reality, it can become so complex that it loses its value However,even when the code deviates from the laws of physics, realistic algorithms usuallyconsider some portion of the real physical model

graph-Once the launch velocity and direction have been obtained, the effect of gravitycan be computed and the X, Y, and Z positions of the projectile can be calculatedover time The X and Z positions are calculated using the same equations as the Lin-ear Projectile algorithm to obtain the projectile’s position over time:

X t = X start + V x * t

Z t = Z start + V z * t

The Arcing Projectile algorithm treats the calculation of the Y position over time

as a special case that also considers gravity Initially, the projectile’s velocity is erful enough to defy gravity—otherwise, there would be insufficient energy to launch

pow-F I G U R E 1 9 - 3

Considering the effect of gravity over time

Trang 2

the projectile into the air However, over time, the projectile loses its momentum and

gravity becomes the strongest force on the object This gravitational pull is defined by

a constant value of acceleration, g, which represents the Earth’s gravity The

ac-cepted value for g equals 9.8 meters / second2

(32 ft/s2

) After the Earth’s gravity is tored in, the equation used for calculating the Y position over time becomes:

fac-Y t = Y start + V y * t - 0.5 * g * t2

Implementing these projectile algorithms in code is simple The first example in

this chapter implements the Linear Projectile algorithm Then, in the example that

follows, the Linear Projectile algorithm is converted into an Arcing Projectile

algo-rithm

This example demonstrates how to add projectiles that can be launched on a linear

path from a rocket launcher, as shown back in Figure 19-1

In this example, you will shoot ten rockets into the air at a time When a trigger or

spacebar event occurs, the first available rocket (that is not already in flight) is

launched At the time of launch, the rocket is given a position and direction to start it

on an outward journey from the tip of the rocket launcher The rocket launcher’s

po-sition and direction are based on the camera’s current popo-sition andLookdirection

Also, during the launch, the activation state for the projectile is set totrue, and

re-mains set totrueuntil the projectile reaches the end of the path The activation state

prevents the projectile from being reused while it is in flight The projectile properties

are reset every time the projectile is launched

This example begins with either the MGHWinBaseCode or MGH360BaseCode

project located in the BaseCode folder on this book’s website

You will create aProjectile class to assist with the implementation of your

projectiles You will useProjectileto keep track of each rocket and to update its

position TheProjectile class can be created from scratch in the Solution

Ex-plorer To generate it, right-click the project and choose Add New Item Then,

choose the Code File icon and enter Projectile.cs as the Name in the Add New Item

di-alog When you click Add, GS will generate an empty Projectile.cs file

First, add the following code shell to start your Projectile class:

Trang 3

Class-level declarations are also required for storing the position, direction, andactivation state of each projectile An additional variable, for storing the size of theworld, enables a check to determine whether the projectile has flown out of sight.This tells you when to deactivate the projectile To allow access to these variablesthroughout the class, we place their declarations at the top of theProjectileclass(inside the class declaration):

public Vector3 position, previousPosition; // rocket position

private Vector3 speed; // relative change in X,Y,Z public Matrix directionMatrix; // direction transformations public bool active; // visibility

private float boundary; // edge of world on X and Z private float seconds; // seconds since launch

private Vector3 startPosition; // launch position

When the program begins, each projectile needs to be created only once After theyare created, the projectiles remain inactive until the user launches them Later, youwill add a method to deactivate a projectile when it flies past the boundaries of theworld To set the projectile flight range and activation state when the projectile is ini-tialized, add this constructor to theProjectileclass:

public Projectile(float border){

public void Launch(Vector3 look, Vector3 start){

position = startPosition = start; // start at camera

speed = Vector3.Normalize(look); // unitize direction

active = true; // make visible

seconds = 0.0f; // used with gravity only

}

As discussed in Chapter 8, an object’s direction can be calculated from the object’sspeed vector AddingSetDirectionMatrix()to yourProjectile class will

Trang 4

provide the method you need to make your rocket point in the direction it is

travel-ing This routine applies to both the Linear Projectile algorithm and the Arcing

Pro-jectile algorithm For the Linear ProPro-jectile algorithm, the rocket direction remains

constant as the rocket travels outwards For the Arcing Projectile algorithm,

SetDirectionMatrix()will launch the rocket with the original launcher

direc-tion, and then it will gradually drop the rocket, nose downward, as the gravitational

pull takes over:

private void SetDirectionMatrix(){

Vector3 Look = position - previousPosition;

Look.Normalize();

Vector3 Up = new Vector3(0.0f, 1.0f, 0.0f); // fake Up to get

Vector3 Right = Vector3.Cross(Up, Look);

Right.Normalize();

Up = Vector3.Cross(Look, Right); // calculate Up with

Up.Normalize(); // correct vectors

Matrix matrix = new Matrix(); // compute direction matrix

The projectile’s position is updated before being drawn each frame Also, in every

frame, the projectile’s position is incremented by a time-scaled direction vector,

which ensures that the rocket flies in the path set by the camera when the rocket is

launched When the projectile location exceeds one of the outer boundaries, it is

de-activated so that it can be dede-activated and made available for the next launch The

U p d a t e P r o j e c t i l e ( ) method implements this routine Adding

UpdateProjectile()to the projectile class ensures that your projectile positions

are updated while they are active The method also deactivates the projectiles after

they reach the outer limits of your world

public void UpdateProjectile(GameTime gameTime){

previousPosition = position; // archive last position

position += speed // update current position

* (float)gameTime.ElapsedGameTime.Milliseconds/90.0f;

SetDirectionMatrix();

Trang 5

// deactivate if outer border exceeded on X or Z

if (position.Z > 2.0f * boundary || position.X > 2.0f * boundary || position.Z <-2.0f * boundary || position.X <-2.0f * boundary) active = false;

}

TheProjectileclass for a Linear Projectile algorithm is now complete, so youcan reference it from Game1.cs Adding the namespace reference at the top of theGame1.cs file enables your use of this new class:

using Projectiles;

To use theProjectileclass, you need to declare instances of it inside the gameclass An array of 10 is used here, but if you wanted, you could create a more dynamicstructure with anArrayList:

const int NUM_ROCKETS = 10;

private Projectile[] rocket = new Projectile[NUM_ROCKETS];

With these declarations, you should set up each of these ten projectiles from theInitialize() method when the program begins Passing the size of the world tothe constructor will allow us to deactivate the rocket later when it flies beyond theouter boundaries of the world:

for (int i = 0; i < NUM_ROCKETS; i++)

rocket[i] = new Projectile(BOUNDARY);

To make this example more interesting, a model of a rocket will be used for theprojectiles To reference this model in the game class, add a class-level declaration forthe model and the matrix to the game class Also, the starting Y value used in therocket and launcher transformations is tracked with the variable declared here asBASE_HEIGHT:

Model rocketModel; Matrix[] rocketMatrix;

Model launcherModel; Matrix[] launcherMatrix;

const float BASE_HEIGHT = 0.6f; // start height for models

The rocket and rocket launcher models are loaded from the rocket.fbx andlauncher.fbx files Adding theInitializeModels()method to your game classprovides the code to load these models using theContentManagerobject The di-rectory path in this code assumes you have copied the rocket.fbx, rocket.bmp,launcher.fbx, and launcher.bmp files from the Models folder on this book’s website

Trang 6

Once the rocket.fbx and launcher.fbx models are referenced from the Solution

Ex-plorer,InitializeModels()can initialize the model objects and their

Remember to only reference the models in your project Both the models and

textures should be placed in the Models folder However, the content pipeline is

unable to load more than one file with the same name from the same folder because no

extension is required

Now that the models have been loaded, projectile objects can be created to track

each rocket’s direction and whereabouts Declaring ten projectile objects in the game

class in the module declarations area will make them available for your use

through-out the game class

Next, we’ll draw the rocket launcher The rocket launcher travels with the camera

and rotates about the X axis—with changes to the view position on Y whenever the

user moves the mouse or right thumbstick up or down The model rocket launcher

was designed to simplify the transformations for this movement The rocket

launcher’s base is positioned at the origin, and the barrel is centered around the Z

axis and is positioned further out on Z By design of the camera, the launcher’s

rota-tion range about the X axis is half a circle (or π radians) If the rocket launcher is

pointed directly upward, the view position on Y would equal 0.5, and if the rocket

launcher is pointed directly downward, the view position would be –0.5 (see Figure

19-4)

As discussed in Chapter 7, because XNA uses the Right Hand Rule, a negative

ro-tation around the X axis will point the launcher upward Using the same logic, a

posi-tive rotation about the X axis will point the launcher downward The launcher must

be rotated about the X axis to match the camera’sLookdirection about the Y axis

Trang 7

With this information, you can calculate the rocket launcher’s rotation angle aboutthe X axis with the following equation:

rotationX = Matrix.CreateRotationX(-MathHelper.Pi*look.Y );

The launcher must also be rotated about the Y axis to match the camera’sLookrection about the Y axis And finally, to finish the transformation using theI.S.R.O.T sequence, the launcher must be translated by an amount that is equivalent

di-to the distance from the origin di-to the camera An extra shift downward on the Y axis

is added to this translation to move the launcher downward slightly so it does notblock your view

Add DrawLauncher() to your game class to move and rotate the rocketlauncher with your camera:

private void DrawLauncher(Model model){

Trang 8

Vector3 look = cam.view - cam.position;

rotationX = Matrix.CreateRotationX(-MathHelper.Pi*look.Y );

rotationY = Matrix.CreateRotationY((float)Math.Atan2(look.X,

look.Z));

// 3: build cumulative matrix using I.S.R.O.T sequence

// identity,scale,rotate,orbit(translate & rotate),translate

world = scale * rotationX * rotationY * translation;

// 4: set shader parameters

foreach (ModelMesh mesh in model.Meshes){

foreach (BasicEffect effect in mesh.Effects){

To actually see the rocket launcher, you obviously need to call the method to draw

it AddingDrawLauncher()to the end of theDraw()method will draw the rocket

when other objects are rendered:

DrawLauncher(launcherModel);

Because the rocket launcher’s rotation angle about the X axis changes with the

view position on Y, if the right thumbstick or mouse shifts the view all the way up or

all the way down, you can actually see the base of the launcher, which spoils the

ef-fect Inside the camera class in theUpdateView()method, you’ll replace the code

that caps the Y view position so that it can no longer exceed 0.30 or fall below –0.10,

which prevents you from pointing the launcher into the ground The end result is that

whatever angle you point, it looks as though you are always holding the rocket

launcher:

const float LOWER_LIMIT = -0.1f; const float UPPER_LIMIT = 0.3f;

if (Qlook.Y > LOWER_LIMIT && Qlook.Y < UPPER_LIMIT)

The code that you use to launch the rocket (from the game class) is contained in the

LaunchRocket()method This routine searches through the array of projectiles

Trang 9

and finds the first inactive projectile available When an inactive projectile is found,LaunchRocket()sets the starting position and direction to equal the camera posi-tion andLookdirection.

The transformations use the I.S.R.O.T sequence Their implementation to angleand position the rocket at the tip of the launcher is summarized in the comments in-cluded with this code

The starting position is needed to help track the location of each rocket To createthe required transformation, and record the initial starting position of the rocket, wecan use the matrix math discussed in Chapter 8 and Chapter 16 Once the startingposition is computed using matrices, the first row of the matrix that contains the po-sition information is stored in a vector This position vector can be used later to up-date the position of the rocket by incrementing the position by a time-scaled directionvector As you can see, it really does pay to understand how to employ linear algebrabeyond just using theMatrixobjects and methods that are shipped with XNA.AddLaunchRocket()to your game class to find the first available rocket when

a launch is triggered and to calculate and store the starting position and direction ofthe rocket:

private void LaunchRocket(int i){

Matrix orbitTranslate, orbitX, orbitY, translate, position;

Vector3 look, start;

// create matrix and store origin in first row

position = new Matrix(); // zero matrix

position.M14 = 1.0f; // set W to 1 so you can transform it

// move to tip of launcher

orbitTranslate = Matrix.CreateTranslation(0.0f, 0.0f, -0.85f);

// use same direction as launcher

look = cam.view - cam.position;

// offset needed to rotate rocket about X to see it with camera

float offsetAngle = MathHelper.Pi;

// adjust angle about X with changes in Look (Forward) direction

orbitX = Matrix.CreateRotationX(offsetAngle-MathHelper.Pi*look.Y);

// rocket's Y direction is same as camera's at time of launch

orbitY = Matrix.CreateRotationY((float)Math.Atan2(look.X,look.Z));

Trang 10

// move rocket to camera position where launcher base is also located

translate = Matrix.CreateTranslation(cam.position.X,BASE_HEIGHT,

cam.position.Z);

// use the I.S.R.O.T sequence to get rocket start position

position = position * orbitTranslate * orbitX * orbitY * translate;

// convert from matrix back to vector so it can be used for updates

start = new Vector3(position.M11, position.M12, position.M13);

rocket[i].Launch(look, start);

}

At this point, the projectile objects are initialized and your launcher is in place Your

rockets are ready, but a mechanism is required to trigger their launch In this case, you

will add code to initiate their launch when the left mouse button is clicked, or when the

right trigger on the controller is pressed To ensure that all ten rockets are not launched

during this press event—which lasts over several frames— the current and previous

states of the game pad and mouse are compared To enable this input device state

checking, you must add a declaration for game pad and mouse states at the class level:

#if !XBOX

MouseState mouseCurrent, mousePrevious;

#endif

GamePadState gamepad, gamepadPrevious;

The projectile trigger events can now be handled at the end of the Update()

method In this block of code, you will update the mouse and game-pad states Then

you can determine new mouse button click or trigger-pull events by comparing the

button press states in the current frame with release states from the previous frame:

// refresh key and button states

#if !XBOX

mouseCurrent = Mouse.GetState();

#endif

gamepad = GamePad.GetState(PlayerIndex.One);

// launch rocket for right trigger and left click events

if (gamepad.Triggers.Right > 0 && gamepadPrevious.Triggers.Right == 0

#if !XBOX

|| mouseCurrent.LeftButton == ButtonState.Pressed

&& mousePrevious.LeftButton == ButtonState.Released

#endif

Trang 11

){ // if launch event then launch next available rocket

for (int i = 0; i < NUM_ROCKETS; i++)

if (rocket[i].active == false){

LaunchRocket(i);

break;

} }

// archive current state for comparison next frame

ani-for (int i = 0; i < NUM_ROCKETS; i++)

// 3: build cumulative matrix using I.S.R.O.T sequence

world = scale * rotateX * rocket[i].directionMatrix * translate;

// 4: set shader parameters

foreach (ModelMesh mesh in model.Meshes){

foreach (BasicEffect effect in mesh.Effects){

Trang 12

To ensure that projectiles are actually drawn,DrawRockets()needs to be called

from theDraw()method This code loops through all projectile objects and draws

the active ones at their current position with their corresponding direction:

for (int i = 0; i < NUM_ROCKETS; i++)

if (rocket[i].active)

DrawRockets(rocketModel, i);

When you compile and run this program, it shows the Linear Projectile algorithm

in action Whenever the left mouse button is clicked, or a game controller trigger is

pulled, a rocket is launched Each projectile shoots outward until it reaches an

arbi-trary boundary located at the outer limits of the world

This Arcing Projectiles example picks up where the Linear Projectile algorithm ends

When this example is complete, and the effect of gravity is factored in, the flight of

each projectile will rise to a peak and then follow a descending path to the ground

Most of the code in this revised routine remains the same However, the method that

updates the rocket position will be replaced so that the gravitational pull over time is

taken into consideration In this new routine, however, initially the linear projectile

algorithm is implemented long enough for the projectile to safely leave the barrel of

the launcher in case it is moving Use of constant speed at the onset creates a mini

turbo boost so your players don’t risk blowing themselves up every time they pull the

trigger Once the rocket is far enough away from the launcher, gravity kicks in—then

the count to the touchdown begins

The UpdateProjectile() method updates the position by factoring speed

over time In Y’s case, the height is also adjusted with the pull of gravity over time

Trang 13

SetDirectionMatrix() makes this effect even more realistic by adjusting therocket’s direction The transformation matrix set when calling this method ensuresthat the rocket flies in the proper direction about the Y axis, and it also gives therocket a tilt on the X axis, so it points upward as it climbs and then lowers as therocket descends to the ground.

Replace the existingUpdateProjectile()method with this one to implementthe change:

public void UpdateProjectile(GameTime gameTime){

previousPosition = position; // store position from last frame

// gravity takes over after rocket clears the launcher

Vector3 distanceTravelled = position - startPosition;

* SCALAR; // Y uses speed and gravity vs time }

// turbo boost needed for rocket to clearly leave the launcher

else

position += speed // speed uses constant scalar

*(float)gameTime.ElapsedGameTime.Milliseconds/90.0f;

SetDirectionMatrix(); // rocket direction considers speed

if (position.Y < -0.5f) // de-activate if below ground

Trang 14

C HAPTER 19 REVIEW EXERCISES

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

1. Follow the step-by-step examples shown in this chapter to implement the

Linear Projectile algorithm and Arcing Projectile algorithm, if you have not

already done so

2. State how the projectile update routine for linear projectiles differs from

that for arcing projectiles

3. Replace the model rocket with your own 3D object and make it point in

the direction that it travels Add bounding-sphere collision detection to an

object in your world so that something happens when you hit it

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

TỪ KHÓA LIÊN QUAN