在xna中为Windows Phone 8添加多个纹理,无需自定义着色器

时间:2014-03-04 19:45:38

标签: c# xna textures

我正在使用xna构建游戏,并且我使用VertexElementNormalTexture创建了一个地形。我知道我可以为顶点元素添加位置,法线和纹理坐标,但无论如何都要添加我想要使用的纹理。我正在我的Lumia手机上测试它,所以它是在没有使用自定义着色器的情况下构建的,因为它们不受手机支持,使得大多数网络上的教程都过时了。我相信basiceffects每个效果只支持一个纹理,所以如果我做了很多效果,我如何让顶点知道要使用哪个效果? grasseffect,watereffect等 我到目前为止的代码如下。 谢谢。

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.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Microsoft.Devices.Sensors;

namespace WindowsPhoneGame2
{

public class Game1 : Microsoft.Xna.Framework.Game
{
    #region // Variables

    public struct VertexPositionColorNormal
    {
        public Vector3 Position;
        public Color Color;
        public Vector3 Normal;

        public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
        (
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
            new VertexElement(sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0),
            new VertexElement(sizeof(float) * 3 + 4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
        );
    }

    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    RasterizerState rasterizerState;

    // terrain
    BasicEffect grassEffect;
    Texture2D grassTexture;
    BasicEffect waterEffect;
    Texture2D waterTexture;

    VertexDeclaration vertexDeclaration;
    VertexPositionNormalTexture[] vertices;
    short[] indices;
    VertexBuffer myVertexBuffer;
    IndexBuffer myIndexBuffer;

    private float[,] heightData;
    private int terrainWidth;
    private int terrainLength;
    int nScale = 16;
    Vector3 terrainPosition;
    Texture2D heightMap;

    Matrix viewMatrix;
    Matrix projectionMatrix;
    Matrix worldMatrix;

    // aircraft model
    private Model aircraftModel;
    private Vector3 aircraftPosition;
    Matrix aircraftMatrix;

    // shell model
    private Model shellModel;
    private Vector3 bulletPosition;
    Matrix bulletMatrix;
    bool blBulletFiring;
    private Vector3 torpedoPosition;
    Matrix torpedoMatrix;
    bool blTorpedoFiring;
    float nTorpedoScale;

    // display
    private SpriteFont font;
    float nHeightData;
    int nBullets = 0;
    int nTorpedoes = 0;

    // tilt gesture
    private float rollAngle;
    private float pitchAngle;
    private float yawAngle;
    Accelerometer accelerometer;
    private const int _num = 5;
    private double[] _y = new double[_num];
    private int _index = 0;

    private const int _num2 = 5;
    private double[] _y2 = new double[_num2];
    private int _index2 = 0;

    Texture2D explosionTexture;
    List<ParticleData> particleList = new List<ParticleData>();
    public struct ParticleData
    {
        public float BirthTime;
        public float MaxAge;
        public Vector2 OrginalPosition;
        public Vector2 Accelaration;
        public Vector2 Direction;
        public Vector2 Position;
        public float Scaling;
        public Color ModColor;
    }
    Random random = new Random();

    #endregion



    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold;

        loadTextures();
        loadAccelerometer();

        loadCamera();

        loadEffect();
        loadTerrain();
    }

    protected override void UnloadContent()
    {
    }

    private void loadTextures()
    {
        aircraftModel = Content.Load<Model>("Ship");
        shellModel = Content.Load<Model>("Shell");
        explosionTexture = Content.Load<Texture2D>("explosion");

        heightMap = Content.Load<Texture2D>("heightmap");
        grassTexture = Content.Load<Texture2D>("Grass");
        waterTexture = Content.Load<Texture2D>("Water");

        font = Content.Load<SpriteFont>("DisplayText");
    }

    private void loadAccelerometer()
    {
        rollAngle = 0;

        if (accelerometer == null)
        {
            accelerometer = new Accelerometer();
            accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
            accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(accelerometer_CurrentValueChanged);
        }

        accelerometer.Start();
    }

