Tutorial 5, DirectX using C#


DirectX using C#

Tutorial 5

Taking Input

Some sort of input is always required to control the main character of the game, or more specifically involve user in the game. Most people play games using keyboard, so it is important to support keyboard in PC games.
Let's see how we'll take input from keyboard.

Microsoft.DirectX.DirectInput

There's a separate library that is extensively used for taking inputs. You'll need to add this dll as reference from your Solution explorer. After that, add these line somewhere before namespace
using Microsoft.DirectX.DirectInput;
using DI = Microsoft.DirectX.DirectInput;

I have redefined it with 'DI' to avoid ambiguity between Microsoft.DirectX.Direct3D.Device and Microsoft.DirectX.DirectInput.Device (both contain a class named Device)

Acquire the keyboard


this.keyb = new DI.Device(SystemGuid.Keyboard);
            this.keyb.SetCooperativeLevel(f, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            this.keyb.Acquire();


After initializing Direct3d device, we will start listening to the keyboard (hook it up). We will retrieve the keyboard state after each render, which means we will get sort of an array of all keys in byte form. Those which are pressed will contain 'non-zero' value while others '0'. 


So, everytime we get a byte array of length 256, and suppose 'A' is pressed at that moment, so the index of the array corresponding to DirectInput.Key.A will have a non-zero value while all others have a '0'.

keys = keyb.GetCurrentKeyboardState();

public bool CheckKeyPress(Key k)
        {
            return this.keys[k];//any non=zero value returns True
        }

Using the function

All game logic will go to OnPaint method of the main form.

protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            X.RenderX();
            this.Text = "Press [space] key";
            if (X.CheckKeyPress(Key.Space))
                this.Text = "Space Pressed";
        }
This program will be looking for user to press [space] key and display Text on form's title bar.


Note: You can isolate class CosmicX into another file to improve code readability and understanding. You'll see besides framework, required code to create your own game is that small and easy!!


Output


Complete Code


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using D3D = Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using DI = Microsoft.DirectX.DirectInput;

namespace XBasic
{
    public partial class Form1 : Form
    {
        class cosmicX
        {
            event EventHandler Render;
            #region -FIELDS-
            D3D.Device device;
            DI.Device keyb;
            KeyboardState keys;
            Form form;
            float _AspectRatio, _FieldOfView;
            static cosmicX _CosmicX;
            Vector3 CameraPosition, LookAt;
            Vector3 UP = new Vector3(0, 1, 0);
        
#endregion
            #region -Properties-
            public D3D.Device Device
            {
                get { return device; }
                set { device = value; }
            }
            public static cosmicX CosmicX
            {
                get { return cosmicX._CosmicX; }
                set { cosmicX._CosmicX = value; }
            }
            public float FieldOfView
            {
                get { return _FieldOfView; }
                set { _FieldOfView = value; }
            }
            public float AspectRatio
            {
                get { return _AspectRatio; }
                set { _AspectRatio = value; }
            }
            public Color SunLightColor
            {
                get { return Device.RenderState.Ambient; }
                set { Device.RenderState.Ambient = value; }
            }
#endregion
            #region -Methods-
            public cosmicX(Form f)
        {
            CosmicX = this;
            this.form = f;
            D3D.PresentParameters presentParams = new D3D.PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;
            presentParams.AutoDepthStencilFormat = DepthFormat.D16;
            presentParams.EnableAutoDepthStencil = true;
            this.Device = new D3D.Device(0, D3D.DeviceType.Hardware, f, CreateFlags.SoftwareVertexProcessing, presentParams);
            SetUp();
            form.Resize += new EventHandler(form_Resize);
            this.keyb = new DI.Device(SystemGuid.Keyboard);
            this.keyb.SetCooperativeLevel(f, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            this.keyb.Acquire();

        }

            void form_Resize(object sender, EventArgs e)
            {
                SunLightColor = Color.White;
                AspectRatio = (float)form.Width / (float)form.Height;
                this.device.Transform.Projection = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio, 0.3f, 500f);
            }
        void SetUp()
        {
            this.device.RenderState.Lighting = true;
            this.device.Lights[0].Type = LightType.Directional;
            this.device.Lights[0].Diffuse = Color.White;
            this.device.Lights[0].Direction = new Vector3(1, 1, -1);
            this.device.Lights[0].Update();
            this.device.Lights[0].Enabled = true;
            this.device.Lights[1].Type = LightType.Directional;
            this.device.Lights[1].Diffuse = Color.White;
            this.device.Lights[1].Direction = new Vector3(-1, -1, -1);
            this.device.Lights[1].Update();
            this.device.Lights[1].Enabled = true;
            SunLightColor = Color.White;
            FieldOfView = 3.14f / 4;
            AspectRatio = (float)form.Width / (float)form.Height;
            this.device.Transform.Projection = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio, 0.3f, 500f);
        }
        public void RenderX()
        {
            this.device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
            this.device.BeginScene();
            keys = keyb.GetCurrentKeyboardState();
            if (Render != null)
                Render(this, null);
            this.device.EndScene();
            this.device.Present();
            this.form.Invalidate();
        }
        public void Stare(Object o, float distance, float height)
        {
            CameraPosition = LookAt = o.Position;
            LookAt.Y += 1;
            Vector3 v = o.LocalToGlobal();
            v.Multiply(distance / v.Length());
            CameraPosition += v;
            CameraPosition.Y = o.Position.Y + height;
            this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
        }
        public bool CheckKeyPress(Key k)
        {
            return this.keys[k];
        }

