Tutorials

XNA 3D Engine - Hero class and rendering (Part 2)

Nivå : 200
Forfatter : Raymond   Link
In this second part of the tutorial we’ll look at how to render our scene, and building our hero class.

 

The code for both parts is available from a link at the bottom of the article.

 

Navigate to the Scene class we made.

 

This is still just an empty class, so what want to do now is to draw our model.

 

First we need to load it.

 

Add these as members of our class:

 

  private Model scene;

 

..and in LoadContent(), add:

 

  scene = this.Game.Content.Load<Model>("CastleSiege");

 

This basically means that we load some content of type “Model” into our “scene” member.

 

Let’s go and draw our model, this will be the most complicated task in this part of the tutorial.

 

A model consists of several ModelMeshes. The ModelMesh has its own Effect, which in turn has a view, projection and world matrix. It also has a Draw method, which means that we have control of both movement and visibility of our modelmeshes in the model.

 

There is much more to it than this, but let’s take one step at a time.

 

In our Draw Method, we’ll first need to iterate over our modelmeshes. Then we’ll iterate over the effects and set its matrices. After that, we’ll draw the modelmesh. Here’s how:

 

public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)

 

{

 

    foreach (ModelMesh mesh in scene.Meshes)

 

    {

 

        foreach (BasicEffect effect in mesh.Effects)

 

        {

 

            effect.World = Matrix.CreateTranslation(new Vector3(0,-80,0));

 

            effect.Projection = Matrix.CreatePerspectiveFieldOfView(

 

                                MathHelper.ToRadians(40.0f),

 

                                this.Game.GraphicsDevice.DisplayMode.AspectRatio,

 

                                0.1f,

 

                                10000.0f);

 

        }

 

        mesh.Draw();

 

    }

 

    base.Draw(gameTime);

 

}

 

We set the world matrix to position our model slightly more up in the y axis, that’s because the model’s origo is in the “ground” of our castle.

 

The projection matrix is a tutorial of it’s own, but this just means how we view the world.

 

XNA luckily has a helper function like CreatePerspectiveFieldOfView to make it easier for us.

 

Notice that we don’t set our view matrix.

 

This is something we have to add later when we start to move around in our scene.

 

Finally, we have to register our scene component with our Game object.

 

Go to the XNA3DEngine class, and navigate to the Initialize method.

 

It will look like this:

 

        protected override void Initialize()

 

        {

 

            Scene scene = new Scene(this);

 

            this.Components.Add(scene);

 

            base.Initialize();

 

        }

 

It’s in the game’s “Components” collection that our gamecomponents reside.

 

OK, hit F5 now and let’s see the result so far.

 

clip_image002

 

Cool, we are actually in a 3d scene now. Hit alt+F4 to close the game window.

 

First thing we’ll need to do now is to make it possible to move around in our world.

 

In the drawing code above, we excluded the view matrix.

 

The view matrix is the one that changes how we view the model

 

To encapsulate the work we have to do in constructing the view matrix, we need a camera class…but we also need a Hero class to hold positional information.

 

But which of these classes should we start building now?

 

Does our hero tell the camera where he is, or is it the camera that tells him where he should be?

 

You guessed correctly; let’s introduce… our Hero game component.

 

Our hero needs to move or rotate, based on the user input.

 

The movement and rotation is based on the position/direction he is facing, so the Hero class must contain his position and rotation in radians.

 

Here’s the class:

 

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Input;

namespace XNA3DEngine

{     /// <summary>

    /// This is a game component that implements IUpdateable. 

    /// </summary>

    public class Hero : GameComponent 

    {

        private Vector3 position;

        public Vector3 Position 

        {

            get { return position; } 

        }

        private float rotation; 

        public float Rotation

       { 

            get { return rotation; }

        }

        public Hero(Game game) 

            : base(game)

       

            this.position = new Vector3(0, 80, 0);

            this.rotation = 0f; 

        }

        /// <summary> 

        /// Allows the game component to perform any initialization it needs to before starting 

        /// to run.  This is where it can query for any required services and load content. 

        /// </summary>

        public override void Initialize() 

        {

            base.Initialize(); 

        }

 

        /// <summary> 

        /// Allows the game component to update itself.

        /// </summary> 

        /// <param name="gameTime">Provides a snapshot of timing values.</param>

        public override void Update(GameTime gameTime) 

        {

            KeyboardState state = Keyboard.GetState();

            if (state.IsKeyDown(Keys.Up)) 

            {

                move(new Vector3(0, 0, -10)); 

           

            else if (state.IsKeyDown(Keys.Down)) 

            {

                move(new Vector3(0, 0, 10)); 

            }

            if (state.IsKeyDown(Keys.Right)) 

            {

                rotate(-0.01f); 

           

            else if (state.IsKeyDown(Keys.Left)) 

           

                rotate(0.01f); 

           

            base.Update(gameTime); 

        }

 

        private void move(Vector3 translation) 

        {

            // Extract the rotation matrix that reflects the direction we are facing. 

            Matrix forwardMovement = Matrix.CreateRotationY(Rotation);

 

            // Then reposition ourselves according to the direction we are facing. 

            position += Vector3.Transform(translation, forwardMovement);

        }

 

        private void rotate(float rotationSpeed) 

        {

            rotation += rotationSpeed; 

       

    }

}

 

This is pretty straightforward. The movement is done by first extracting the rotation matrix from the “rotation” member and then move in the direction specified by the translation vector.

 

The rotation is in radians, and you add it to turn left, and subtract from it to turn right.

 

To register our game component, go back to our game class and add this before our scene initialization:

 

            Hero hero = new Hero(this); 

            this.Components.Add(hero);

 

This is it. In the next part of the tutorial we’ll add a camera to our game and I’ll explain how the camera and our hero interact with our game world.

 

Until next time, take care!

Comments

No Comments