XNA for C#
DirectX 9 for C#
DirectX 9 for C++
DirectX 9 for VB
Forum
   
My XNA Book
      
       Go to section on this site

Additional info


Latest Forum posts

 40% OFF Pavtube DVD Ripper for Mac
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:54

 DVD Ripper with 40% off
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:22

 Get DVD Ripper Wind/Mac + $14 Coupon
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:03

 Backup DVD Escape Plan
  Posted by: Applefly
  When: 17/04/2014 at 06:00:12

 Disney DVDs to MP4
  Posted by: Applefly
  When: 17/04/2014 at 05:56:07

 DVD movies through media streamer
  Posted by: VIKIVannessa
  When: 16/04/2014 at 02:25:09

 DVD movies to play on Galaxy Tab 3 10.1
  Posted by: VIKIVannessa
  When: 16/04/2014 at 02:20:51

 Blu-ray to Apple ProRes
  Posted by: Applefly
  When: 12/04/2014 at 00:47:46

 HD H.264 MP4 format
  Posted by: Applefly
  When: 12/04/2014 at 00:43:23

 DVD collection to computer
  Posted by: VIKIVannessa
  When: 04/04/2014 at 07:13:33


Ads

Point sprites – Billboarding

This chapter we’ll be adding bullets to our game. For these bullets, we could use real 3D spheres, but this would ask a lot from our graphics card. Instead, we’ll be using a very simple 2D image of a fireball, which you can download here (link). For this, we’ll be using a new technique from my effect file. This technique allows us to only specify the central point of the image in 3D space. The technique will do the rest, to render the image so it is always facing the viewer and is scaled to reflect the distance between the viewer and the point in 3D space. This technique is called billboarding.

Billboarding is used a lot in 3D games, for example to add trees in a forest. For a lot of detailed information and samples on billboarding, see Recipes 3-11 and 3-12.

A 2D image is also called a sprite, and since XNA needs only the center point of the image as 3D location, these 2D sprites used in 3D are called point sprites.

When being fired, we want the bullets to move forward continuously. Thus, for every bullet, we’ll need to keep track of the current position and the rotation to calculate the direction of the bullet, just as with our plane. So we’re going to define a new struct, which you should put at the very top of our code, above our variables:

 struct Bullet
 {
     public Vector3 position;
     public Quaternion rotation;
 }

With this struct defined, we can create objects of the Bullet type. For each object of the Bullet type, we can store a Vector3 and a Quaternion to store the position and rotation, respectively.

We will keep track of a List containing these Bullet objects. Furthermore, to define the firing speed, we need to keep track of the last time a bullet was fired. Finally, we will need a Texture2D variable to hold the image of the bullet. So put these lines among our other variable declarations:

 Texture2D bulletTexture;

List<Bullet> bulletList = new List<Bullet> ();double lastBulletTime = 0;

You can download my sample bullet image here (link).

Go ahead and import the image into your solution as you’ve done before. Next, we’ll load the 2D image into our texture variable. This is done by adding this line to the LoadContent method:


bulletTexture = Content.Load<Texture2D> ("bullet");
Now, every time the user presses the spacebar, we want a new bullet to be created and be added to our bulletList, so add this code at the bottom of our ProcessKeyboardmethod:

 if (keys.IsKeyDown(Keys.Space))
 {    
     double currentTime = gameTime.TotalGameTime.TotalMilliseconds;
     if (currentTime - lastBulletTime > 100)
     {
         Bullet newBullet = new Bullet();
         newBullet.position = xwingPosition;
         newBullet.rotation = xwingRotation;
         bulletList.Add(newBullet);
 
         lastBulletTime = currentTime;
     }
 }

When the spacebar is pressed, we compare the current time with the last time our xwing fired a bullet. If our last shot was more than 100 milliseconds ago, we want to fire a new bullet. This comes down to 10 bullets per second.

If it’s OK to fire a new bullet, we create a new Bullet object, and the current position and rotation of the xwing is stored to it. This is of course because we want the bullet to travel in the same direction as our xwing was flying the moment the bullet was fired. The last line effectively adds the newly created Bullet object to the bulletList.