    private void loadCamera()
    {
        aircraftPosition = new Vector3(heightMap.Width * nScale * 2 / 2, 0, 400);
        projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, graphics.GraphicsDevice.Viewport.AspectRatio, 10.0f, 8000.0f);
        worldMatrix = Matrix.CreateTranslation(0, 0, 0);
        terrainPosition = new Vector3(0, 0, 0);
    }

    private void loadEffect()
    {
        //grass effect
        grassEffect = new BasicEffect(GraphicsDevice);
        //grassEffect.VertexColorEnabled = true;
        grassEffect.LightingEnabled = true; // Turn on the lighting subsystem.
        grassEffect.DirectionalLight0.DiffuseColor = new Vector3(0.1f, 0.1f, 0.1f);
        grassEffect.DirectionalLight0.Direction = new Vector3(0, 5, -10);
        grassEffect.TextureEnabled = true;
        grassEffect.Texture = grassTexture;

        //water effect
        waterEffect = new BasicEffect(GraphicsDevice);
        waterEffect.LightingEnabled = true; // Turn on the lighting subsystem.
        waterEffect.DirectionalLight0.DiffuseColor = new Vector3(0.1f, 0.1f, 0.1f);
        waterEffect.DirectionalLight0.Direction = new Vector3(0, 5, -10);
        waterEffect.TextureEnabled = true;
        waterEffect.Texture = waterTexture;

    }
    private void loadTerrain()
    {
        LoadHeightData();
        SetUpVertices();
        SetUpIndices();
        CalculateNormals();
        CopyToBuffers();
    }

