diff --git a/GameOfLife.sln b/GameOfLife.sln index dbcd493..91d17c4 100644 --- a/GameOfLife.sln +++ b/GameOfLife.sln @@ -3,9 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameOfLife", "GameOfLife\GameOfLife.csproj", "{82A1D4AF-7CCF-4328-8A9A-BA7EEC2889E8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameOfLife", "GameOfLife\GameOfLife.csproj", "{82A1D4AF-7CCF-4328-8A9A-BA7EEC2889E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SFMLGame", "SFMLGame\SFMLGame.csproj", "{0B3283B0-16CB-4E2F-B199-6155C3CB6AC0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SFMLGame", "SFMLGame\SFMLGame.csproj", "{0B3283B0-16CB-4E2F-B199-6155C3CB6AC0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameOfLife3D", "GameOfLife3D\GameOfLife3D.csproj", "{9B25978A-4E8D-4387-8A19-356D2B6BBD0F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {0B3283B0-16CB-4E2F-B199-6155C3CB6AC0}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B3283B0-16CB-4E2F-B199-6155C3CB6AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU {0B3283B0-16CB-4E2F-B199-6155C3CB6AC0}.Release|Any CPU.Build.0 = Release|Any CPU + {9B25978A-4E8D-4387-8A19-356D2B6BBD0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B25978A-4E8D-4387-8A19-356D2B6BBD0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B25978A-4E8D-4387-8A19-356D2B6BBD0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B25978A-4E8D-4387-8A19-356D2B6BBD0F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GameOfLife3D/.config/dotnet-tools.json b/GameOfLife3D/.config/dotnet-tools.json new file mode 100644 index 0000000..efabe22 --- /dev/null +++ b/GameOfLife3D/.config/dotnet-tools.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-mgcb": { + "version": "3.8.1.303", + "commands": [ + "mgcb" + ] + }, + "dotnet-mgcb-editor": { + "version": "3.8.1.303", + "commands": [ + "mgcb-editor" + ] + }, + "dotnet-mgcb-editor-linux": { + "version": "3.8.1.303", + "commands": [ + "mgcb-editor-linux" + ] + }, + "dotnet-mgcb-editor-windows": { + "version": "3.8.1.303", + "commands": [ + "mgcb-editor-windows" + ] + }, + "dotnet-mgcb-editor-mac": { + "version": "3.8.1.303", + "commands": [ + "mgcb-editor-mac" + ] + } + } +} \ No newline at end of file diff --git a/GameOfLife3D/Content/Content.mgcb b/GameOfLife3D/Content/Content.mgcb new file mode 100644 index 0000000..c0f6a3f --- /dev/null +++ b/GameOfLife3D/Content/Content.mgcb @@ -0,0 +1,53 @@ + +#----------------------------- Global Properties ----------------------------# + +/outputDir:bin/$(Platform) +/intermediateDir:obj/$(Platform) +/platform:Windows +/config: +/profile:Reach +/compress:False + +#-------------------------------- References --------------------------------# + + +#---------------------------------- Content ---------------------------------# + +#begin Models/Cube.fbx +/importer:FbxImporter +/processor:ModelProcessor +/processorParam:ColorKeyColor=0,0,0,0 +/processorParam:ColorKeyEnabled=True +/processorParam:DefaultEffect=BasicEffect +/processorParam:GenerateMipmaps=True +/processorParam:GenerateTangentFrames=False +/processorParam:PremultiplyTextureAlpha=True +/processorParam:PremultiplyVertexColors=True +/processorParam:ResizeTexturesToPowerOfTwo=False +/processorParam:RotationX=0 +/processorParam:RotationY=0 +/processorParam:RotationZ=0 +/processorParam:Scale=1 +/processorParam:SwapWindingOrder=False +/processorParam:TextureFormat=Compressed +/build:Models/Cube.fbx + +#begin Models/Cube.fbx +/importer:FbxImporter +/processor:ModelProcessor +/processorParam:ColorKeyColor=0,0,0,0 +/processorParam:ColorKeyEnabled=True +/processorParam:DefaultEffect=BasicEffect +/processorParam:GenerateMipmaps=True +/processorParam:GenerateTangentFrames=False +/processorParam:PremultiplyTextureAlpha=True +/processorParam:PremultiplyVertexColors=True +/processorParam:ResizeTexturesToPowerOfTwo=False +/processorParam:RotationX=0 +/processorParam:RotationY=0 +/processorParam:RotationZ=0 +/processorParam:Scale=1 +/processorParam:SwapWindingOrder=False +/processorParam:TextureFormat=Compressed +/build:Models/Cube.fbx + diff --git a/GameOfLife3D/Content/Models/Cube.fbx b/GameOfLife3D/Content/Models/Cube.fbx new file mode 100644 index 0000000..cf7b8db Binary files /dev/null and b/GameOfLife3D/Content/Models/Cube.fbx differ diff --git a/GameOfLife3D/GameModel/Balancing.cs b/GameOfLife3D/GameModel/Balancing.cs new file mode 100644 index 0000000..8f0c76e --- /dev/null +++ b/GameOfLife3D/GameModel/Balancing.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GameOfLife3D.GameModel +{ + //Max Val is 27 + internal static class Balancing + { + public static readonly int MIN_ALIVE = 6; + public static readonly int MAX_ALIVE = 11; + public static readonly int CREATE_MIN = 8; + public static readonly int CREATE_MAX = 9; + + } +} diff --git a/GameOfLife3D/GameModel/Cell.cs b/GameOfLife3D/GameModel/Cell.cs new file mode 100644 index 0000000..6a68617 --- /dev/null +++ b/GameOfLife3D/GameModel/Cell.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GameOfLife3D.GameModel +{ + internal struct Cell + { + public bool isAlive; + public int X, Y, Z; + + public override string ToString() + { + return $"{X}:{Y}:{Z}::{isAlive}"; + } + } +} diff --git a/GameOfLife3D/GameModel/GameOfLifeModel.cs b/GameOfLife3D/GameModel/GameOfLifeModel.cs new file mode 100644 index 0000000..cf19063 --- /dev/null +++ b/GameOfLife3D/GameModel/GameOfLifeModel.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GameOfLife3D.GameModel +{ + internal class GameOfLifeModel + { + private int X_DIM,Y_DIM,Z_DIM; + public GameOfLifeModel(int SizeX,int SizeY,int SizeZ) { + Map = new(SizeX,SizeY,SizeZ); + X_DIM = SizeX; + Y_DIM = SizeY; + Z_DIM = SizeZ; + } + + public GameOfLifeModel(int Size) + { + Map = new(Size); + X_DIM = Size; + Y_DIM = Size; + Z_DIM = Size; + } + private GameOfLifeModel() { } + + public Map Map { get; init; } + + + + + + public void Update() + { + Map.Update(); + } + } +} diff --git a/GameOfLife3D/GameModel/Map.cs b/GameOfLife3D/GameModel/Map.cs new file mode 100644 index 0000000..3c027db --- /dev/null +++ b/GameOfLife3D/GameModel/Map.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace GameOfLife3D.GameModel +{ + internal class Map + { + private Cell[,,] _Cells; + private int _SizeX, _SizeY, _SizeZ; + + public Cell[,,] Cells => _Cells; + public int AliveCell => GetAliveCells(); + + public Map SwapMap; + + + + public Map(int XSize, int YSize, int ZSize) + { + _Cells = new Cell[XSize, YSize, ZSize]; + StoreDimensions(XSize, YSize, ZSize); + InitializeCells(); + } + + private void StoreDimensions(int xSize, int ySize, int zSize) + { + _SizeX = xSize; + _SizeY = ySize; + _SizeZ = zSize; + } + + public Map(int Size) + { + _Cells = new Cell[Size, Size, Size]; + StoreDimensions(Size, Size, Size); + InitializeCells(); + } + + public void Update() + { + if (SwapMap == null) + { + SwapMap = new(_SizeX, _SizeY, _SizeZ); + } + foreach (var cell in _Cells) + { + SwapMap.GetCell(cell.X, cell.Y, cell.Z).isAlive = GetNewState(GetAliveCount(cell), cell.isAlive); + } + this.CloneFrom(SwapMap); + } + + private static bool GetNewState(int value, bool CurrentCellState) + { + if (value < Balancing.MIN_ALIVE) + return false; + if (value >= Balancing.MIN_ALIVE && value < Balancing.CREATE_MIN) + return CurrentCellState; + if (value >= Balancing.CREATE_MIN && value < Balancing.CREATE_MAX) + return true; + if (value > Balancing.CREATE_MAX && value < Balancing.MAX_ALIVE) + return CurrentCellState; + return false; + } + + private int GetAliveCount(Cell cell) + { + int AliveCount = 0; + for (int i = -1; i <= 1; i++) + { + for (int j = -1; j <= 1; j++) + { + for (int k = -1; k <= 1; k++) + { + AliveCount += GetCell(cell.X + i, cell.Y + j, cell.Z + k).isAlive ? 1 : 0; + if (AliveCount > Balancing.MAX_ALIVE) + { return AliveCount; } + } + } + } + return AliveCount; + } + + private void CloneFrom(Map source) + { + this._Cells = source.Cells; + } + + private void InitializeCells() + { + for (int i = 0; i < _Cells.GetLength(0); i++) + { + for (int j = 0; j < _Cells.GetLength(1); j++) + { + for (int k = 0; k < _Cells.GetLength(2); k++) + { + _Cells[i, j, k].X = i; + _Cells[i, j, k].Y = j; + _Cells[i, j, k].Z = k; + } + } + } + } + public ref Cell GetCell(int x, int y, int z) + { + //Clamp Values to Bound + x = Math.Clamp(x, 0, _SizeX-1); + y = Math.Clamp(y, 0, _SizeY-1); + z = Math.Clamp(z, 0, _SizeZ-1); + return ref _Cells[x, y, z]; + } + + private int GetAliveCells() + { + int aliveCount = 0; + foreach (Cell cell in _Cells) + { + aliveCount += cell.isAlive ? 1 : 0; + } + return aliveCount; + } + + public void SetRandom(int mod = 2) + { + for (int i = 0; i < _Cells.GetLength(0); i++) + { + for (int j = 0; j < _Cells.GetLength(1); j++) + { + for (int k = 0; k < _Cells.GetLength(2); k++) + { + + _Cells[i, j, k].isAlive = Random.Shared.Next() % mod == 0; + //_Cells[i, j, k].isAlive = true; + + } + } + } + } + } +} diff --git a/GameOfLife3D/GameOfLife.cs b/GameOfLife3D/GameOfLife.cs new file mode 100644 index 0000000..fb43920 --- /dev/null +++ b/GameOfLife3D/GameOfLife.cs @@ -0,0 +1,178 @@ +using GameOfLife3D.GameModel; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System; + +namespace GameOfLife3D +{ + public class GameOfLife : Game + { + private GraphicsDeviceManager _graphics; + private SpriteBatch _spriteBatch; + private GameOfLifeModel _gameOfLife; + private bool paused= false; + private Model model; + + Vector3 CameraTarget, CameraPosition; + Matrix ProjectionMatrix, ViewMatrix, WorldMatrix; + private bool orbit = false; + Matrix TranslationMatrix; + int tickcount = 0; + public GameOfLife() + { + _graphics = new GraphicsDeviceManager(this); + + _graphics.PreferredBackBufferWidth = 1920; + _graphics.PreferredBackBufferHeight = 1080; + + Content.RootDirectory = "Content"; + IsMouseVisible = true; + } + + protected override void Initialize() + { + // TODO: Add your initialization logic here + _gameOfLife = new(16); + _gameOfLife.Map.SetRandom(2); + model = Content.Load("Models/Cube"); + + CameraTarget = new(0f,0f,0f); + CameraPosition = new(0f, 0f, -30f); + + ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(60f), _graphics.GraphicsDevice.Viewport.AspectRatio, 1f, 1000f); + + ViewMatrix = Matrix.CreateLookAt(CameraPosition, CameraTarget,new Vector3(0f,1f,0f)); + + WorldMatrix = Matrix.CreateWorld(CameraTarget, Vector3.Forward, Vector3.Up); + + TranslationMatrix = Matrix.CreateTranslation(new Vector3(0f, 0f, 0f)); + + + base.Initialize(); + } + + protected override void LoadContent() + { + _spriteBatch = new SpriteBatch(GraphicsDevice); + + // TODO: use this.Content to load your game content here + } + + protected override void Update(GameTime gameTime) + { + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) + Exit(); + + if(Keyboard.GetState().IsKeyDown(Keys.P)) + { + paused = !paused; + } + + + if (Keyboard.GetState().IsKeyDown(Keys.Left)) + { + CameraPosition.X -= 0.1f; + CameraTarget.X -= 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.Right)) + { + CameraPosition.X += 0.1f; + CameraTarget.X += 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.Up)) + { + CameraPosition.Y -= 0.1f; + CameraTarget.Y -= 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.Down)) + { + CameraPosition.Y += 0.1f; + CameraTarget.Y += 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.OemPlus)) + { + CameraPosition.Z += 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.OemMinus)) + { + CameraPosition.Z -= 0.1f; + } + if (Keyboard.GetState().IsKeyDown(Keys.Space)) + { + orbit = !orbit; + } + + + if (orbit) + { + Matrix rotationMatrix = Matrix.CreateRotationY( + MathHelper.ToRadians(1f)); + CameraPosition = Vector3.Transform(CameraPosition, + rotationMatrix); + } + ViewMatrix = Matrix.CreateLookAt(CameraPosition, CameraTarget, + Vector3.Up); + + + TranslationMatrix = Matrix.CreateTranslation( + new Vector3( + 0f, + 0f, + (float)Math.Sin(gameTime.ElapsedGameTime.TotalMilliseconds)*10f)); + //WorldMatrix.Translation = TranslationMatrix.Translation; + + tickcount++; + + if (!paused) + { + if (tickcount % 20 == 0) + { + _gameOfLife.Update(); + } + } + // TODO: Add your update logic here + + base.Update(gameTime); + + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(Color.Black); + foreach (var cell in _gameOfLife.Map.Cells) + { + + foreach (ModelMesh mesh in model.Meshes) + { + foreach (BasicEffect effect in mesh.Effects) + { + + effect.EnableDefaultLighting(); + effect.AmbientLightColor = cell.isAlive ? Color.AliceBlue.ToVector3() : Color.Green.ToVector3(); + effect.View = ViewMatrix; + effect.World = Matrix.CreateTranslation(cell.X*2.1f, cell.Y*2.1f, cell.Z * 2.1f); + effect.Projection = ProjectionMatrix; + + } + + if (cell.isAlive) + { + mesh.Draw(); + } + } + + //model.Draw(WorldMatrix * Matrix.CreateTranslation(new Vector3(cell.X, cell.Y, cell.Z)), ViewMatrix, ProjectionMatrix); + } + + // TODO: Add your drawing code here + + base.Draw(gameTime); + } + + protected void GeneratorCubeModel() + { + + } + } +} diff --git a/GameOfLife3D/GameOfLife3D.csproj b/GameOfLife3D/GameOfLife3D.csproj new file mode 100644 index 0000000..7869798 --- /dev/null +++ b/GameOfLife3D/GameOfLife3D.csproj @@ -0,0 +1,22 @@ + + + WinExe + net6.0-windows + Major + false + false + true + + + app.manifest + Icon.ico + + + + + + + + + + \ No newline at end of file diff --git a/GameOfLife3D/Icon.ico b/GameOfLife3D/Icon.ico new file mode 100644 index 0000000..7d9dec1 Binary files /dev/null and b/GameOfLife3D/Icon.ico differ diff --git a/GameOfLife3D/Program.cs b/GameOfLife3D/Program.cs new file mode 100644 index 0000000..1fa4633 --- /dev/null +++ b/GameOfLife3D/Program.cs @@ -0,0 +1,3 @@ + +using var game = new GameOfLife3D.GameOfLife(); +game.Run(); diff --git a/GameOfLife3D/app.manifest b/GameOfLife3D/app.manifest new file mode 100644 index 0000000..afa95cd --- /dev/null +++ b/GameOfLife3D/app.manifest @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + + diff --git a/SFMLGame/Program.cs b/SFMLGame/Program.cs index 29a10d9..fbc8c94 100644 --- a/SFMLGame/Program.cs +++ b/SFMLGame/Program.cs @@ -81,7 +81,7 @@ namespace SFMLGame //DrawAll(ref window, ref objects); watch.Restart(); - window.Draw(GetFPSText(CurrentFPS, font)); + DrawFPSText(CurrentFPS, font, ref window); window.Draw(GetCellCountText(CellCount, font)); window.Draw(GetIterationText(game.Iteration, font)); @@ -150,7 +150,7 @@ namespace SFMLGame private static Drawable GetCellCountText(int value, Font font) { - Text ret = new Text($"CellCOunt: {value}", font); + Text ret = new Text($"Cell Count: {value}", font); ret.Position = new Vector2f(0, 40); return ret; } @@ -184,11 +184,13 @@ namespace SFMLGame //game.getActiveMap().GetCell(e.Y/4, e.X/4).isAlive = true; } - private static Text GetFPSText(int currentFPS, Font font) + private static void DrawFPSText(int currentFPS, Font font, ref RenderWindow window) { Text txt = new($"FPS: {currentFPS}", font); - return txt; + window.Draw(txt); + txt.Dispose(); + } private static void Render(in GameMap gameMap, ref VertexArray vtx) @@ -204,32 +206,11 @@ namespace SFMLGame private static void Render(in GameMap gameMap, out int DrawCalls, ref RenderWindow window) { - /** - drawables = [];//int ctn=0; - var sizeScalar = new Vector2f(4f, 4f); - RectangleShape shape = new(sizeScalar); - int drawCalls = 0; - foreach (var cell in gameMap.GetAllCells()) - { - - shape.Position = new Vector2f(cell.YCoord * 4, cell.XCoord * 4); - //shape.Scale = new(2f, 2f); - //shape.Radius = 1f; - //shape.Size = sizeScalar; - shape.FillColor = GetColor(cell); - shape.OutlineThickness = 1f; - shape.OutlineColor = Color.Black; - //window.Draw(shape); - window.Draw(shape); - drawCalls++; - //drawables.Add(shape); - //ctn++; - //vtx.Append(new Vertex(new Vector2f(cell.YCoord * 4, cell.XCoord * 4), GetColor(cell))); - }**/ - //shape.Dispose(); - +#if DEBUG + Stopwatch stopwatch = new Stopwatch(); - stopwatch.Start(); + stopwatch.Start(); +#endif var sizeScalar = new Vector2f(4f, 4f); DrawCalls = 0; VertexArray vtx = new VertexArray(PrimitiveType.Quads); @@ -256,11 +237,13 @@ namespace SFMLGame } window.Draw(vtx); vtx.Dispose(); - if(dmsg) +#if DEBUG + if (dmsg) { Console.WriteLine($"Drawing took {stopwatch.ElapsedMilliseconds}ms | {stopwatch.ElapsedTicks}ticks"); } - stopwatch.Stop(); + stopwatch.Stop(); +#endif //Console.WriteLine($"Draw Calls per Frame: {drawCalls}"); return; }