            #endregion
        public class Object
        {
            private Mesh mesh;
            private Material[] materials;
            private Texture[] textures;
            object _Tag;
            public object Tag
            {
                get { return _Tag; }
                set { _Tag = value; }
            }
            private float radius;
            public Vector3 Position, centre, Orientation, LocalAxis, Scaling;
            public Object(string Filename, float scaling)
                : this(Filename, scaling, true)
            {

            }
            public Object(string Filename, float scaling, bool renderable)
            {
                Scaling = new Vector3(scaling, scaling, scaling);
                LoadMesh(Filename, ref mesh, ref materials, ref textures, ref radius, scaling, out centre);
                Position = new Vector3(0, 0, 0);
                if (renderable)
                    CosmicX.Render += new EventHandler(_CosmicX_Render);
                Orientation = new Vector3(0, 0, 0);
                LocalAxis = new Vector3(0, 0, 1);
            }
            public void LoadMesh(string filename, ref Mesh mesh, ref Material[] meshmaterials, ref Texture[] meshtextures, ref float meshradius, float scaling, out Vector3 meshcenter)
            {
                if (!System.IO.File.Exists(filename))
                { throw new Exception("File not found " + filename); }
                ExtendedMaterial[] materialarray;
                mesh = Mesh.FromFile(filename, MeshFlags.Managed, CosmicX.device, out materialarray);

                if ((materialarray != null) && (materialarray.Length > 0))
                {
                    meshmaterials = new Material[materialarray.Length];
                    meshtextures = new Texture[materialarray.Length];

                    for (int i = 0; i < materialarray.Length; i++)
                    {
                        meshmaterials[i] = materialarray[i].Material3D;
                        meshmaterials[i].Ambient = meshmaterials[i].Diffuse;

                        if ((materialarray[i].TextureFilename != null) && (materialarray[i].TextureFilename != string.Empty))
                        {
                            System.IO.FileInfo fi = new System.IO.FileInfo(filename);
                            if (System.IO.File.Exists(fi.DirectoryName + "\\" + materialarray[i].TextureFilename))
                            {
                                meshtextures[i] = TextureLoader.FromFile(CosmicX.device, fi.DirectoryName + "\\" + materialarray[i].TextureFilename);
                            }
                            else System.Diagnostics.Debug.Print("File not found: " + materialarray[i].TextureFilename + " !");
                        }
                    }
                }

                mesh = mesh.Clone(mesh.Options.Value, CustomVertex.PositionNormalTextured.Format, CosmicX.device);
                mesh.ComputeNormals();

                VertexBuffer vertices = mesh.VertexBuffer;
                GraphicsStream stream = vertices.Lock(0, 0, LockFlags.None);
                meshradius = Geometry.ComputeBoundingSphere(stream, mesh.NumberVertices, mesh.VertexFormat, out meshcenter) * scaling;

            }
            public Vector3 LocalToGlobal()
            {
                Vector4 v = Vector3.Transform(LocalAxis, Matrix.RotationY(Orientation.Y) * Matrix.RotationX(Orientation.X) * Matrix.RotationZ(Orientation.Z));
                return new Vector3(v.X, v.Y, v.Z);
            }
            
            public void DrawMesh()
            {
                for (int i = 0; i < materials.Length; i++)
                {
                    CosmicX.device.Material = materials[i];
                    CosmicX.device.SetTexture(0, textures[i]);
                    mesh.DrawSubset(i);
                }
            }
            void _CosmicX_Render(object sender, EventArgs e)
            {
                Render();
            }
            public void Render()
            {
                CosmicX.device.Transform.World = Matrix.Scaling(Scaling.X, Scaling.Y, Scaling.Z) * Matrix.RotationX(Orientation.X) * Matrix.RotationZ(Orientation.Z) * Matrix.RotationY(Orientation.Y) * Matrix.Translation(Position);
                DrawMesh();
            }
            public void Dispose()
            {
                CosmicX.Render -= _CosmicX_Render;
                mesh = null;
                materials = null;
                textures = null;
                System.GC.SuppressFinalize(this);
            }

        }
        
        }
        cosmicX X;
        cosmicX.Object truck;
        public Form1()
        {
            InitializeComponent();
            //this.Size = new Size(800, 800);
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            X = new cosmicX(this);
            truck = new cosmicX.Object("slam\\slam.x", 1);
            X.Stare(truck, 10, 4);
            Resize += new EventHandler(Form1_Resize);
        }

        void Form1_Resize(object sender, EventArgs e)
        {
            X.Stare(truck, 10, 4);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            X.RenderX();
            this.Text = "Press [space] key";
            if (X.CheckKeyPress(Key.Space ))
                this.Text = "Space Pressed";
        }
    }
}

Comments

Popular Posts