Before we move on to the drawing code, let’s finish this part by making the bullets move forward. We’ve already created a method that does all the calculations: MoveForward. We’re going to create a new method, UpdateSpritePositions, which will scroll through our bulletList and update the position of every bullet. This is the code:

 private void UpdateBulletPositions(float moveSpeed)
 {
     for (int i = 0; i < bulletList.Count; i++)
     {
         Bullet currentBullet = bulletList[i];
         MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 2.0f);
         bulletList[i] = currentBullet;
     }
 }

Pretty straightforward. The position of every bullet in our bulletList is updated. This method will also receive the same moveSpeed as our xwing, but since we multiply it with 2.0f the bullets will go twice as fast as our xwing.

Call this method from within the Update method:

 UpdateBulletPositions(moveSpeed);

Next, we want to draw our bullets. I’ve provided a technique which requires you to only specify the center point of the bullet, and your graphics card will render the bullet at that location. However, since each bullet is a square image, our graphics card will need two triangles to render. Therefore, for each bullet, you’ll need to provide 6 vertices. Luckily, for each vertex you can provide the same position, and the technique will make sure these positions are adjusted correctly.

We will define a new method, DrawSprites, which draws the bullets stored in our bulletList. Let’s start with this part:

 private void DrawBullets()
 {
     if (bulletList.Count > 0)
     {
         VertexPositionTexture[] bulletVertices = new VertexPositionTexture[bulletList.Count * 6];
         int i = 0;
         foreach (Bullet currentBullet in bulletList)
         {
             Vector3 center = currentBullet.position;
 
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 1));
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 0));
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 0));
 
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 1));
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 1));
             bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 0));
         }
     }
 }

For each bullet in our bulletList, this code will add 6 vertices to the bulletVertices array. As you can see, for all vertices we specify the same position: the location of the bullet. The technique will use the texture coordinates to make sure two triangles are rendered around this center position, which is required to display the image.
This technique is called PointSprites, so we need to select it. We’ll immediately set all the parameters required by the effect to work. Add this code at the end of your if-block:

 effect.CurrentTechnique = effect.Techniques["PointSprites"];
 effect.Parameters["xWorld"].SetValue(Matrix.Identity);
 effect.Parameters["xProjection"].SetValue(projectionMatrix);
 effect.Parameters["xView"].SetValue(viewMatrix);
 effect.Parameters["xCamPos"].SetValue(cameraPosition);
 effect.Parameters["xTexture"].SetValue(bulletTexture);
 effect.Parameters["xCamUp"].SetValue(cameraUpDirection);
 effect.Parameters["xPointSpriteSize"].SetValue(0.1f);

As for all objects rendered into a 3D world, you first need to set the World, View and Projection matrices. Specific to the PointSprites technique, you need to pas the camera position, as well as the camera Up direction, allowing the technique to render the 2 triangles so they’re always facing the camera. Finally, you need to pass the texture, and define how large you want it to be.

Obviously, before this can work, we first need to define both camera variables at the very top of our code:

 Vector3 cameraPosition;
 Vector3 cameraUpDirection;

We already calculated this in our UpdateCamera method, so add these lines to the end of that method:

 cameraPosition = campos;
 cameraUpDirection = camup;

Back to our DrawBullets method. With the vertices ready and the effect set up correctly, all we need to do now is render the bullets! Which is done by the following code:

 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
 {
 pass.Apply();
 
 device.DrawUserPrimitives(PrimitiveType.TriangleList, bulletVertices, 0, bulletList.Count * 2);
 }

DrawBullets();

In this example, the CPU is calculating the new position of each bullet for each frame, creates an array of vertices from these positions and sends them to the graphics card for each frame. It would be much better and faster to have the GPU calculate all the new positions. See Recipe 3-12 on how this can be done using a particle engine.

This concludes the method; All we have to do is call this method from the bottom of our Draw method:

 DrawBullets();

Now try to run this code!

You should see a screen as the one below:




DirectX Tutorial 11 - Point sprites

If you appreciate the amount of time I spend creating and updating
these pages, feel free to donate -- any amount is welcome !



Click here to go to the forum on this chapter!

