# Microsoft XNA Game Studio Creator’s Guide- P12

Chia sẻ: Cong Thanh | Ngày: | Loại File: PDF | Số trang:30

0
56
lượt xem
8

## Microsoft XNA Game Studio Creator’s Guide- P12

Mô tả tài liệu

Microsoft XNA Game Studio Creator’s Guide- P12:The release of the XNA platform and specifically the ability for anyone to write Xbox 360 console games was truly a major progression in the game-programming world. Before XNA, it was simply too complicated and costly for a student, software hobbyist, or independent game developer to gain access to a decent development kit for a major console platform.

Chủ đề:

Bình luận(0)

Lưu

## Nội dung Text: Microsoft XNA Game Studio Creator’s Guide- P12

1. 308 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Figure 19-3 shows several rockets at various elevations (on the Y axis) and at dif- ferent stages of flight. Over time, the projectiles lose momentum and gravity pulls them to the ground. The overall effect creates a nice arcing projectile path. Game developers will often use real-world physics to create more realistic graph- 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 the laws 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 usually consider some portion of the real physical model. Once the launch velocity and direction have been obtained, the effect of gravity can be computed and the X, Y, and Z positions of the projectile can be calculated over 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: Xt = Xstart + Vx * t Zt = Zstart + Vz * 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 pow- erful enough to defy gravity—otherwise, there would be insufficient energy to launch FIGURE 19-3 Considering the effect of gravity over time
2. C H A P T E R 1 9 309 Ballistics 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 fac- tored in, the equation used for calculating the Y position over time becomes: Yt = Ystart + Vy * 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. L INEAR PROJECTILES EXAMPLE 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 position and Look direction. Also, during the launch, the activation state for the projectile is set to true, and re- mains set to true until 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 a Projectile class to assist with the implementation of your projectiles. You will use Projectile to keep track of each rocket and to update its position. The Projectile 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: using Microsoft.Xna.Framework; namespace Projectiles{ public class Projectile{ } }
3. 310 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Class-level declarations are also required for storing the position, direction, and activation state of each projectile. An additional variable, for storing the size of the world, 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 variables throughout the class, we place their declarations at the top of the Projectile class (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 they are created, the projectiles remain inactive until the user launches them. Later, you will add a method to deactivate a projectile when it flies past the boundaries of the world. To set the projectile flight range and activation state when the projectile is ini- tialized, add this constructor to the Projectile class: public Projectile(float border){ boundary = border; active = false; } The projectile’s position, direction, and activation state are set according to the camera’s position and Look direction at the time of the launch. The rocket speed is actually based on the direction, which is a relative change in X, Y, and Z. Including the Launch() method in the Projectile class will enable proper initialization of these attributes during the launch. 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’s speed vector. Adding SetDirectionMatrix() to your Projectile class will
4. C H A P T E R 1 9 311 Ballistics 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 Projectile 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 matrix.Right = Right; matrix.Up = Up; matrix.Forward = Look; matrix.M44 = 1.0f; // W is set to 1 to enable transforms directionMatrix = 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 deactivated and made available for the next launch. The Up da te Pro ject ile( ) met hod i mp l e me nt s t h i s ro ut i n e. Ad d i n g 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();
5. 312 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE // deactivate if outer border exceeded on X or Z if (position.Z > 2.0f * boundary || position.X > 2.0f * boundary || position.Z
7. 314 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE FIGURE 19-4 Rocket launcher rotation range around the X axis With this information, you can calculate the rocket launcher’s rotation angle about the 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’s Look di- rection about the Y axis. And finally, to finish the transformation using the I.S.R.O.T. sequence, the launcher must be translated by an amount that is equivalent to the distance from the origin 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 not block your view. Add DrawLauncher() to your game class to move and rotate the rocket launcher with your camera: private void DrawLauncher(Model model){ // 1: declare matrices Matrix world, translation, scale, rotationX, rotationY; // 2: initialize matrices scale = Matrix.CreateScale(0.002f, 0.002f, 0.002f); translation = Matrix.CreateTranslation(cam.position.X, BASE_HEIGHT, cam.position.Z);
8. C H A P T E R 1 9 315 Ballistics 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){ effect.World = launcherMatrix[mesh.ParentBone.Index]*world; effect.View = cam.viewMatrix; effect.Projection = cam.projectionMatrix; effect.EnableDefaultLighting(); effect.SpecularPower = 0.01f; } // 5: draw object mesh.Draw(); } } To actually see the rocket launcher, you obviously need to call the method to draw it. Adding DrawLauncher() to the end of the Draw() 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 the UpdateView() 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
9. 316 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 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 and Look direction. The transformations use the I.S.R.O.T. sequence. Their implementation to angle and 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 create the required transformation, and record the initial starting position of the rocket, we can use the matrix math discussed in Chapter 8 and Chapter 16. Once the starting position 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 direction vector. As you can see, it really does pay to understand how to employ linear algebra beyond just using the Matrix objects and methods that are shipped with XNA. Add LaunchRocket() 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 of the 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));