Added 3D Variant, still nedds improvment

This commit is contained in:
Jan Grießhaber
2024-10-24 16:16:43 +02:00
parent 73c8cbca39
commit 1bb56adceb
14 changed files with 577 additions and 33 deletions

View File

@@ -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

View File

@@ -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"
]
}
}
}

View File

@@ -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

Binary file not shown.

View File

@@ -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;
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}
}
}
}

178
GameOfLife3D/GameOfLife.cs Normal file
View File

@@ -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<Model>("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()
{
}
}
}

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.1.303" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>

BIN
GameOfLife3D/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

3
GameOfLife3D/Program.cs Normal file
View File

@@ -0,0 +1,3 @@

using var game = new GameOfLife3D.GameOfLife();
game.Run();

43
GameOfLife3D/app.manifest Normal file
View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="GameOfLife3D"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@@ -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;
}