    private void LoadHeightData()
    {
        terrainWidth = heightMap.Width;
        terrainLength = heightMap.Height;

        Color[] heightMapColors = new Color[terrainWidth * terrainLength];
        heightMap.GetData(heightMapColors);

        heightData = new float[terrainWidth, terrainLength];
        for (int x = 0; x < terrainWidth; x++)
            for (int y = 0; y < terrainLength; y++)
                heightData[x, y] = heightMapColors[x + y * terrainWidth].R / 5.0f;
    }
    private void SetUpVertices()
    {
        vertices = new VertexPositionNormalTexture[terrainWidth * terrainLength];
        for (int x = 0; x < terrainWidth; x++)
        {
            for (int y = 0; y < terrainLength; y++)
            {
                vertices[x + y * terrainWidth].Position = new Vector3(x * nScale * 2, y * nScale, heightData[x, y] * nScale) + terrainPosition;
            }
        }
    }
    private void SetUpIndices()
    {
        indices = new short[(terrainWidth - 1) * (terrainLength - 1) * 6];
        int counter = 0;
        for (int y = 0; y < terrainLength - 1; y++)
        {
            for (int x = 0; x < terrainWidth - 1; x++)
            {
                short lowerLeft = (short)(x + y * terrainWidth);
                short lowerRight = (short)((x + 1) + y * terrainWidth);
                short topLeft = (short)(x + (y + 1) * terrainWidth);
                short topRight = (short)((x + 1) + (y + 1) * terrainWidth);

                indices[counter++] = topLeft;
                indices[counter++] = lowerRight;
                indices[counter++] = lowerLeft;

                indices[counter++] = topLeft;
                indices[counter++] = topRight;
                indices[counter++] = lowerRight;
            }
        }
    }
    private void CalculateNormals()
    {
        for (int i = 0; i < vertices.Length; i++)
            vertices[i].Normal = new Vector3(0, 0, 0);

        for (int i = 0; i < indices.Length / 3; i++)
        {
            int index1 = indices[i * 3];
            int index2 = indices[i * 3 + 1];
            int index3 = indices[i * 3 + 2];

            Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
            Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
            Vector3 normal = Vector3.Cross(side1, side2);

            vertices[index1].Normal += normal;
            vertices[index2].Normal += normal;
            vertices[index3].Normal += normal;
        }

        for (int i = 0; i < vertices.Length; i++)
            vertices[i].Normal.Normalize();
    }
    private void CopyToBuffers()
    {
        myVertexBuffer = new VertexBuffer(graphics.GraphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
        myVertexBuffer.SetData(vertices);

        myIndexBuffer = new IndexBuffer(graphics.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
        myIndexBuffer.SetData(indices);
    }

















    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // Adjust camera position
        viewMatrix = Matrix.CreateLookAt(new Vector3(aircraftPosition.X, aircraftPosition.Y - 10, aircraftPosition.Z + 5), new Vector3(aircraftPosition.X, aircraftPosition.Y + 5, aircraftPosition.Z ), new Vector3(0, 1, 0));

        // Adjust aircraft position
        aircraftMatrix = Matrix.CreateRotationY(rollAngle) * Matrix.CreateRotationX(pitchAngle) * Matrix.CreateRotationZ(yawAngle) * Matrix.CreateTranslation(aircraftPosition);
        aircraftPosition.Y += 10.0f;

        // Check against height data for collision
        int x = (int)aircraftPosition.X / (nScale * 2);
        int y = ((int)aircraftPosition.Y - (int)terrainPosition.Y) / nScale;
        if(y < 128) nHeightData = heightData[(int)x, (int)y];
        if (nHeightData > aircraftPosition.Z / nScale)
        {
            aircraftPosition = new Vector3(terrainWidth * nScale * 2 / 2, 0, 400);
            terrainPosition = new Vector3(0, 0, 0);
        }

        // edit weapons fire positions
        if (blBulletFiring)
        {
            bulletPosition.Y += 20;
            fireBullet();

        }
        if (blTorpedoFiring)
        {
            if (torpedoPosition.Z > 5)
            {
                torpedoPosition.Z -= 6;
                torpedoPosition.Y += 10;
                nTorpedoScale = 0.8f;
            }
            else
            {
                torpedoPosition.Y += 16;
                nTorpedoScale = 1.5f;
            }

            fireTorpedo();
        }

        // detect any gestures
        while (TouchPanel.IsGestureAvailable)
        {
            GestureSample gs = TouchPanel.ReadGesture();
            switch (gs.GestureType)
            {
                case GestureType.Tap:
                    blBulletFiring = true;
                    bulletPosition = new Vector3(aircraftPosition.X - 0.05f, aircraftPosition.Y, aircraftPosition.Z);
                    AddExplosion(new Vector2(gs.Position.X, gs.Position.Y), 12, 80.0f, 1500.0f, gameTime);
                    // AddExplosion(new Vector2(aircraftPosition.X * -1, aircraftPosition.Y * -1), 12, 80.0f, 1500.0f, gameTime);
                    break;

                case GestureType.Hold:
                    blTorpedoFiring = true;
                    torpedoPosition = new Vector3(aircraftPosition.X, aircraftPosition.Y, aircraftPosition.Z);
                    break;
            }
        }


        if (particleList.Count > 0)
            UpdateParticles(gameTime);

        base.Update(gameTime);
    }

    private void UpdateParticles(GameTime gameTime)
    {
        float now = (float)gameTime.TotalGameTime.TotalMilliseconds;
        for (int i = particleList.Count - 1; i >= 0; i--)
        {
            ParticleData particle = particleList[i];
            float timeAlive = now - particle.BirthTime;

            if (timeAlive > particle.MaxAge)
            {
                particleList.RemoveAt(i);
            }
            else
            {
                float relAge = timeAlive / particle.MaxAge;
                particle.Position = 0.5f * particle.Accelaration * relAge * relAge + particle.Direction * relAge + particle.OrginalPosition;

                float invAge = 1.0f - relAge;
                particle.ModColor = new Color(new Vector4(invAge, invAge, invAge, invAge));

                Vector2 positionFromCenter = particle.Position - particle.OrginalPosition;
                float distance = positionFromCenter.Length();
                particle.Scaling = (50.0f + distance) / 200.0f;

                particleList[i] = particle;
            }
        }
    }

    private void AddExplosion(Vector2 explosionPos, int numberOfParticles, float size, float maxAge, GameTime gameTime)
    {
        for (int i = 0; i < numberOfParticles; i++)
            AddExplosionParticle(explosionPos, size, maxAge, gameTime);
    }

    private void AddExplosionParticle(Vector2 explosionPos, float explosionSize, float maxAge, GameTime gameTime)
    {
        ParticleData particle = new ParticleData();

        particle.OrginalPosition = explosionPos;
        particle.Position = particle.OrginalPosition;

        particle.BirthTime = (float)gameTime.TotalGameTime.TotalMilliseconds;
        particle.MaxAge = maxAge;
        particle.Scaling = 0.25f;
        particle.ModColor = Color.White;

        float particleDistance = (float)random.NextDouble() * explosionSize;
        Vector2 displacement = new Vector2(particleDistance, 0);
        float angle = MathHelper.ToRadians(random.Next(360));
        displacement = Vector2.Transform(displacement, Matrix.CreateRotationZ(angle));

        particle.Direction = displacement * 2.0f;
        particle.Accelaration = -particle.Direction;

        particleList.Add(particle);
    }

    private void fireBullet()
    {
        nBullets++;
        bulletMatrix = Matrix.CreateScale(0.1f) * Matrix.CreateRotationZ(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(bulletPosition);

        if (bulletPosition.Y > aircraftPosition.Y + 200)
        {
            blBulletFiring = false;
        }
    }

    private void fireTorpedo()
    {
        nTorpedoes++;
        torpedoMatrix = Matrix.CreateScale(nTorpedoScale) * Matrix.CreateRotationZ(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(torpedoPosition);

        if (torpedoPosition.Y > aircraftPosition.Y + 1000)
        {
            blTorpedoFiring = false;
        }
    }

    public void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
    {
        _y[_index++] = e.SensorReading.Acceleration.Y;
        if (_index >= _num) _index = 0;
        double ysum = 0.0;
        for (int i = 0; i < _num; i++)
            ysum += _y[i];

        double x = ysum / _num;

        // Cap it at -0.5 and 0.5
        if (x > 0.1)
        {
            if (rollAngle >= -0.9)
            {
                rollAngle -= 0.05f;
                yawAngle += 0.02f;
            }
            if (aircraftPosition.X >= 5) aircraftPosition.X -= rollAngle * -5;
        }
        else if (x <= -0.1)
        {
            if (rollAngle <= 0.9)
            {
                rollAngle += 0.05f;
                yawAngle -= 0.02f;
            }
            if (aircraftPosition.X <= terrainWidth * nScale * 2 - 6) aircraftPosition.X += rollAngle * 5;
        }
        else
        {
            if (rollAngle > 0.05)
            {
                rollAngle -= 0.05f;
                yawAngle += 0.02f;
            }
            else if (rollAngle < -0.05)
            {
                rollAngle += 0.05f;
                yawAngle -= 0.02f;
            }
            else
            {
                rollAngle = 0;
                yawAngle = 0;
            }
        }

        _y2[_index2++] = e.SensorReading.Acceleration.X;
        if (_index2 >= _num2) _index2 = 0;
        double ysum2 = 0.0;
        for (int i = 0; i < _num2; i++)
            ysum2 += _y2[i];

        double x2 = ysum2 / _num2;

        // Cap it at -0.5 and 0.5
        if (x2 > -0.4)
        {
            if(pitchAngle >= -0.6) pitchAngle -= 0.025f;
            if (aircraftPosition.Z > 6) aircraftPosition.Z -= pitchAngle * -10;
        }
        else if (x2 <= -0.5)
        {
            if (pitchAngle <= 0.6) pitchAngle += 0.025f;
            if (aircraftPosition.Z <= 500) aircraftPosition.Z += pitchAngle * 10;
        }
        else
        {
            if (pitchAngle > 0.05) pitchAngle -= 0.05f;
            else if (pitchAngle < -0.05) pitchAngle += 0.05f;
            else pitchAngle = 0;
        }
    }















    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
        GraphicsDevice.BlendState = BlendState.Opaque;
        GraphicsDevice.DepthStencilState = DepthStencilState.Default;

        rasterizerState = new RasterizerState();
        rasterizerState.FillMode = FillMode.Solid;
        rasterizerState.CullMode = CullMode.None;
        GraphicsDevice.RasterizerState = rasterizerState;

        Vector3 oldPosition = terrainPosition;

        loadTerrain();
        DrawTerrain();
        terrainPosition.Y += nScale * terrainLength - nScale;
        loadTerrain();
        DrawTerrain();
        terrainPosition.Y += nScale * terrainLength - nScale;
        loadTerrain();
        DrawTerrain();

        terrainPosition.Y -= nScale * terrainLength - nScale;
        if (aircraftPosition.Y >= terrainPosition.Y)
        { }
        else
        {
            terrainPosition = oldPosition;
        }

        if (blBulletFiring) DrawBullet(shellModel, bulletMatrix, viewMatrix, projectionMatrix);
        if(blTorpedoFiring) DrawTorpedo(shellModel, torpedoMatrix, viewMatrix, projectionMatrix);

        DrawAircraft(aircraftModel, aircraftMatrix, viewMatrix, projectionMatrix);

        DrawDisplay();

        DrawExplosion();

        base.Draw(gameTime);
    }

    private void DrawTerrain()
    {
        grassEffect.World = worldMatrix;
        grassEffect.View = viewMatrix;
        grassEffect.Projection = projectionMatrix;

        foreach (EffectPass pass in grassEffect.CurrentTechnique.Passes)
        {
            pass.Apply();

            GraphicsDevice.Indices = myIndexBuffer;
            GraphicsDevice.SetVertexBuffer(myVertexBuffer);
            GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
        }
    }
    private void DrawBullet(Model model, Matrix world, Matrix view, Matrix projection)
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                effect.LightingEnabled = true;
                effect.DirectionalLight0.DiffuseColor = new Vector3(0.9f, 0.0f, 0.0f);
                effect.DirectionalLight0.Direction = new Vector3(0, 1, -1);

                effect.World = world;
                effect.View = view;
                effect.Projection = projection;
            }

            mesh.Draw();
        }
    }
    private void DrawTorpedo(Model model, Matrix world, Matrix view, Matrix projection)
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                effect.LightingEnabled = true;
                effect.DirectionalLight0.DiffuseColor = new Vector3(0.0f, 0.0f, 0.0f);
                effect.DirectionalLight0.Direction = new Vector3(0, 1, -1);

                effect.World = world;
                effect.View = view;
                effect.Projection = projection;
            }

            mesh.Draw();
        }
    }
    private void DrawAircraft(Model model, Matrix world, Matrix view, Matrix projection)
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                // effect.EnableDefaultLighting();
                effect.LightingEnabled = true; // Turn on the lighting subsystem.
                effect.DirectionalLight0.DiffuseColor = new Vector3(0.2f, 0.2f, 0.2f); 
                effect.DirectionalLight0.Direction = new Vector3(0, 5, -10);

                //effect.DirectionalLight0.SpecularColor = new Vector3(0, 1, 0); // with green highlights
                //effect.AmbientLightColor = new Vector3(0.2f, 0.2f, 0.2f); // Add some overall ambient light.
                //effect.EmissiveColor = new Vector3(1, 0, 0); // Sets some strange emmissive lighting.  This just looks weird.

                effect.World = world;
                effect.View = view;
                effect.Projection = projection;
            }

            mesh.Draw();
        }
    }
    private void DrawDisplay()
    {
        spriteBatch.Begin();
        spriteBatch.DrawString(font, "Position: " + aircraftPosition.ToString(), new Vector2(10, 10), Color.Black);
        spriteBatch.DrawString(font, "Ground Height: " + nHeightData.ToString(), new Vector2(10, 25), Color.Black);
        spriteBatch.DrawString(font, "Bullet Position: " + nBullets.ToString(), new Vector2(10, 40), Color.Black);
        spriteBatch.DrawString(font, "Torpedo Position: " + nTorpedoes.ToString(), new Vector2(10, 55), Color.Black);
        spriteBatch.End();
    }
    private void DrawExplosion()
    {
        spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
        for (int i = 0; i < particleList.Count; i++)
        {
            ParticleData particle = particleList[i];
            spriteBatch.Draw(explosionTexture, particle.Position, null, particle.ModColor, i, new Vector2(256, 256), particle.Scaling, SpriteEffects.None, 1);
        }
        spriteBatch.End();
    }
}
}

1 个答案:

答案 0 :(得分:0)

使用DualTextureEffect而不是使用BasicEffect。我之前从未使用它,因为我不是为了磨练而开发,但这应该是一个非常好的教程。 http://blogs.msdn.com/b/shawnhar/archive/2010/08/04/dualtextureeffect.aspx&GT;