Or click on one of the topics on this chapter to go there:
  • Follow sprite with camera
          Hello, first of all, thanks a lot for all your ...
  • Distorted bullet problem
          Hi, i tried to add bullets to my game but my tex...
  • Invis Bullets
          Hey Guys, iam trying to add some bullets to my ta...
  • Rendering Non-Regular Point Sprites
          Hi Guys, I am trying to draw a 2D image that do...
  • Invisible bullets
          I have followed the Series 2 tutorials about the f...
  • memory consumption
          Hello riemer great tutorials, first than anythi...
  • Right Point Sprite Rendering
          Hello! I have a problem with way of the renderi...
  • The method call is invalid
          Hi Riemer! I'm following your XNA tutorial from ...


    We will fine-tune our bullets in the next chapter. This will also include detecting collisions between a bullet and an obstacle. In case of a collision, the bullet will be removed from our bulletList, which will free the memory.

    You can try these exercises to practice what you've learned:
  • Change the size of the point sprites.
    Our code thus far:

     using System;
     using System.Collections.Generic;
     using System.Linq;
     using Microsoft.Xna.Framework;
     using Microsoft.Xna.Framework.Audio;
     using Microsoft.Xna.Framework.Content;
     using Microsoft.Xna.Framework.GamerServices;
     using Microsoft.Xna.Framework.Graphics;
     using Microsoft.Xna.Framework.Input;
     using Microsoft.Xna.Framework.Media;
     
     namespace Series3D2
     {
         public class Game1 : Microsoft.Xna.Framework.Game
         {
             enum CollisionType { None, Building, Boundary, Target }
     
             struct Bullet
             {
                 public Vector3 position;
                 public Quaternion rotation;
             }
     
             GraphicsDeviceManager graphics;
             SpriteBatch spriteBatch;
             GraphicsDevice device;
             Effect effect;
             Texture2D sceneryTexture;
             Model xwingModel;
             VertexBuffer cityVertexBuffer;
     
             int[,] floorPlan;
             int[] buildingHeights = new int[] { 0, 2, 2, 6, 5, 4 };
             Vector3 lightDirection = new Vector3(3, -2, 5);
             Vector3 xwingPosition = new Vector3(8, 1, -3);
             Quaternion xwingRotation = Quaternion.Identity;
             float gameSpeed = 1.0f;
             BoundingBox[] buildingBoundingBoxes;
             BoundingBox completeCityBox;
             const int maxTargets = 50;
             Model targetModel;

            List<BoundingSphere> targetList = new List<BoundingSphere> ();
             Texture2D bulletTexture;

            List<Bullet> bulletList = new List<Bullet> ();        double lastBulletTime = 0;
            Vector3 cameraPosition;
            Vector3 cameraUpDirection;

            Matrix viewMatrix;
            Matrix projectionMatrix;

     
             public Game1()
             {
                 graphics = new GraphicsDeviceManager(this);
                 Content.RootDirectory = "Content";
             }
     
             protected override void Initialize()
             {
                 graphics.PreferredBackBufferWidth = 500;
                 graphics.PreferredBackBufferHeight = 500;
                 graphics.IsFullScreen = false;
                 graphics.ApplyChanges();
                 Window.Title = "Riemer's XNA Tutorials -- 3D Series 2";
     
                 lightDirection.Normalize();            
     
                 base.Initialize();
             }
     
             protected override void LoadContent()
             {
                 spriteBatch = new SpriteBatch(GraphicsDevice);
                 
                 device = graphics.GraphicsDevice;

                effect = Content.Load<Effect> ("effects");
                sceneryTexture = Content.Load<Texture2D> ("texturemap");            xwingModel = LoadModel("xwing");
                targetModel = LoadModel("target");

                bulletTexture = Content.Load<Texture2D> ("bullet");
                LoadFloorPlan();
                SetUpVertices();
                SetUpBoundingBoxes();
                AddTargets();
            }

            private void LoadFloorPlan()
            {
                floorPlan = new int[,]
                {
                    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,1,1,0,0,0,1,1,0,0,1,0,1},
                    {1,0,0,1,1,0,0,0,1,0,0,0,1,0,1},
                    {1,0,0,0,1,1,0,1,1,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,1,1,0,0,0,1,0,0,0,0,0,0,1},
                    {1,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},
                    {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},
                    {1,0,1,0,0,0,0,0,0,1,0,0,0,0,1},
                    {1,0,1,1,0,0,0,0,1,1,0,0,0,1,1},
                    {1,0,0,0,0,0,0,0,1,1,0,0,0,1,1},
                    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                };

                Random random = new Random();
                int differentBuildings = buildingHeights.Length - 1;
                for (int x = 0; x < floorPlan.GetLength(0); x++)
                    for (int y = 0; y < floorPlan.GetLength(1); y++)
                        if (floorPlan[x, y] == 1)
                            floorPlan[x, y] = random.Next(differentBuildings) + 1;
            }

            private void SetUpBoundingBoxes()
            {
                int cityWidth = floorPlan.GetLength(0);
                int cityLength = floorPlan.GetLength(1);


                List<BoundingBox> bbList = new List<BoundingBox> ();            for (int x = 0; x < cityWidth; x++)
                {
                    for (int z = 0; z < cityLength; z++)
                    {
                        int buildingType = floorPlan[x, z];
                        if (buildingType != 0)
                        {
                            int buildingHeight = buildingHeights[buildingType];
                            Vector3[] buildingPoints = new Vector3[2];
                            buildingPoints[0] = new Vector3(x, 0, -z);
                            buildingPoints[1] = new Vector3(x + 1, buildingHeight, -z - 1);
                            BoundingBox buildingBox = BoundingBox.CreateFromPoints(buildingPoints);
                            bbList.Add(buildingBox);
                        }
                    }
                }
                buildingBoundingBoxes = bbList.ToArray();

                Vector3[] boundaryPoints = new Vector3[2];
                boundaryPoints[0] = new Vector3(0, 0, 0);
                boundaryPoints[1] = new Vector3(cityWidth, 20, -cityLength);
                completeCityBox = BoundingBox.CreateFromPoints(boundaryPoints);
            }

            private void AddTargets()
            {
                int cityWidth = floorPlan.GetLength(0);
                int cityLength = floorPlan.GetLength(1);

                Random random = new Random();

                while (targetList.Count < maxTargets)
                {
                    int x = random.Next(cityWidth);
                    int z = -random.Next(cityLength);
                    float y = (float)random.Next(2000) / 1000f + 1;
                    float radius = (float)random.Next(1000) / 1000f * 0.2f + 0.01f;

                    BoundingSphere newTarget = new BoundingSphere(new Vector3(x, y, z), radius);

                    if (CheckCollision(newTarget) == CollisionType.None)
                        targetList.Add(newTarget);
                }
            }

            private void SetUpVertices()
            {
                int differentBuildings = buildingHeights.Length - 1;
                float imagesInTexture = 1 + differentBuildings * 2;

                int cityWidth = floorPlan.GetLength(0);
                int cityLength = floorPlan.GetLength(1);


                List<VertexPositionNormalTexture> verticesList = new List<VertexPositionNormalTexture> ();
                for (int x = 0; x < cityWidth; x++)
                {
                    for (int z = 0; z < cityLength; z++)
                    {
                        int currentbuilding = floorPlan[x, z];

                        //floor or ceiling
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2(currentbuilding * 2 / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1)));

                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1)));

                        if (currentbuilding != 0)
                        {
                            //front wall
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));

                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));

                            //back wall
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));

                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));

                            //left wall
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));

                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));

                            //right wall
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));

                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                            verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                        }
                    }
                }

                cityVertexBuffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, verticesList.Count, BufferUsage.WriteOnly);

                cityVertexBuffer.SetData<VertexPositionNormalTexture> (verticesList.ToArray());        }

            private Model LoadModel(string assetName)
            {

                Model newModel = Content.Load<Model> (assetName);            foreach (ModelMesh mesh in newModel.Meshes)
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                        meshPart.Effect = effect.Clone();
                return newModel;
            }

            protected override void UnloadContent()
            {
            }

            protected override void Update(GameTime gameTime)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                    this.Exit();

                ProcessKeyboard(gameTime);
                float moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * gameSpeed;
                MoveForward(ref xwingPosition, xwingRotation, moveSpeed);

                BoundingSphere xwingSpere = new BoundingSphere(xwingPosition, 0.04f);
                if (CheckCollision(xwingSpere) != CollisionType.None)
                {
                    xwingPosition = new Vector3(8, 1, -3);
                    xwingRotation = Quaternion.Identity;
                    gameSpeed /= 1.1f;
                }

                UpdateCamera();

                 UpdateBulletPositions(moveSpeed);
     
                 base.Update(gameTime);
             }
     
             private void UpdateCamera()
             {
                 Vector3 campos = new Vector3(0, 0.1f, 0.6f);
                 campos = Vector3.Transform(campos, Matrix.CreateFromQuaternion(xwingRotation));
                 campos += xwingPosition;
     
                 Vector3 camup = new Vector3(0, 1, 0);
                 camup = Vector3.Transform(camup, Matrix.CreateFromQuaternion(xwingRotation));
     
                 viewMatrix = Matrix.CreateLookAt(campos, xwingPosition, camup);
                 projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f);
     
                 cameraPosition = campos;
                 cameraUpDirection = camup;
             }
     
             private void ProcessKeyboard(GameTime gameTime)
             {
                 float leftRightRot = 0;
     
                 float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
                 turningSpeed *= 1.6f * gameSpeed;
                 KeyboardState keys = Keyboard.GetState();
                 if (keys.IsKeyDown(Keys.Right))
                     leftRightRot += turningSpeed;
                 if (keys.IsKeyDown(Keys.Left))
                     leftRightRot -= turningSpeed;
     
                 float upDownRot = 0;
                 if (keys.IsKeyDown(Keys.Down))
                     upDownRot += turningSpeed;
                 if (keys.IsKeyDown(Keys.Up))
                     upDownRot -= turningSpeed;
     
                 Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot);
                 xwingRotation *= additionalRot;
     
                 if (keys.IsKeyDown(Keys.Space))
                 {
                     double currentTime = gameTime.TotalGameTime.TotalMilliseconds;
                     if (currentTime - lastBulletTime > 100)
                     {
                         Bullet newBullet = new Bullet();
                         newBullet.position = xwingPosition;
                         newBullet.rotation = xwingRotation;
                         bulletList.Add(newBullet);
     
                         lastBulletTime = currentTime;
                     }
                 }
             }
     
             private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed)
             {
                 Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
                 position += addVector * speed;
             }
     
             private CollisionType CheckCollision(BoundingSphere sphere)
             {
                 for (int i = 0; i < buildingBoundingBoxes.Length; i++)
                     if (buildingBoundingBoxes[i].Contains(sphere) != ContainmentType.Disjoint)
                         return CollisionType.Building;
     
                 if (completeCityBox.Contains(sphere) != ContainmentType.Contains)
                     return CollisionType.Boundary;
     
                 for (int i = 0; i < targetList.Count; i++)
                 {
                     if (targetList[i].Contains(sphere) != ContainmentType.Disjoint)
                     {
                         targetList.RemoveAt(i);
                         i--;
                         AddTargets();
     
                         return CollisionType.Target;
                     }
                 }
     
                 return CollisionType.None;
             }
     
             private void UpdateBulletPositions(float moveSpeed)
             {
                 for (int i = 0; i < bulletList.Count; i++)
                 {
                     Bullet currentBullet = bulletList[i];
                     MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 2.0f);
                     bulletList[i] = currentBullet;
                 }
             }
     
             protected override void Draw(GameTime gameTime)
             {
                 device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0);
     
                 DrawCity();
                 DrawModel();
                 DrawTargets();
                 DrawBullets();
     
                 base.Draw(gameTime);
             }
     
             private void DrawCity()
             {
                 effect.CurrentTechnique = effect.Techniques["Textured"];
                 effect.Parameters["xWorld"].SetValue(Matrix.Identity);
                 effect.Parameters["xView"].SetValue(viewMatrix);
                 effect.Parameters["xProjection"].SetValue(projectionMatrix);
                 effect.Parameters["xTexture"].SetValue(sceneryTexture);
                 effect.Parameters["xEnableLighting"].SetValue(true);
                 effect.Parameters["xLightDirection"].SetValue(lightDirection);
                 effect.Parameters["xAmbient"].SetValue(0.5f);
     
                 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                 {
                     pass.Apply();
                     device.SetVertexBuffer(cityVertexBuffer);
                     device.DrawPrimitives(PrimitiveType.TriangleList, 0, cityVertexBuffer.VertexCount/3);
                 }
             }
     
             private void DrawModel()
             {
                 Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(xwingPosition);
     
                 Matrix[] xwingTransforms = new Matrix[xwingModel.Bones.Count];
                 xwingModel.CopyAbsoluteBoneTransformsTo(xwingTransforms);
                 foreach (ModelMesh mesh in xwingModel.Meshes)
                 {
                     foreach (Effect currentEffect in mesh.Effects)
                     {
                         currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
                         currentEffect.Parameters["xWorld"].SetValue(xwingTransforms[mesh.ParentBone.Index] * worldMatrix);
                         currentEffect.Parameters["xView"].SetValue(viewMatrix);
                         currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                         currentEffect.Parameters["xEnableLighting"].SetValue(true);
                         currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
                         currentEffect.Parameters["xAmbient"].SetValue(0.5f);
                     }
                     mesh.Draw();
                 }
             }
     
             private void DrawTargets()
             {
                 for (int i = 0; i < targetList.Count; i++)
                 {
                     Matrix worldMatrix = Matrix.CreateScale(targetList[i].Radius) * Matrix.CreateTranslation(targetList[i].Center);
     
                     Matrix[] targetTransforms = new Matrix[targetModel.Bones.Count];
                     targetModel.CopyAbsoluteBoneTransformsTo(targetTransforms);
                     foreach (ModelMesh modmesh in targetModel.Meshes)
                     {
                         foreach (Effect currentEffect in modmesh.Effects)
                         {
                             currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
                             currentEffect.Parameters["xWorld"].SetValue(targetTransforms[modmesh.ParentBone.Index] * worldMatrix);
                             currentEffect.Parameters["xView"].SetValue(viewMatrix);
                             currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                             currentEffect.Parameters["xEnableLighting"].SetValue(true);
                             currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
                             currentEffect.Parameters["xAmbient"].SetValue(0.5f);
                         }
                         modmesh.Draw();
                     }
                 }
             }
     
             private void DrawBullets()
             {
                 if (bulletList.Count > 0)
                 {
                     VertexPositionTexture[] bulletVertices = new VertexPositionTexture[bulletList.Count * 6];
                     int i = 0;
                     foreach (Bullet currentBullet in bulletList)
                     {
                         Vector3 center = currentBullet.position;
     
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 1));
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 0));
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 0));
     
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(1, 1));
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 1));
                         bulletVertices[i++] = new VertexPositionTexture(center, new Vector2(0, 0));
                     }
     
                     effect.CurrentTechnique = effect.Techniques["PointSprites"];
                     effect.Parameters["xWorld"].SetValue(Matrix.Identity);
                     effect.Parameters["xProjection"].SetValue(projectionMatrix);
                     effect.Parameters["xView"].SetValue(viewMatrix);
                     effect.Parameters["xCamPos"].SetValue(cameraPosition);
                     effect.Parameters["xTexture"].SetValue(bulletTexture);
                     effect.Parameters["xCamUp"].SetValue(cameraUpDirection);
                     effect.Parameters["xPointSpriteSize"].SetValue(0.1f);
     
                     foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                     {
                         pass.Apply();
                         device.DrawUserPrimitives(PrimitiveType.TriangleList, bulletVertices, 0, bulletList.Count * 2);
                     }
                 }
             }
         }
     }
     
     


    Google
     
    Webwww.riemers.net


    If you appreciate the amount of time I spend creating and updating
    these pages, feel free to donate -- any amount is welcome !



    - Website design & XNA + DirectX code : Riemer Grootjans -
    ©2003 - 2011 Riemer Grootjans
  • Translations

    This site in English
    This site in Korean
    This site in Czech

    Microsoft MVP Award



    2007 - 2011 MVP Award
    DirectX - XNA

    Contents

    News
    Home
    Forum
    XNA 2.0 Recipes Book (8)
    XNA 3.0 Recipes Book (8)
    Downloads
    Extra Reading (3)
    Matrices: geometrical
    Matrix Mathematics
    Homogenous matrices
    Community Projects (1)
    Tutorials (160)
    XNA 4.0 using C# (89)
    2D Series: Shooters (22)
    3D Series 1: Terrain (13)
    3D Series 2: Flightsim (14)
    Starting point
    Textures
    Loading the floorplan
    Creating the 3D city
    Loading a Model
    Ambient and diffuse
    Quaternion camera
    Flight kinematics
    Collision detection
    Adding targets
    Point sprites
    Alpha blending
    Skybox
    Camera delay
    3D Series 3: HLSL (18)
    3D Series 4: Adv. terrain (19)
    Short Tuts (3)
    DirectX using C# (54)
    DirectX using C++ (15)
    DirectX using VB (2)
    -- Expand all --


    Thank you!

    Support this site --
    any amount is welcome !

    Stay up-to-date

    I don't have the time to keep a News section, so stay informed about the updates by clicking on this RSS file!