using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace AstroSim1
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
BasicEffect effect;
VertexBuffer vertexBuffer;
MouseState mStateOld = new MouseState();
const double au = 149597870700; // 天文単位(m)
const double Er = 6356.752; // 地球の極半径(km)
const double Sr = 1392000 / 2; // 太陽の半径(km)
const double e = 0.01671022; // 離心率
const float q = 0.983f; // 近日点距離(au)
float a = 1.0f; // 長半径(天文単位 au)
float b = (float)Math.Sqrt(1.0 - e * e); // 短半径
Vector3 camPos = new Vector3(0, 0, (float)(au * 3));
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 = new BasicEffect(GraphicsDevice);
effect.VertexColorEnabled = true;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
GraphicsDevice.Viewport.AspectRatio, 10000, (float)(au * 3));
VertexPositionColor[] vertices = new VertexPositionColor[8 + (360 + 1) * 2];
// 楕円の焦点
float Fx = (float)((a - q) * au); // 太陽の位置
float Fr = (float)(Sr * 1000); // 太陽の半径
vertices[0] = new VertexPositionColor(new Vector3(Fx, -Fr, 0), Color.Red);
vertices[1] = new VertexPositionColor(new Vector3(Fx, Fr, 0), Color.Red);
vertices[2] = new VertexPositionColor(new Vector3(Fx - Fr, 0, 0), Color.Red);
vertices[3] = new VertexPositionColor(new Vector3(Fx + Fr, 0, 0), Color.Red);
// もう一つの焦点
vertices[4] = new VertexPositionColor(new Vector3(-Fx, -Fr, 0), Color.Blue);
vertices[5] = new VertexPositionColor(new Vector3(-Fx, Fr, 0), Color.Blue);
vertices[6] = new VertexPositionColor(new Vector3(-Fx - Fr, 0, 0), Color.Blue);
vertices[7] = new VertexPositionColor(new Vector3(-Fx + Fr, 0, 0), Color.Blue);
for (int t = 0; t <= 360; t++)
{
float rad = MathHelper.ToRadians(t);
float x = (float)(Math.Cos(rad) * au);
float y = (float)(Math.Sin(rad) * au);
vertices[8 + t] = new VertexPositionColor(
new Vector3(Fx + x, y, 0), Color.Red); // 太陽から1au
vertices[369 + t] = new VertexPositionColor(
new Vector3(a * x, b * y, 0), Color.White); // 地球の軌道
}
vertexBuffer = new VertexBuffer(GraphicsDevice,
typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
base.LoadContent();
}
protected override void Update(GameTime gameTime)
{
int dx = 0;
int dy = 0;
int dz = 0;
// キーボード
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Escape)) Exit();
// マウス
MouseState mState = Mouse.GetState();
if (mState.LeftButton == ButtonState.Pressed)
{
dx = mState.X - mStateOld.X;
dy = mState.Y - mStateOld.Y;
}
dz = mState.ScrollWheelValue - mStateOld.ScrollWheelValue;
mStateOld = mState;
// カメラ移動
if (dx != 0 || dy != 0)
{
float magni = camPos.Z / GraphicsDevice.Viewport.Height;
camPos.X -= dx * magni;
camPos.Y += dy * magni;
}
if (dz != 0)
{
float magni = Math.Abs(dz / 120) * 1.4f;
camPos.Z *= (dz < 0) ? magni : 1 / magni;
camPos.Z = MathHelper.Clamp(camPos.Z, (float)(au * 0.01), (float)(au * 3));
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.BlendState = BlendState.AlphaBlend;
effect.View = Matrix.CreateLookAt(
camPos, new Vector3(camPos.X, camPos.Y, 0), Vector3.Up);
GraphicsDevice.SetVertexBuffer(vertexBuffer);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, 4);
GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 8, 360);
GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 369, 360);
}
sprite.Begin();
string text = string.Format("(au) x={0:f3} y={1:f3} z={2:f3}",
camPos.X / au, camPos.Y / au, camPos.Z / au);
sprite.DrawString(font, text, new Vector2(0, 0), Color.White);
sprite.End();
base.Draw(gameTime);
}
}
}