開発環境 Microsoft Visual C# 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Windows Game (4.0)
プロジェクト名 AstroSim1

Game1.cs
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);
        }
    }
}
 
最終更新:2012年12月30日 16:36