/*
* プロジェクトのプロパティ
* [XNA Game Studio]タブ
* Use HiDef to access the complete API
*/
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using CustomVertex;
namespace XnaCarRace
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
Effect effect;
EffectParameter ViewProj;
Texture2D map;
Texture2D compass;
Texture2D marker;
// fps
int fpsSec;
int fpsDraw = 0;
int fpsCount = 0;
VertexBuffer instanceBuffer;
VertexBuffer geometryBuffer;
IndexBuffer indexBuffer;
VertexDeclaration instanceVertexDeclaration;
VertexBufferBinding[] bindings;
Matrix projection;
byte[,] objMap;
// カメラ
//Vector3 camPos = new Vector3(0, 2, 0);
Vector3 camPos = new Vector3(22, 0.5f, 70);
float camLon = 270;
float velocity = 0;
float steering = 0;
struct InstanceInfo
{
public Matrix World;
public Vector4 Color;
}
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void LoadContent()
{
sprite = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("SpriteFont1");
effect = Content.Load<Effect>("Effect1");
ViewProj = effect.Parameters["ViewProj"];
//effect.CurrentTechnique = effect.Techniques["Technique1"];
map = Content.Load<Texture2D>("map"); // 128x128くらいのpng
compass = Content.Load<Texture2D>("compass");
GenerateGeometryBuffers();
GenerateInstanceVertexDeclaration();
GenerateInstanceInformation();
bindings = new VertexBufferBinding[2];
bindings[0] = new VertexBufferBinding(geometryBuffer, 0);
bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
GraphicsDevice.Viewport.AspectRatio, 0.1f, 100);
// マーカー
Color[] data = new Color[9];
for (int n = 0; n < 9; n++)
{
data[n] = new Color(255, 255, 255);
}
marker = new Texture2D(GraphicsDevice, 3, 3);
marker.SetData<Color>(data);
base.LoadContent();
}
void GenerateGeometryBuffers()
{
// 頂点
VertexPosition[] vertices = new VertexPosition[8];
Vector3[] cube =
{
new Vector3(1, 1, 1), new Vector3(1, 1, -1),
new Vector3(1, -1, 1), new Vector3(1, -1, -1),
new Vector3(-1, -1, -1), new Vector3(-1, 1, -1),
new Vector3(-1, -1, 1), new Vector3(-1, 1, 1),
};
for (int n = 0; n < 8; n++)
{
vertices[n] = new VertexPosition(cube[n] * 0.5f);
}
geometryBuffer = new VertexBuffer(GraphicsDevice,
typeof(VertexPosition), 8, BufferUsage.WriteOnly);
geometryBuffer.SetData(vertices);
// 索引
short[] indices =
{
0, 1, 2, 3, 2, 1, // +X面
4, 5, 6, 7, 6, 5, // -X面
0, 7, 1, 5, 1, 7, // +Y面
4, 6, 3, 2, 3, 6, // -Y面
0, 2, 7, 6, 7, 2, // +Z面
4, 3, 5, 1, 5, 3, // -Z面
};
indexBuffer = new IndexBuffer(GraphicsDevice,
typeof(short), 36, BufferUsage.WriteOnly);
indexBuffer.SetData(indices);
}
void GenerateInstanceVertexDeclaration()
{
VertexElement[] elements = new VertexElement[5];
for (int n = 0; n < 4; n++)
{
elements[n] = new VertexElement(sizeof(float) * 4 * n,
VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, n + 1);
}
elements[4] = new VertexElement(sizeof(float) * 16,
VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5);
instanceVertexDeclaration = new VertexDeclaration(elements);
}
void GenerateInstanceInformation()
{
objMap = new byte[map.Width, map.Height];
int dataNum = map.Width * map.Height;
InstanceInfo[] instances = new InstanceInfo[dataNum];
Color[] data = new Color[dataNum];
map.GetData<Color>(0, null, data, 0, dataNum);
int i = 0;
for (int x = 0; x < map.Height; x++)
{
for (int z = 0; z < map.Width; z++)
{
Color color = data[map.Width * (map.Height - 1 - x) + z];
if (color == Color.Black) continue;
instances[i].World = Matrix.CreateTranslation(
new Vector3(0.5f + x, 0.5f, 0.5f + z));
instances[i].Color = color.ToVector4();
i++;
objMap[z, x] = 1;
}
}
instanceBuffer = new VertexBuffer(GraphicsDevice,
instanceVertexDeclaration, i, BufferUsage.WriteOnly);
instanceBuffer.SetData(instances, 0, i);
}
protected override void Update(GameTime gameTime)
{
float deltaVelocity = -0.001f;
float deltaSteering = 0;
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Escape)) Exit();
if (kState.IsKeyDown(Keys.Z)) deltaVelocity = -0.01f;
if (kState.IsKeyDown(Keys.X)) deltaVelocity = 0.005f;
if (kState.IsKeyDown(Keys.Left)) deltaSteering = -0.1f;
if (kState.IsKeyDown(Keys.Right)) deltaSteering = 0.1f;
// 速度
velocity = MathHelper.Clamp(velocity + deltaVelocity, 0, 0.2f);
// ステアリング
if (deltaSteering == 0)
{
steering = (Math.Abs(steering) < 0.05f) ?
0 : steering - Math.Sign(steering) * 0.05f;
}
else
{
steering += deltaSteering;
}
steering = MathHelper.Clamp(steering, -1, 1);
if (velocity == 0)
{
// 停止中
camLon += Math.Sign(deltaSteering) * 2;
}
else
{
// 移動
camLon += steering;
float rad = MathHelper.ToRadians(camLon);
float x = (float)Math.Cos(rad) * velocity;
float z = (float)Math.Sin(rad) * velocity;
// 衝突判定
if (objMap[(int)(camPos.Z + z), (int)(camPos.X + x)] == 0)
{
camPos.X += x;
camPos.Z += z;
}
else
{
velocity = 0;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
//GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
float rad = MathHelper.ToRadians(camLon);
float x = camPos.X + (float)Math.Cos(rad);
float z = camPos.Z + (float)Math.Sin(rad);
Matrix view = Matrix.CreateLookAt(camPos, new Vector3(x, 0.5f, z), Vector3.Up);
GraphicsDevice.Indices = indexBuffer;
ViewProj.SetValue(view * projection);
effect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.SetVertexBuffers(bindings);
GraphicsDevice.DrawInstancedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, 12, instanceBuffer.VertexCount);
// fps
fpsDraw++;
if (gameTime.TotalGameTime.Seconds != fpsSec)
{
fpsCount = fpsDraw;
fpsDraw = 0;
fpsSec = gameTime.TotalGameTime.Seconds;
}
sprite.Begin();
string text = string.Format("fps={0} lon={1} x={2:f1} z={3:f1}",
fpsCount, camLon, camPos.X, camPos.Z);
sprite.DrawString(font, text, new Vector2(0, 0), Color.White);
text = string.Format("v={0:f2} s={1:f2}", velocity, steering);
sprite.DrawString(font, text, new Vector2(0, 20), Color.White);
sprite.Draw(map, new Vector2(20, 60), Color.White);
sprite.Draw(marker, new Vector2(20 + camPos.Z, 60 + 128 - camPos.X), null, Color.White,
0, new Vector2(1, 1), 1, SpriteEffects.None, 0);
sprite.Draw(compass, new Vector2(20 + 64, 200 + 64), null, Color.White,
MathHelper.ToRadians(camLon), new Vector2(64, 64), 1, SpriteEffects.None, 0);
sprite.End();
base.Draw(gameTime);
}
}
}