我正在使用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();
}
}
}
答案 0 :(得分:0)
使用DualTextureEffect而不是使用BasicEffect。我之前从未使用它,因为我不是为了磨练而开发,但这应该是一个非常好的教程。 http://blogs.msdn.com/b/shawnhar/archive/2010/08/04/dualtextureeffect.aspx&GT;