using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaMesh
{
class Game1 : Game
{
const int gridSize = 30;
readonly Vector3[] palette =
{
new Vector3(0.0f, 0.0f, 0.8f),
new Vector3(0.8f, 0.0f, 0.0f),
new Vector3(0.8f, 0.0f, 0.8f),
new Vector3(0.0f, 0.8f, 0.0f),
new Vector3(0.0f, 0.8f, 0.8f),
new Vector3(0.8f, 0.8f, 0.0f),
new Vector3(0.8f, 0.8f, 0.8f),
new Vector3(0.0f, 0.0f, 0.0f),
};
readonly int[] dirX = { 1, 1, 0, -1, -1, -1, 0, 1, 1 };
readonly int[] dirZ = { 0, 1, 1, 1, 0, -1, -1, -1, 0 };
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
DateTime prevTime;
int draw = 0;
int fps = 0;
Model model;
Matrix view;
Matrix proj;
byte[, ,] grid;
Vector3 camPos;
int camLat; // 緯度
int camLong; // 経度
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
prevTime = DateTime.Now;
camPos = new Vector3(5.0f, 2.0f, 5.0f);
camLat = 0;
camLong = 0;
proj = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
GraphicsDevice.Viewport.AspectRatio, 0.1f, 40.0f);
base.Initialize();
}
protected override void LoadContent()
{
sprite = new SpriteBatch(GraphicsDevice);
// ContentにSprite Fontを追加しておく
font = Content.Load<SpriteFont>("SpriteFont1");
// Contentに.xファイルを追加しておく
model = Content.Load<Model>("Box");
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
}
}
grid = new byte[gridSize, gridSize, gridSize];
for (int x = 0; x < gridSize; x++)
{
for (int z = 0; z < gridSize; z++)
{
grid[x, 0, z] = (byte)((z & 0x7) + 1);
}
}
base.LoadContent();
}
protected override void Update(GameTime gameTime)
{
// キー入力
KeyboardState state = Keyboard.GetState();
if (state[Keys.W] == KeyState.Down) MoveXZ(0);
if (state[Keys.S] == KeyState.Down) MoveXZ(180);
if (state[Keys.A] == KeyState.Down) MoveXZ(-90);
if (state[Keys.D] == KeyState.Down) MoveXZ(90);
if (state[Keys.Left] == KeyState.Down)
{
camLong -= 2;
if (camLong < 0) camLong += 360;
}
if (state[Keys.Right] == KeyState.Down)
{
camLong += 2;
if (360 <= camLong) camLong -= 360;
}
if (state[Keys.Up] == KeyState.Down) camLat = Math.Min(camLat + 2, 80);
if (state[Keys.Down] == KeyState.Down) camLat = Math.Max(camLat - 2, -80);
if (state[Keys.PageUp] == KeyState.Down) MoveY(0.1f);
if (state[Keys.PageDown] == KeyState.Down) MoveY(-0.1f);
if (state[Keys.NumPad0] == KeyState.Down) SetGrid(0);
if (state[Keys.NumPad1] == KeyState.Down) SetGrid(1);
if (state[Keys.NumPad2] == KeyState.Down) SetGrid(2);
if (state[Keys.NumPad3] == KeyState.Down) SetGrid(3);
if (state[Keys.NumPad4] == KeyState.Down) SetGrid(4);
if (state[Keys.NumPad5] == KeyState.Down) SetGrid(5);
if (state[Keys.NumPad6] == KeyState.Down) SetGrid(6);
if (state[Keys.NumPad7] == KeyState.Down) SetGrid(7);
if (state[Keys.NumPad8] == KeyState.Down) SetGrid(8);
if (state[Keys.Escape] == KeyState.Down) Exit();
// 視点(カメラの1単位先にターゲット)
float rad = MathHelper.ToRadians(camLat);
float y = (float)Math.Sin(rad) + camPos.Y;
float r = (float)Math.Cos(rad);
rad = MathHelper.ToRadians(camLong);
float x = camPos.X + (float)Math.Cos(rad) * r;
float z = camPos.Z + (float)Math.Sin(rad) * r;
Vector3 camTar = new Vector3(x, y, z);
view = Matrix.CreateLookAt(camPos, camTar, Vector3.Up);
base.Update(gameTime);
}
void MoveXZ(int deg)
{
float rad = MathHelper.ToRadians(camLong + deg);
float x = camPos.X + (float)Math.Cos(rad) * 0.1f;
float z = camPos.Z + (float)Math.Sin(rad) * 0.1f;
if (GetGrid((int)x, (int)camPos.Y, (int)z) <= 0)
{
camPos.X = x;
camPos.Z = z;
}
}
void MoveY(float dy)
{
float y = camPos.Y + dy;
if (GetGrid((int)camPos.X, (int)y, (int)camPos.Z) <= 0)
{
camPos.Y = y;
}
}
int GetGrid(int x, int y, int z)
{
if (x < 0 || gridSize <= x) return -1;
if (y < 0 || gridSize <= y) return -1;
if (z < 0 || gridSize <= z) return -1;
return grid[x, y, z];
}
void SetGrid(byte b)
{
int dir = (camLong + 22) / 45;
int x = (int)camPos.X + dirX[dir];
int y = (int)camPos.Y - 1;
int z = (int)camPos.Z + dirZ[dir];
if (GetGrid(x, y, z) < 0) return;
grid[x, y, z] = b;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// モデル描画
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
for (int z = 0; z < gridSize; z++)
{
byte b = grid[x, y, z];
if (b == 0) continue;
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.DiffuseColor = palette[b - 1];
}
}
Matrix world = Matrix.CreateTranslation(
new Vector3(x + 0.5f, y + 0.5f, z + 0.5f));
model.Draw(world, view, proj);
}
}
}
// フレームレート
draw++;
DateTime now = DateTime.Now;
TimeSpan t = now - prevTime;
if (t.TotalMilliseconds >= 1000)
{
fps = draw;
draw = 0;
prevTime = now;
}
sprite.Begin();
string text = "fps=" + fps
+ " x=" + (int)camPos.X + " y=" + (int)camPos.Y + " z=" + (int)camPos.Z
+ " lat=" + camLat + " long=" + camLong;
sprite.DrawString(font, text, new Vector2(0, 0), Color.White);
sprite.End();
base.Draw(gameTime);
}
}
}