using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
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.Media;
using Newtonsoft.Json;
namespace Serious
{
public class Game1 : Game
{
string game_data_dname = "Serious";
string persistent_fname = "persistent.json";
string game_data_directory;
string persistent_fpath
{
get
{
return Path.Combine(game_data_directory, persistent_fname);
}
}
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Effect effect;
CullMode cull_mode = CullMode.CullCounterClockwiseFace;
FillMode fill_mode = FillMode.Solid;
FillMode other_fill_mode = FillMode.WireFrame;
KeyboardState prevKs;
Terrain earth;
Cylinder player;
IEnumerable<Cylinder> all_game_cylinders
{
get
{
return new Cylinder[] { player };
}
}
Camera3D player_camera;
public Game1 ()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize ()
{
Console.SetOut(new StreamWriter("console.log"));
string app_data_dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
try
{
game_data_directory = Path.Combine(app_data_dir, game_data_dname);
Directory.CreateDirectory(game_data_directory);
}
catch (IOException ex)
{
Logger.Log(ex.ToString());
}
int w = 2;
if (w == 0)
{
graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
graphics.IsFullScreen = true;
}
else if (w == 1)
{
graphics.PreferredBackBufferWidth = 1024;
graphics.PreferredBackBufferHeight = 768;
graphics.IsFullScreen = false;
}
else if (w == 2)
{
graphics.PreferredBackBufferWidth = 1600;
graphics.PreferredBackBufferHeight = 900;
graphics.IsFullScreen = false;
}
IsMouseVisible = false;
graphics.ApplyChanges();
Window.Title = "3D Terrain or whatever";
prevKs = new KeyboardState();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
effect = Content.Load<Effect>("effects");
startup persistent;
try
{
string json = File.ReadAllText(persistent_fpath);
persistent = JsonConvert.DeserializeObject<startup>(json);
}
catch (FileNotFoundException)
{
persistent = default_persistent;
}
SetUpTerrain();
SetUpCylinders(persistent);
SetUpCamera(persistent);
}
protected override void UnloadContent ()
{
startup persistent;
persistent.player.location.x = player.position.X;
persistent.player.location.y = player.position.Y;
persistent.player.angle = player.angle;
persistent.player.go_fast = player.go_fast;
persistent.camera.vertical_delta.x = player_camera.vertical_delta.X;
persistent.camera.vertical_delta.y = player_camera.vertical_delta.Y;
persistent.camera.dist = player_camera.dist;
persistent.camera.z_offset = player_camera.z_offset;
string json = JsonConvert.SerializeObject(persistent);
File.WriteAllText(persistent_fpath, json);
}
private startup default_persistent
{
get
{
startup persistent;
persistent.player.location.x = 16.0f;
persistent.player.location.y = 16.0f;
persistent.player.angle = 90.0f;
persistent.player.go_fast = false;
Vector2 vdelta = Vector2.Normalize(new Vector2(1.0f, 0.25f));
persistent.camera.vertical_delta.x = vdelta.X;
persistent.camera.vertical_delta.y = vdelta.Y;
persistent.camera.dist = 19.0f;
persistent.camera.z_offset = 4.0f;
return persistent;
}
}
private BasicModel player_normal_model { get { return BasicModel.Cylinder; } }
private BasicModel player_fast_model { get { return BasicModel.Sphere; } }
private Cylinder startup_2_cylinder(startup persistent)
{
startup.guy player = persistent.player;
return new Cylinder(new Vector3(player.location.as_vector2(), 0.0f), player.angle, player.go_fast, player_normal_model, player_fast_model);
}
private Camera3D startup_2_camera(startup persistent)
{
startup.cam camera = persistent.camera;
return new Camera3D(player, camera.vertical_delta.as_vector2(), camera.dist, camera.z_offset);
}
private void SetUpTerrain ()
{
using (Texture2D heightmap_bmp = Content.Load<Texture2D>("heightmap4"))
{
earth = new Terrain(heightmap_bmp, Vector3.Zero, 2.0f);
}
}
private void SetUpCylinders(startup persistent)
{
player = startup_2_cylinder(persistent);
}
private void SetUpCamera(startup persistent)
{
player_camera = startup_2_camera(persistent);
}
private Single get_floor_at(Vector2 v)
{
try
{
return earth.z_at(v);
}
catch (ArgumentOutOfRangeException)
{
return 0.0f;
}
}
protected override void Update(GameTime gameTime)
{
KeyboardEvent kev = new KeyboardEvent(Keyboard.GetState(), prevKs);
prevKs = kev.Current;
// Allows the game to exit
if (kev.IsKeyDown(Keys.Escape))
{
Exit();
return;
}
{
if (kev.WasKeyPressed(Keys.Enter))
{
startup persistent = default_persistent;
player = startup_2_cylinder(persistent);
player_camera = startup_2_camera(persistent);
}
}
Index2 input_vecdir = Index2.Zero;
int input_deltang = 0;
if (kev.IsKeyDown(Keys.D)) input_vecdir.Y -= 1;
if (kev.IsKeyDown(Keys.A)) input_vecdir.Y += 1;
if (kev.IsKeyDown(Keys.W)) input_vecdir.X += 1;
if (kev.IsKeyDown(Keys.S)) input_vecdir.X -= 1;
if (kev.IsKeyDown(Keys.Left)) input_deltang += 1;
if (kev.IsKeyDown(Keys.Right)) input_deltang -= 1;
bool player_is_do_jump = (/*player.on_floor && */(kev.WasKeyPressed(Keys.Up) || kev.WasKeyPressed(Keys.Space)));
/*
if (kev.WasKeyPressed(Keys.Home))
{
player.is_floating = !player.is_floating;
}
*/
Single s = Cylinder.move_spd;
Single a = Cylinder.turn_spd;
Single j = player_is_do_jump ? Cylinder.jump_mag : 0.0f;
if (kev.WasKeyPressed(Keys.Down))
{
player.go_fast = !player.go_fast;
}
if (player.go_fast)
{
s *= 5.0f;
a *= 3.0f;
j *= 2.0f;
}
player.angle += input_deltang * a;
if (input_vecdir)
{
Vector2 player_angdir = Vector2Ext.FromDirectionDeg(player.angle);
Vector2 move_vec = Vector2.Normalize(input_vecdir).Rotated(player_angdir);
player.position += new Vector3(move_vec, 0.0f) * s;
}
if (player_is_do_jump)
{
player.velocity.Z = j;
player.on_floor = false;
}
else
{
player.velocity.Z -= Cylinder.gravity;
}
player.position += player.velocity;
Single floor = this.get_floor_at(new Vector2(player.position.X, player.position.Y));
if (player.position.Z <= floor || player.on_floor)
{
if (player.velocity.Z < 0.0f)
{
Single minminmin = 1.5f;
player.velocity.Z *= 0.86f;
if (Math.Abs(player.velocity.Z) <= 0.125f)
{
player.velocity.Z = 0.0f;
}
if (player.position.Z <= floor && Math.Abs(player.velocity.Z) >= minminmin)
{
int n = (int)MathHelper.Lerp(5, 15, Math.Abs(player.velocity.Z) - minminmin);
Func<Vector3, Single> modifier = delegate(Vector3 v)
{
Single dist = Vector2.Distance(v.AsXY(), player.position.AsXY());
Single nn = (Single)n;
if (dist > nn)
{
return v.Z;
}
Single zoff = (MathExt.Cos(dist / nn * MathHelper.Pi) + 1.0f) / 2.0f;
zoff *= (floor - player.position.Z);
return v.Z - zoff;
};
Vector3 p = player.position;
p -= earth.position;
p /= earth.scale;
Index2 ii = new Index2((int)Math.Floor(p.X), (int)Math.Floor(p.Y)) - Index2.One * ((n - 1) / 2);
earth.set_model(ii, new Index2(n, n), modifier);
}
player.on_floor = true;
}
player.position.Z = floor;
}
{
if (kev.WasKeyPressed(Keys.NumPad5))
{
Common.Swap(ref fill_mode, ref other_fill_mode);
}
if (kev.WasKeyPressed(Keys.NumPad7))
{
cull_mode = CullMode.CullCounterClockwiseFace;
}
if (kev.WasKeyPressed(Keys.NumPad8))
{
cull_mode = CullMode.CullClockwiseFace;
}
if (kev.WasKeyPressed(Keys.NumPad9))
{
cull_mode = CullMode.None;
}
}
{
if (kev.IsKeyDown(Keys.PageUp))
{
player_camera.vertical_delta = player_camera.vertical_delta.Rotated(Vector2Ext.FromDirectionDeg(1.0f));
}
if (kev.IsKeyDown(Keys.PageDown))
{
player_camera.vertical_delta = player_camera.vertical_delta.Rotated(Vector2Ext.FromDirectionDeg(-1.0f));
}
if (kev.IsKeyDown(Keys.Home))
{
player_camera.dist -= 0.75f;
}
if (kev.IsKeyDown(Keys.End))
{
player_camera.dist += 0.75f;
}
if (kev.IsKeyDown(Keys.Insert))
{
player_camera.z_offset += 0.25f;
}
if (kev.IsKeyDown(Keys.Delete))
{
player_camera.z_offset -= 0.25f;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
RasterizerState rs = new RasterizerState();
rs.CullMode = cull_mode;
rs.FillMode = fill_mode;
GraphicsDevice.RasterizerState = rs;
GraphicsDevice.BlendState = BlendState.AlphaBlend;
GraphicsDevice.BlendFactor = Color.Red;
effect.CurrentTechnique = effect.Techniques["Colored"];
Matrix proj_matrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 0.0625f, 10000.0f);
effect.Parameters["xView"].SetValue(player_camera.ViewMatrix);
effect.Parameters["xProjection"].SetValue(proj_matrix);
Vector3 lightDirection = player_camera.to - player_camera.from;
effect.Parameters["xLightDirection"].SetValue(Vector3.Normalize(lightDirection));
effect.Parameters["xAmbient"].SetValue(0.25f);
effect.Parameters["xEnableLighting"].SetValue(true);
effect.Parameters["xWorld"].SetValue(Matrix.CreateScale(earth.scale) * Matrix.CreateTranslation(earth.position));
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
earth.Draw(GraphicsDevice);
}
foreach (Cylinder c in all_game_cylinders)
{
Matrix world_matrix = Matrix.CreateRotationZ(MathHelper.ToRadians(c.angle)) *
Matrix.CreateScale(new Vector3(new Vector2(c.radius), c.height)) *
Matrix.CreateTranslation(c.position + new Vector3(0.0f, 0.0f, c.height));
effect.Parameters["xWorld"].SetValue(world_matrix);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
player.Draw(gameTime, GraphicsDevice);
}
}
Func<int, int> flat_index = delegate(int i)
{
return 1 + i;
};
Color shadow_color = Color.Black;
int n = 24;
VertexPositionColorNormal[] vertices = new VertexPositionColorNormal[1 + n];
{
Vector2 v2 = new Vector2(player.position.X, player.position.Y);
vertices[0] = new VertexPositionColorNormal(new Vector3(v2, get_floor_at(v2)), shadow_color, Vector3.UnitZ);
}
shadow_color.A = 0;
for (int k = 0; k < n; k++)
{
Single angle = ((Single)k / (Single)n) * MathHelper.TwoPi;
Vector2 v2 = Vector2Ext.FromDirection(angle);
v2 *= player.radius * 1.125f;
v2 += new Vector2(player.position.X, player.position.Y);
vertices[flat_index(k)] = new VertexPositionColorNormal(new Vector3(v2, get_floor_at(v2)), shadow_color, Vector3.UnitZ);
}
int[] indeces = new int[(n+1) * 3];
int index = 0;
for (int k = 0; k < n; k++)
{
indeces[index++] = 0;
indeces[index++] = flat_index((k + 1)%n);
indeces[index++] = flat_index(k);
}
effect.Parameters["xWorld"].SetValue(Matrix.CreateTranslation(0.0f, 0.0f, 0.0625f));
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indeces, 0, indeces.Length / 3);
}
base.Draw(gameTime);
}
}
}