From c60ebfcb55556a8a47843c633ae1e80c86b61fff Mon Sep 17 00:00:00 2001 From: Jonathan Riedel Date: Thu, 4 May 2023 10:48:40 +0200 Subject: [PATCH] =?UTF-8?q?Projektdateien=20hinzuf=C3=BCgen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CityGame.sln | 25 ++ CityGame/App.xaml | 9 + CityGame/App.xaml.cs | 17 + CityGame/AssemblyInfo.cs | 10 + CityGame/CityGame.csproj | 121 ++++++ CityGame/ColorConversionMaps.cs | 60 +++ CityGame/CustomShader.cs | 35 ++ CityGame/ImageConverter.cs | 33 ++ CityGame/MainWindow.xaml | 9 + CityGame/MainWindow.xaml.cs | 507 ++++++++++++++++++++++ CityGame/OCanvas.cs | 19 + CityGame/Pattern.cs | 85 ++++ CityGame/Properties/Resources.Designer.cs | 63 +++ CityGame/Properties/Resources.resx | 120 +++++ CityGame/Renderer.cs | 88 ++++ CityGame/Resources/BlueTint.hlsl | 9 + CityGame/Resources/Building0.png | Bin 0 -> 348 bytes CityGame/Resources/Building1.png | Bin 0 -> 285 bytes CityGame/Resources/Building2.png | Bin 0 -> 254 bytes CityGame/Resources/Building2c.png | Bin 0 -> 295 bytes CityGame/Resources/Building3.png | Bin 0 -> 274 bytes CityGame/Resources/Building3a.png | Bin 0 -> 381 bytes CityGame/Resources/Building3ab.png | Bin 0 -> 433 bytes CityGame/Resources/Building3c.png | Bin 0 -> 298 bytes CityGame/Resources/Building4.png | Bin 0 -> 266 bytes CityGame/Resources/Building4c.png | Bin 0 -> 308 bytes CityGame/Resources/Building4m.png | Bin 0 -> 280 bytes CityGame/Resources/Building5.png | Bin 0 -> 237 bytes CityGame/Resources/Building7.png | Bin 0 -> 247 bytes CityGame/Resources/Building8.png | Bin 0 -> 200 bytes CityGame/Resources/Car.png | Bin 0 -> 353 bytes CityGame/Resources/Error.png | Bin 0 -> 544 bytes CityGame/Resources/ParkingLot.png | Bin 0 -> 478 bytes CityGame/Resources/Road1.png | Bin 0 -> 410 bytes CityGame/Resources/Road2.png | Bin 0 -> 324 bytes CityGame/Resources/Road2c.png | Bin 0 -> 402 bytes CityGame/Resources/Road3c.png | Bin 0 -> 369 bytes CityGame/Resources/Road4c.png | Bin 0 -> 362 bytes CityGame/Resources/Tree.png | Bin 0 -> 736 bytes CityGame/Resources/Vent1.png | Bin 0 -> 442 bytes CityGame/Resources/Vent2.png | Bin 0 -> 514 bytes CityGame/Resources/Vent3.png | Bin 0 -> 655 bytes CityGame/SourcedImage.cs | 69 +++ CityGame/Tile.cs | 10 + CityGame/TileType.cs | 17 + 45 files changed, 1306 insertions(+) create mode 100644 CityGame.sln create mode 100644 CityGame/App.xaml create mode 100644 CityGame/App.xaml.cs create mode 100644 CityGame/AssemblyInfo.cs create mode 100644 CityGame/CityGame.csproj create mode 100644 CityGame/ColorConversionMaps.cs create mode 100644 CityGame/CustomShader.cs create mode 100644 CityGame/ImageConverter.cs create mode 100644 CityGame/MainWindow.xaml create mode 100644 CityGame/MainWindow.xaml.cs create mode 100644 CityGame/OCanvas.cs create mode 100644 CityGame/Pattern.cs create mode 100644 CityGame/Properties/Resources.Designer.cs create mode 100644 CityGame/Properties/Resources.resx create mode 100644 CityGame/Renderer.cs create mode 100644 CityGame/Resources/BlueTint.hlsl create mode 100644 CityGame/Resources/Building0.png create mode 100644 CityGame/Resources/Building1.png create mode 100644 CityGame/Resources/Building2.png create mode 100644 CityGame/Resources/Building2c.png create mode 100644 CityGame/Resources/Building3.png create mode 100644 CityGame/Resources/Building3a.png create mode 100644 CityGame/Resources/Building3ab.png create mode 100644 CityGame/Resources/Building3c.png create mode 100644 CityGame/Resources/Building4.png create mode 100644 CityGame/Resources/Building4c.png create mode 100644 CityGame/Resources/Building4m.png create mode 100644 CityGame/Resources/Building5.png create mode 100644 CityGame/Resources/Building7.png create mode 100644 CityGame/Resources/Building8.png create mode 100644 CityGame/Resources/Car.png create mode 100644 CityGame/Resources/Error.png create mode 100644 CityGame/Resources/ParkingLot.png create mode 100644 CityGame/Resources/Road1.png create mode 100644 CityGame/Resources/Road2.png create mode 100644 CityGame/Resources/Road2c.png create mode 100644 CityGame/Resources/Road3c.png create mode 100644 CityGame/Resources/Road4c.png create mode 100644 CityGame/Resources/Tree.png create mode 100644 CityGame/Resources/Vent1.png create mode 100644 CityGame/Resources/Vent2.png create mode 100644 CityGame/Resources/Vent3.png create mode 100644 CityGame/SourcedImage.cs create mode 100644 CityGame/Tile.cs create mode 100644 CityGame/TileType.cs diff --git a/CityGame.sln b/CityGame.sln new file mode 100644 index 0000000..5109268 --- /dev/null +++ b/CityGame.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CityGame", "CityGame\CityGame.csproj", "{5D76B596-FC17-4F47-B5C6-D811DE04F806}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5D76B596-FC17-4F47-B5C6-D811DE04F806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D76B596-FC17-4F47-B5C6-D811DE04F806}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D76B596-FC17-4F47-B5C6-D811DE04F806}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D76B596-FC17-4F47-B5C6-D811DE04F806}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B17891C9-0FBF-46C7-8697-0CD3D795A9FD} + EndGlobalSection +EndGlobal diff --git a/CityGame/App.xaml b/CityGame/App.xaml new file mode 100644 index 0000000..51191dd --- /dev/null +++ b/CityGame/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/CityGame/App.xaml.cs b/CityGame/App.xaml.cs new file mode 100644 index 0000000..f5fe8e0 --- /dev/null +++ b/CityGame/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace CityGame +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/CityGame/AssemblyInfo.cs b/CityGame/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/CityGame/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/CityGame/CityGame.csproj b/CityGame/CityGame.csproj new file mode 100644 index 0000000..d48a3b7 --- /dev/null +++ b/CityGame/CityGame.csproj @@ -0,0 +1,121 @@ + + + + WinExe + net6.0-windows + enable + true + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/CityGame/ColorConversionMaps.cs b/CityGame/ColorConversionMaps.cs new file mode 100644 index 0000000..68f95bd --- /dev/null +++ b/CityGame/ColorConversionMaps.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CityGame +{ + public class ColorConversionMaps + { + + public static Dictionary HouseToLakeMap = new Dictionary + { + { "#616161", "#006bb3" }, + { "#3b3b3b", "#005485" } + }; + public static Dictionary LakeToRiver = new Dictionary + { + { "#006bb3", "#005ba3" }, + { "#005485", "#004475" } + }; + public static Dictionary HouseToBuildingDarkMap = new Dictionary + { + { "#616161", "#3b3b3b" }, + { "#3b3b3b", "#1b1b1b" } + }; + public static Dictionary HouseToBuildingBlueMap = new Dictionary + { + { "#616161", "#616181" }, + { "#3b3b3b", "#3b3b5b" } + }; + public static Dictionary HouseToBuildingRedMap = new Dictionary + { + { "#616161", "#816161" }, + { "#3b3b3b", "#5b3b3b" } + }; + public static Dictionary HouseToBuildingGreenMap = new Dictionary + { + { "#616161", "#618161" }, + { "#3b3b3b", "#3b5b3b" } + }; + public static Dictionary HouseToParkMap = new Dictionary + { + { "#616161", "#00a34b" }, + { "#3b3b3b", "#007534" } + }; + public static Dictionary RoadToPathMap = new Dictionary() + { + { "#00000000", "#00b36b00" }, + { "#616161", "#00b36b00" }, + { "#303030", "#8a5e00" }, + { "#ffffff", "#8a5e00" } + }; + public static Dictionary RoadToBridgeMap = new Dictionary() + { + { "#00000000", "#00b36b00" }, + { "#616161", "#00b36b00" } + }; + } +} diff --git a/CityGame/CustomShader.cs b/CityGame/CustomShader.cs new file mode 100644 index 0000000..451c60b --- /dev/null +++ b/CityGame/CustomShader.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Effects; + +namespace CityGame +{ + public class CustomShader : ShaderEffect + { + private const string _kshaderAsBase64 = @"AAP///7/HwBDVEFCHAAAAE8AAAAAA///AQAAABwAAAAAAQAASAAAADAAAAADAAAAAQACADgAAAAAAAAAaW5wdXQAq6sEAAwAAQABAAEAAAAAAAAAcHNfM18wAE1pY3Jvc29mdCAoUikgSExTTCBTaGFkZXIgQ29tcGlsZXIgMTAuMQCrUQAABQAAD6AAAIA/AAAAAAAAAAAAAAAAHwAAAgUAAIAAAAOQHwAAAgAAAJAACA+gQgAAAwAAD4AAAOSQAAjkoAEAAAIACAuAAADkgAEAAAIACASAAAAAoP//AAA="; + private readonly PixelShader _shader; + + public CustomShader(string shaderName) + { + _shader = new PixelShader(); + using (var stream = new MemoryStream(Convert.FromBase64String(_kshaderAsBase64))) + { + _shader.SetStreamSource(stream); + } + PixelShader = _shader; + UpdateShaderValue(InputProperty); + } + + public Brush Input + { + get { return (Brush)GetValue(InputProperty); } + set { SetValue(InputProperty, value); } + } + + public static readonly DependencyProperty InputProperty = + ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(CustomShader), 0); + + } +} \ No newline at end of file diff --git a/CityGame/ImageConverter.cs b/CityGame/ImageConverter.cs new file mode 100644 index 0000000..7b030a7 --- /dev/null +++ b/CityGame/ImageConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace CityGame +{ + public class ImageConverter + { + public static void ChangeColor(string srcFile, string destFile, Dictionary conversions) + { + destFile = Environment.CurrentDirectory + "\\Resources\\" + destFile + ".png"; + //if (File.Exists(destFile)) return; + srcFile = Environment.CurrentDirectory + "\\Resources\\" + srcFile + ".png"; + if (!File.Exists(srcFile)) return; + + Dictionary Conversions = conversions.Select(x => new KeyValuePair(System.Drawing.ColorTranslator.FromHtml(x.Key), System.Drawing.ColorTranslator.FromHtml(x.Value))).ToDictionary(x => x.Key, x => x.Value); + System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromFile(srcFile); + for (int x = 0; x < bmp.Width; x++) + { + for (int y = 0; y < bmp.Height; y++) + { + var color = bmp.GetPixel(x, y); + if (Conversions.ContainsKey(color)) + { + bmp.SetPixel(x, y, Conversions[color]); + } + } + } + bmp.Save(destFile); + } + } +} \ No newline at end of file diff --git a/CityGame/MainWindow.xaml b/CityGame/MainWindow.xaml new file mode 100644 index 0000000..0c6d5c3 --- /dev/null +++ b/CityGame/MainWindow.xaml @@ -0,0 +1,9 @@ + + diff --git a/CityGame/MainWindow.xaml.cs b/CityGame/MainWindow.xaml.cs new file mode 100644 index 0000000..0971332 --- /dev/null +++ b/CityGame/MainWindow.xaml.cs @@ -0,0 +1,507 @@ +using AStar; +using AStar.Options; +using SimplexNoise; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.WebSockets; +using System.Numerics; +using System.Reflection.Metadata; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; + +namespace CityGame +{ + public abstract class Entity + { + public float X { get; set; } + public float Y { get; set; } + public float Rotation { get; set; } + public long Time { get; set; } + public OCanvas Object { get; set; } + public abstract OCanvas Render(); + public abstract void Tick(long deltaTime); + } + public static class Extensions + { + public static System.Drawing.Point Convert(this Point point) + { + return new System.Drawing.Point((int)point.X, (int)point.Y); + } + public static Point Convert(this System.Drawing.Point point) + { + return new Point(point.X, point.Y); + } + public static bool CloselyEquals(this double A, double B) + { + return Math.Round(A) == Math.Round(B); + } + public static bool CloselyEquals(this float A, double B) + { + return Math.Round(A) == Math.Round(B); + } + } + public class Car : Entity + { + public delegate void CarEvent(Car car); + public event CarEvent JourneyFinished; + public event CarEvent JourneyImpossible; + public Point? Target { get; set; } = null; + public int NextTarget { get; set; } = 0; + public Point[]? Path { get; set; } = null; + public Point Point { + get + { + return new Point((int)X / MainWindow.TileSize, (int)Y / MainWindow.TileSize); + } + set + { + X = (float)value.X * MainWindow.TileSize; + Y = (float)value.Y * MainWindow.TileSize; + } + } + public float Speed { get; set; } = 256; + public override OCanvas Render() + { + return new SourcedImage("Car.png"); + } + + public override void Tick(long deltaTime) + { + if(Target is not null) + { + if (Path is null) + { + Path = MainWindow.pathfinder.FindPath(Point.Convert(), ((Point)Target).Convert()).Select(x => x.Convert()).ToArray(); + NextTarget = 0; + } + if (Path.Length == 0) + { + JourneyImpossible(this); + return; + } + Point nextTarget = Path[NextTarget]; + if (X.CloselyEquals(nextTarget.X * MainWindow.TileSize) && Y.CloselyEquals(nextTarget.Y * MainWindow.TileSize)) + { + NextTarget++; + } + if(NextTarget == Path.Length) + { + Path = null; + Target = null; + NextTarget = 0; + JourneyFinished(this); + return; + } + if (X.CloselyEquals(nextTarget.X * MainWindow.TileSize) && Y.CloselyEquals(nextTarget.Y * MainWindow.TileSize)) + return; + Vector2 travel = new Vector2((float)nextTarget.X * 64 - X, (float)nextTarget.Y * 64 - Y); + Vector2 direction = Vector2.Normalize(travel); + float degrees = (float)(Math.Atan2(direction.Y, direction.X) * (180 / Math.PI)) + 90; + Rotation = degrees; + var possibleDistance = Speed * deltaTime / 1000; + var finalDistance = Math.Min(possibleDistance, travel.Length()); + Vector2 travelFinal = direction * finalDistance; + X += travelFinal.X; + Y += travelFinal.Y; + } + } + } + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public static Random random; + public static bool MouseIsDown = false; + public static Point MousePos = new Point(0, 0); + public static PathFinder pathfinder; + public static short[,] pathfindingGrid; + public static List npcWalkable = new List(); + public static List Entities { get; set; } = new List(); + public const int TileSize = 64; + public MainWindow() + { + #region | Texture Conversions | + string[] patternCodes = new[] { "0", "1", "2", "2c", "3", "3a", "3ab", "3c", "4", "4m", "4c", "5", "7", "8" }; + + foreach (var code in patternCodes) + { + ImageConverter.ChangeColor("Building" + code, "Lake" + code, ColorConversionMaps.HouseToLakeMap); + ImageConverter.ChangeColor("Lake" + code, "River" + code, ColorConversionMaps.LakeToRiver); + ImageConverter.ChangeColor("Building" + code, "BuildingDark" + code, ColorConversionMaps.HouseToBuildingDarkMap); + ImageConverter.ChangeColor("Building" + code, "BuildingBlue" + code, ColorConversionMaps.HouseToBuildingBlueMap); + ImageConverter.ChangeColor("Building" + code, "BuildingRed" + code, ColorConversionMaps.HouseToBuildingRedMap); + ImageConverter.ChangeColor("Building" + code, "BuildingGreen" + code, ColorConversionMaps.HouseToBuildingGreenMap); + ImageConverter.ChangeColor("Building" + code, "Park" + code, ColorConversionMaps.HouseToParkMap); + ImageConverter.ChangeColor("Road" + code, "Path" + code, ColorConversionMaps.RoadToPathMap); + ImageConverter.ChangeColor("Road" + code, "Bridge" + code, ColorConversionMaps.RoadToBridgeMap); + } + ImageConverter.ChangeColor("ParkingLot", "ParkingLotDark", ColorConversionMaps.HouseToBuildingDarkMap); + ImageConverter.ChangeColor("ParkingLot", "ParkingLotBlue", ColorConversionMaps.HouseToBuildingBlueMap); + ImageConverter.ChangeColor("ParkingLot", "ParkingLotRed", ColorConversionMaps.HouseToBuildingRedMap); + ImageConverter.ChangeColor("ParkingLot", "ParkingLotGreen", ColorConversionMaps.HouseToBuildingGreenMap); + + ImageConverter.ChangeColor("Error", "ErrorRed", new Dictionary { { "#000000", "#ff0000" } }); + #endregion + + InitializeComponent(); + + #region | Map Generation | + #region | Map Generation Constants | + int seed = 1; + + Noise.Seed = seed; + + int mapHeight = 100; + int mapWidth = 100; + + float[,] lakeMap = Noise.Calc2D(mapWidth, mapHeight, 0.05f); + + Noise.Seed = seed * 24 + 1; + float[,] parkMap = Noise.Calc2D(mapWidth, mapHeight, 0.05f); + + Noise.Seed = Noise.Seed * 24 + 1; + float[,] riverMap = Noise.Calc2D(mapWidth, mapHeight, 0.01f); + + mapHeight /= 2; + mapWidth /= 2; + + int doubleHeight = mapHeight * 2; + int doubleWidth = mapWidth * 2; + + int maxBlockHeight = 5; + int maxBlockWidth = 5; + int minBlockHeight = 3; + int minBlockWidth = 3; + + int NPCCount = 100; + + random = new Random(seed); + + #endregion + + #region | Map Initialization | + Tile[,] InitialGrid = new Tile[mapWidth, mapHeight]; + + List> coords = new List>(); + for (int y = 0; y < mapHeight; y++) + { + for (int x = 0; x < mapWidth; x++) + { + coords.Add(new Tuple(x, y)); + } + } + + coords = coords.OrderBy(x => random.Next(0, coords.Count)).ToList(); + + #endregion + + #region | Main Algorithm | + + int i = 0; + foreach (var coord in coords) + { + int x = coord.Item1; + int y = coord.Item2; + + int height = random.Next(minBlockHeight, maxBlockHeight + 1); + int width = random.Next(minBlockWidth, maxBlockWidth + 1); + int yOffset = random.Next(0, height); + int xOffset = random.Next(0, width); + + TileType BlockType = TileType.Skyscraper; + + for (int y2 = y - yOffset; y2 < y - yOffset + height; y2++) + { + for (int x2 = x - xOffset; x2 < x - xOffset + width; x2++) + { + if (x2 < 0) continue; + if (y2 < 0) continue; + if (x2 >= mapWidth) continue; + if (y2 >= mapHeight) continue; + InitialGrid[x2, y2].BlockID = i; + InitialGrid[x2, y2].Type = BlockType; + if (lakeMap[x2, y2] > 214) InitialGrid[x2, y2].Type = TileType.Park; + if (lakeMap[x2, y2] > 219) InitialGrid[x2, y2].Type = TileType.Lake; + if (parkMap[x2, y2] > 214 && parkMap[x2, y2] > lakeMap[x2, y2]) InitialGrid[x2, y2].Type = TileType.Park; + if (riverMap[x2, y2] > 128 && riverMap[x2,y2] < 148) InitialGrid[x2, y2].Type = TileType.River; + + + } + } + + i++; + } + + #endregion + + #region | Doubling | + + Tile[,] IntermediateGrid = new Tile[doubleWidth, doubleHeight]; + for (int y = 0; y < mapHeight; y++) + { + for (int x = 0; x < mapWidth; x++) + { + IntermediateGrid[x * 2, y * 2] = InitialGrid[x, y]; + IntermediateGrid[x * 2, y * 2 + 1] = InitialGrid[x, y]; + IntermediateGrid[x * 2 + 1, y * 2 + 1] = InitialGrid[x, y]; + IntermediateGrid[x * 2 + 1, y * 2] = InitialGrid[x, y]; + + IntermediateGrid[x * 2, y * 2].X = x * 2; + IntermediateGrid[x * 2, y * 2].Y = y * 2; + + IntermediateGrid[x * 2, y * 2 + 1].X = x * 2; + IntermediateGrid[x * 2, y * 2 + 1].Y = y * 2 + 1; + + IntermediateGrid[x * 2 + 1, y * 2 + 1].X = x * 2 + 1; + IntermediateGrid[x * 2 + 1, y * 2 + 1].Y = y * 2 + 1; + + IntermediateGrid[x * 2 + 1, y * 2].X = x * 2 + 1; + IntermediateGrid[x * 2 + 1, y * 2].Y = y * 2; + } + } + #endregion + + #region | Roads and Bridges | + Dictionary decidedBridges = new Dictionary(); + pathfindingGrid = new short[doubleWidth, doubleHeight]; + List bridgeTiles = new List(); + List roadTiles = new List(); + for (int y = 0; y < doubleHeight; y++) + { + for (int x = 0; x < doubleWidth; x++) + { + TileType changeTo = TileType.Road; + int myID = IntermediateGrid[x, y].BlockID; + if (IntermediateGrid[x, y].Type == TileType.Lake || IntermediateGrid[x, y].Type == TileType.River) + { + if (!decidedBridges.ContainsKey(myID)) + { + decidedBridges[myID] = random.Next(0, 2) == 0; + } + if (decidedBridges[myID]) + { + changeTo = TileType.Bridge; + } + else + { + continue; + } + } + if (IntermediateGrid[x, y].Type == TileType.Park) changeTo = TileType.Path; + if (x < doubleWidth - 1 && IntermediateGrid[x + 1, y].BlockID != myID) IntermediateGrid[x, y].Type = changeTo; + if (y < doubleHeight - 1 && IntermediateGrid[x, y + 1].BlockID != myID) IntermediateGrid[x, y].Type = changeTo; + bool walkable = ((int)IntermediateGrid[x, y].Type) / 100 == 4; + pathfindingGrid[y, x] = (short)(walkable ? 1 : 0); + if (IntermediateGrid[x, y].Type == TileType.Bridge) bridgeTiles.Add(IntermediateGrid[x, y]); + if (IntermediateGrid[x, y].Type == TileType.Road) roadTiles.Add(IntermediateGrid[x, y]); + if (IntermediateGrid[x, y].Type == TileType.Road || IntermediateGrid[x, y].Type == TileType.Bridge) npcWalkable.Add(IntermediateGrid[x, y]); + } + } + + #endregion + + #region | Pathfinding | + + var worldGrid = new WorldGrid(pathfindingGrid); + pathfinder = new PathFinder(worldGrid, new PathFinderOptions { PunishChangeDirection = true, UseDiagonals = false, SearchLimit = int.MaxValue, HeuristicFormula = AStar.Heuristics.HeuristicFormula.Euclidean }); + + //foreach(var tile in bridgeTiles) + //{ + // List sortedRoads = roadTiles.OrderBy(x => Math.Abs(x.X - tile.X) + Math.Abs(x.Y - tile.Y)).ToList(); + // if(!sortedRoads.Any(x => pathfinder.FindPath(new System.Drawing.Point(x.X, x.Y), new System.Drawing.Point(tile.X, tile.Y)).Length > 0)) + // { + // IntermediateGrid[tile.X, tile.Y].Type = TileType.House; + // } + // i++; + //} + + int mainRoadCount = random.Next(1, 2); + for(int m = 0; m < mainRoadCount; m++) + { + int variant = random.Next(0, 2); + Point startPoint = new Point(0, 0); + Point endPoint = new Point(0, 0); + } + + #endregion + + Tile[,] Grid = IntermediateGrid; + //for(int y = 0; y < mapHeight; y++) + //{ + // for(int x = 0; x < mapWidth; x++) + // { + // Grid[x, y] = IntermediateGrid[x * 2 + 1, y * 2 + 1]; + // } + //} + + mapHeight *= 2; + mapWidth *= 2; + + #endregion + + Show(); + + #region | Rendering | + + Canvas MainCanvas = new OCanvas(); + Canvas BGCanvas = new OCanvas(); + Canvas GameCanvas = new OCanvas(); + Canvas CameraCanvas = new OCanvas(); + Canvas UICanvas = new OCanvas(); + + Canvas.SetLeft(CameraCanvas, 0); + Canvas.SetTop(CameraCanvas, 0); + + RenderOptions.SetEdgeMode(GameCanvas, EdgeMode.Aliased); + + MainCanvas.Children.Add(CameraCanvas); + MainCanvas.Children.Add(UICanvas); + + CameraCanvas.Children.Add(BGCanvas); + CameraCanvas.Children.Add(GameCanvas); + + MainCanvas.HorizontalAlignment = HorizontalAlignment.Left; + MainCanvas.VerticalAlignment = VerticalAlignment.Top; + + Content = MainCanvas; + + int tileSize = TileSize; + for (int x = 0; x < mapWidth; x++) + { + for (int y = 0; y < mapHeight; y++) + { + Canvas image = Renderer.Render(Grid[x, y].Type, x, y, Grid); + + image.Height = tileSize; + image.Width = tileSize; + + RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.NearestNeighbor); + + Canvas.SetLeft(image, x * tileSize); + Canvas.SetTop(image, y * tileSize); + + //image.Opacity = pathfindingGrid[y, x]; + + GameCanvas.Children.Add(image); + } + } + + #endregion + + #region | Controls | + + MainCanvas.MouseDown += (a, b) => MouseIsDown = true; + MainCanvas.MouseUp += (a, b) => MouseIsDown = false; + MainCanvas.MouseMove += (a, b) => + { + if (MouseIsDown) + { + var newpos = PointToScreen(Mouse.GetPosition(this)); + var diff = newpos - MousePos; + Canvas.SetLeft(CameraCanvas, Canvas.GetLeft(CameraCanvas) + diff.X); + Canvas.SetTop(CameraCanvas, Canvas.GetTop(CameraCanvas) + diff.Y); + } + MousePos = PointToScreen(Mouse.GetPosition(this)); + }; + + ScaleTransform scale = new ScaleTransform(1, 1); + CameraCanvas.RenderTransform = scale; + + MainCanvas.MouseWheel += (a, b) => + { + float multi = 0.952f; + if (b.Delta > 0) multi = 1.05f; + + scale.ScaleX *= multi; + scale.ScaleY *= multi; + + if (b.Delta < 0) + { + scale.ScaleX = Math.Floor(scale.ScaleX * 100) / 100f; + scale.ScaleY = Math.Floor(scale.ScaleY * 100) / 100f; + } + else + { + scale.ScaleX = Math.Ceiling(scale.ScaleX * 100) / 100f; + scale.ScaleY = Math.Ceiling(scale.ScaleY * 100) / 100f; + } + + Debug.WriteLine(scale.ScaleX); + }; + #endregion + + #region | Entities | + + DispatcherTimer EntityLoop = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1 / 20) }; + EntityLoop.Tick += (a, b) => + { + long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + foreach(Entity entity in Entities) + { + long delta = milliseconds - entity.Time; + entity.Time = milliseconds; + entity.Tick(delta); + + if(entity.Object is null) + { + entity.Object = entity.Render(); + RenderOptions.SetBitmapScalingMode(entity.Object, BitmapScalingMode.NearestNeighbor); + var rt = new RotateTransform(entity.Rotation); + rt.CenterX = MainWindow.TileSize / 2; + rt.CenterY = MainWindow.TileSize / 2; + entity.Object.RenderTransform = rt; + GameCanvas.Children.Add(entity.Object); + } + ((RotateTransform)entity.Object.RenderTransform).Angle = entity.Rotation; + Canvas.SetLeft(entity.Object, entity.X); + Canvas.SetTop(entity.Object, entity.Y); + + } + }; + EntityLoop.Start(); + + #endregion + + for(int n = 0; n < NPCCount; n++) + { + Car car = new Car(); + Tile startTile = npcWalkable[random.Next(0, npcWalkable.Count)]; + Tile targetTile = npcWalkable[random.Next(0, npcWalkable.Count)]; + + car.Point = new Point(startTile.X, startTile.Y); + + car.Target = new Point(targetTile.X, targetTile.Y); + + Car.CarEvent reset = car => + { + Tile targetTile = npcWalkable[random.Next(0, npcWalkable.Count)]; + DispatcherTimer delay = new DispatcherTimer { Interval = TimeSpan.FromSeconds(random.Next(1, 5)) }; + delay.Tick += (a, b) => + { + car.Target = new Point(targetTile.X, targetTile.Y); + delay.Stop(); + }; + delay.Start(); + }; + + car.JourneyFinished += reset; + car.JourneyImpossible += reset; + + Entities.Add(car); + } + } + } +} \ No newline at end of file diff --git a/CityGame/OCanvas.cs b/CityGame/OCanvas.cs new file mode 100644 index 0000000..c4d8ce8 --- /dev/null +++ b/CityGame/OCanvas.cs @@ -0,0 +1,19 @@ +using System.Windows.Controls; + +namespace CityGame +{ + public class OCanvas : Canvas + { + public static implicit operator OCanvas(Image image) + { + OCanvas canvas = new OCanvas(); + canvas.Children.Add(image); + return canvas; + } + public OCanvas() : base() + { + this.Height = 100; + this.Width = 100; + } + } +} \ No newline at end of file diff --git a/CityGame/Pattern.cs b/CityGame/Pattern.cs new file mode 100644 index 0000000..64dc2ef --- /dev/null +++ b/CityGame/Pattern.cs @@ -0,0 +1,85 @@ +using System; +using System.Linq; + +namespace CityGame +{ + public class Pattern + { + public string PatternCode { get; set; } + public int Rotation { get; set; } + public Pattern(string pattern) + { + PatternCode = pattern; + Rotation = 0; + } + public Pattern(string pattern, int rotation) + { + PatternCode = pattern; + Rotation = rotation; + } + public Pattern(string pattern, string rotation) + { + PatternCode = pattern; + int.TryParse(rotation, out int rot); + Rotation = rot; + } + public static Pattern Calculate(Tile[,] Grid, int x, int y, params TileType[] allowed) + { + Func IsAdjacent = (X, Y) => + { + if (!Renderer.IsInGrid(Grid, X, Y)) return false; + if (Grid[x, y].BlockID != Grid[X, Y].BlockID && Grid[x, y].Type == TileType.Skyscraper) return false; + return allowed.Contains(Grid[X, Y].Type); + }; + + if (IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1)) return new Pattern("8"); + + if (IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1)) return new Pattern("7"); + if (IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1)) return new Pattern("7", "90"); + if (IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1)) return new Pattern("7", "180"); + if (IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1)) return new Pattern("7", "270"); + + if (IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x + 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1)) return new Pattern("5"); + if (IsAdjacent(x, y - 1) && IsAdjacent(x - 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y + 1)) return new Pattern("5", "180"); + if (IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y)) return new Pattern("5", "270"); + if (IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y + 1) && IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y)) return new Pattern("5", "90"); + + if (IsAdjacent(x - 1, y) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x + 1, y)) return new Pattern("4"); + if (IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y) && IsAdjacent(x + 1, y + 1) && IsAdjacent(x, y + 1)) return new Pattern("4", "90"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x - 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1)) return new Pattern("4", "180"); + if (IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y) && IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1)) return new Pattern("4", "270"); + + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x - 1, y - 1)) return new Pattern("4m"); + if (IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y) && IsAdjacent(x, y - 1) && IsAdjacent(x + 1, y - 1)) return new Pattern("4m", "90"); + if (IsAdjacent(x - 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x + 1, y) && IsAdjacent(x + 1, y + 1)) return new Pattern("4m", "180"); + if (IsAdjacent(x, y - 1) && IsAdjacent(x - 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y + 1)) return new Pattern("4m", "270"); + + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y) && IsAdjacent(x, y - 1)) return new Pattern("4c"); + + if (IsAdjacent(x + 1, y) && IsAdjacent(x + 1, y + 1) && IsAdjacent(x, y + 1)) return new Pattern("3"); + if (IsAdjacent(x - 1, y) && IsAdjacent(x - 1, y + 1) && IsAdjacent(x, y + 1)) return new Pattern("3", "90"); + if (IsAdjacent(x - 1, y) && IsAdjacent(x - 1, y - 1) && IsAdjacent(x, y - 1)) return new Pattern("3", "180"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x + 1, y - 1) && IsAdjacent(x, y - 1)) return new Pattern("3", "270"); + + if (IsAdjacent(x, y - 1) && IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y)) return new Pattern("3c"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y - 1) && IsAdjacent(x - 1, y)) return new Pattern("3c", "90"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y - 1) && IsAdjacent(x, y + 1)) return new Pattern("3c", "180"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y + 1) && IsAdjacent(x - 1, y)) return new Pattern("3c", "270"); + + if (IsAdjacent(x - 1, y) && IsAdjacent(x + 1, y)) return new Pattern("2", "90"); + if (IsAdjacent(x, y - 1) && IsAdjacent(x, y + 1)) return new Pattern("2"); + + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y + 1)) return new Pattern("2c"); + if (IsAdjacent(x - 1, y) && IsAdjacent(x, y + 1)) return new Pattern("2c", "90"); + if (IsAdjacent(x - 1, y) && IsAdjacent(x, y - 1)) return new Pattern("2c", "180"); + if (IsAdjacent(x + 1, y) && IsAdjacent(x, y - 1)) return new Pattern("2c", "270"); + + if (IsAdjacent(x + 1, y)) return new Pattern("1"); + if (IsAdjacent(x - 1, y)) return new Pattern("1", "180"); + if (IsAdjacent(x, y + 1)) return new Pattern("1", "90"); + if (IsAdjacent(x, y - 1)) return new Pattern("1", "270"); + + return new Pattern("0"); + } + } +} \ No newline at end of file diff --git a/CityGame/Properties/Resources.Designer.cs b/CityGame/Properties/Resources.Designer.cs new file mode 100644 index 0000000..003deb5 --- /dev/null +++ b/CityGame/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace CityGame.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CityGame.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/CityGame/Properties/Resources.resx b/CityGame/Properties/Resources.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CityGame/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CityGame/Renderer.cs b/CityGame/Renderer.cs new file mode 100644 index 0000000..fd03451 --- /dev/null +++ b/CityGame/Renderer.cs @@ -0,0 +1,88 @@ +using System.Windows.Controls; + +namespace CityGame +{ + public class Renderer + { + public static bool IsRoad(Tile[,] Grid, int x, int y) + { + return IsInGrid(Grid, x, y) && (Grid[x, y].Type == TileType.Road || Grid[x, y].Type == TileType.Bridge); + } + public static bool IsInGrid(Tile[,] Grid, int x, int y) + { + return !(x < 0 || y < 0 || x >= Grid.GetLength(0) || y >= Grid.GetLength(1)); + } + public static bool IsBuilding(Tile[,] Grid, int x, int y) + { + return IsInGrid(Grid, x, y) && (Grid[x, y].Type == TileType.Skyscraper || Grid[x, y].Type == TileType.House); + } + public static OCanvas Render(TileType type, int x, int y, Tile[,] Grid) + { + if (type == TileType.Skyscraper) + { + string theme = ""; + if (Grid[x, y].BlockID % 2 == 1) theme = "Dark"; + if (Grid[x, y].BlockID % 30 == 1) theme = "Blue"; + if (Grid[x, y].BlockID % 30 == 2) theme = "Red"; + if (Grid[x, y].BlockID % 30 == 3) theme = "Green"; + Pattern pattern = Pattern.Calculate(Grid, x, y, TileType.Skyscraper); + if (pattern.PatternCode == "1" && MainWindow.random.Next(0, 3) == 0) return new SourcedImage("ParkingLot"+theme+".png:" + pattern.Rotation); + if (pattern.PatternCode == "3" && MainWindow.random.Next(0, 12) == 0) pattern.PatternCode = "3a"; + if (pattern.PatternCode == "3" && MainWindow.random.Next(0, 12) == 1) pattern.PatternCode = "3ab"; + OCanvas canvas = new SourcedImage("Building"+ theme + pattern.PatternCode + ".png:" + pattern.Rotation); + + if (MainWindow.random.Next(0, 10) == 0 && pattern.PatternCode != "3a") canvas.Children.Add(new SourcedImage("Vent" + (MainWindow.random.Next(0, 3) + 1) + ".png:" + (MainWindow.random.Next(0, 4) * 90))); + + return canvas; + } + if (type == TileType.Lake || type == TileType.River) + { + Pattern pattern = Pattern.Calculate(Grid, x, y, TileType.Lake, TileType.Bridge, TileType.River); + return new SourcedImage("Lake" + pattern.PatternCode + ".png:" + pattern.Rotation); + } + if (type == TileType.Park) + { + Pattern pattern = Pattern.Calculate(Grid, x, y, TileType.Park, TileType.Path); + OCanvas canvas = new SourcedImage("Park" + pattern.PatternCode + ".png:" + pattern.Rotation); + if (MainWindow.random.Next(0, 4) == 0) canvas.Children.Add(new SourcedImage("Tree.png:" + MainWindow.random.Next(0,4) * 90)); + return canvas; + } + if (type == TileType.Road) + { + Pattern pattern = Pattern.Calculate(Grid, x, y, TileType.Road, TileType.Path, TileType.Bridge); + if (pattern.PatternCode == "2c") pattern.Rotation += 270; + if (pattern.PatternCode == "1") pattern.Rotation += 180; + return new SourcedImage("Road" + pattern.PatternCode + ".png:" + pattern.Rotation); + } + if (type == TileType.Path) + { + Pattern roadpattern = Pattern.Calculate(Grid, x, y, TileType.Road, TileType.Path, TileType.Bridge); + Pattern parkpattern = Pattern.Calculate(Grid, x, y, TileType.Path, TileType.Park); + if (roadpattern.PatternCode == "2c") roadpattern.Rotation += 270; + if (roadpattern.PatternCode == "1") roadpattern.Rotation += 180; + Image path = new SourcedImage("Path" + roadpattern.PatternCode + ".png:" + roadpattern.Rotation); + Image park = new SourcedImage("Park" + parkpattern.PatternCode + ".png:" + parkpattern.Rotation); + + OCanvas result = new OCanvas(); + result.Children.Add(park); + result.Children.Add(path); + return result; + } + if (type == TileType.Bridge) + { + Pattern roadpattern = Pattern.Calculate(Grid, x, y, TileType.Road, TileType.Bridge, TileType.Path); + Pattern parkpattern = Pattern.Calculate(Grid, x, y, TileType.Bridge, TileType.Lake, TileType.River); + if (roadpattern.PatternCode == "2c") roadpattern.Rotation += 270; + if (roadpattern.PatternCode == "1") roadpattern.Rotation += 180; + Image path = new SourcedImage("Bridge" + roadpattern.PatternCode + ".png:" + roadpattern.Rotation); + Image park = new SourcedImage("Lake" + parkpattern.PatternCode + ".png:" + parkpattern.Rotation); + + OCanvas result = new OCanvas(); + result.Children.Add(park); + result.Children.Add(path); + return result; + } + return new SourcedImage("Error.png"); + } + } +} \ No newline at end of file diff --git a/CityGame/Resources/BlueTint.hlsl b/CityGame/Resources/BlueTint.hlsl new file mode 100644 index 0000000..b356f0d --- /dev/null +++ b/CityGame/Resources/BlueTint.hlsl @@ -0,0 +1,9 @@ +Texture2D inputTexture : register(t0); +SamplerState inputSampler : register(s0); + +float4 main(float2 uv : TEXCOORD) : SV_Target +{ + float4 color = inputTexture.Sample(inputSampler, uv); + float4 grayscaleColor = float4(dot(color.rgb, float3(0.299, 0.587, 0.114)), dot(color.rgb, float3(0.299, 0.587, 0.114)), dot(color.rgb, float3(0.299, 0.587, 0.114)), color.a); + return grayscaleColor; +} \ No newline at end of file diff --git a/CityGame/Resources/Building0.png b/CityGame/Resources/Building0.png new file mode 100644 index 0000000000000000000000000000000000000000..f3fc232b1f0b09173ec4b90a0231692cf12e1757 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z#XMacLn`9l z-aaeX!W zUXm!mx4Gu~;Wv%Poo_R5Wuyc?X;K*n( zagtJ;yCCd_PJ)CHuT*>Q;bRZ4tUvOD!S2Cy21Tb1pYe58)EplObR z`U%b=6zZBwgOGM;(){4{xk`Js7;IzFVdQ&MBb@0A+!R`2YX_ literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building1.png b/CityGame/Resources/Building1.png new file mode 100644 index 0000000000000000000000000000000000000000..a7de14897a048a6d7003a12e29777983504a6c0c GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|u6w#ThE&A8 zy?vXvL4k)gAhu2QM!jBdpisz#|KD~vu7A33N~!0+H7B3PGbAwA39Q(fH_>sHT;q%8 z?bEGT7Rc|LB2>wEOyvechuxo#Y4Oq%GAkHvFt{_YD;!*YBDnGNue1*gDHC`mIU0Ge zoqWK|XxG4RVeR0iQ6XyfmZgw^?*OC61g;5=b`64$SS%0Th;NO2$j#V0!OcUt#N9zg zto>+WVFVKO@Irm(YvwPE>P%b{FFKwV>5QE@GqCoRcd)I-#m0hSlh)fmB`&e0+;5Oo YKUVtE?kMA8pcffDUHx3vIVCg!0K~Lx3jhEB literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building2.png b/CityGame/Resources/Building2.png new file mode 100644 index 0000000000000000000000000000000000000000..c3af0ffdcf59c321bf0fb2d98dcdaf7d37203a62 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|c6hothE&A8 zy?IcuL4k+GA+t?w#eB6(J$!X4B@FBApDdPaEr?$CG;8hM$6;$r=iaK45q$so`@PeD zlrjy}L=K2Q5Z}NS!Sa@An`3Q*n}_-e(R;hT$IIV~Jdk)I^Fm>SoPxkaj?N<~O-_L; zH$=?g_7P=J&gkKN#;&6Q1?iOLoC&;}z?=u3q791+MEVW|T5!2P)R1X~bM|vx qNVM{4e_61KLGJkDia+5t{}{|)90+JOiv17t1B0ilpUXO@geCwh&tc>M literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building2c.png b/CityGame/Resources/Building2c.png new file mode 100644 index 0000000000000000000000000000000000000000..e346aa1acb856ae2732897a240e708689ea9a325 GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|9(uYshE&A8 zy>(l#SwVy)Ah%6z#eB64wa&n_o`WC%-%DoS{a{~7>?Hf_qCebBcN*B)vevFYp>lU0 z)5XSq=ea@!Z1G;5HH^=cEI2y&>a1_>m!80B!*qvXJp->oQ~2cPOzvOKPGG#DAf3{j zGl6&0L2l-v2AK`{4NU-jG&8z!0_a%=Pgg&ebxsLQ0Gi5eM*si- literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building3.png b/CityGame/Resources/Building3.png new file mode 100644 index 0000000000000000000000000000000000000000..af7008cd5df6a6529d42c1fb38509cc4fcd0815e GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|&Um^whE&A8 zy>*edK|!E7F{VxRM!jCIqp)ko`||nHF$c4MzYd#ZAN}bkH{+cKdDf`x>XeDo);oMT z_}+Og*9Vz>*Q9CT*Jm}gdX~ZC%(wsAa zcax);g@ywA3C6jMTuuiAZ%pF6#aPxLo4{GbXr{r=;WTN1ip1~L8#HP(8#ol5Ixa*r zmPW{iwO>s{rkww)_OU-;jAe9S5nyy-m^huOLqMqosD5V01;&r}>qB4V94rI+i^0>? K&t;ucLK6V0(Pt9? literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building3a.png b/CityGame/Resources/Building3a.png new file mode 100644 index 0000000000000000000000000000000000000000..e719927362dcc0e52e6293c4bb800a3eafb40812 GIT binary patch literal 381 zcmV-@0fPRCP)Px$H%UZ6RCr$P+uIF;Fc3shXoe=}zpg})5-Cy$7<(Tx<8=W@_ptWguFK?SoxFc3 zfSLeNfqmZ}EoqWhpf&ylBnR*vzir#)5J&;sjhC8$o_HC6-gpUsk$8H5(RgYAi+EZ9 zt9VKP%Xm5f>v$>vk9ZmYuXqXo&vV~uMe=FpM{Cf1QbBSx(WN=uPbo0G*wsNy>C} literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building3ab.png b/CityGame/Resources/Building3ab.png new file mode 100644 index 0000000000000000000000000000000000000000..291a3b5460f3c5f2f4a064459538536661bd9dd9 GIT binary patch literal 433 zcmV;i0Z#sjP)Px$Ye_^wRCr$Po6!-2AP_`jGc-Z{HeoZ#XoLX-4hR}$H@}e4eRnJemrSpVK3eN{ z&70gr)ga0RA0yNleRlF@O=pufU1`jFj@# zCOEQqF#|>yUku>sPMn z$P8cxl(nw!oX#!p#wCDU2D1)eDZDpFk(U9F!@Li0E<{!sXceJtjG+1e0hsa;^=2sA z8$|K}Hb=t~6q*?xej-BvU_An606iceKo6h?eE;2rQVh`qX@WFCp8$6O?gHEexDB!n b04jt&I#`=kOoyu&00000NkvXXu0mjfr!J{! literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building3c.png b/CityGame/Resources/Building3c.png new file mode 100644 index 0000000000000000000000000000000000000000..be8d3d88869aab0ad5301ada74f358ef41d80dbd GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|o_M-AhE&A8 zy?v0kML~e|!cxiE8>G6Ia?ZZVt0pDp`)$vk=e~O_;L_# zyZ`<1@9ecp^`E?6wzq>X;o76~g7vdluk%=R&oBJd&-lfA;g{C)F@J(N-rf{FkmLJ4 z{J7n8=bPK!zWB9rI>Q+TZwLMhEWxZ6|Cmi2eFKEAu$Ufvz@pLM$de?{e30V?cY;8( z#1REHLy0*IY=#{`VFL-q-C$XeaI^3Mpd3(`O*z3FEIa4m$14%DIJPGj7cwppwYgSp kZ9PYmdKI;Vst0EJ6*ng9R* literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building4.png b/CityGame/Resources/Building4.png new file mode 100644 index 0000000000000000000000000000000000000000..bff9a7edad006399c4ca625b6549455fec1ba761 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|j(EB_hE&A8 zy?v0kML~omAhS(vMccpb3l56{UmU2sQ)c@&a?W-cjpLi5vY-E0b#0g3ucyzI8p4?} z_y3dldz10|2hZE}Y#-!oa)0kW&{mY*gGOl@2ANue4Sredt7(8A5T-G@yGywp3 CPh}$j literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building4c.png b/CityGame/Resources/Building4c.png new file mode 100644 index 0000000000000000000000000000000000000000..595fee5905eeede413a6824dd08fd7b88729203f GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|-g&w>hE&A8 zy?v0k*?@=jLYm~X1gW-E&S?w1mMk!7`WExMkXf&{@Lx8c-ujnO*T1gmpO!i^{_oen zg)(oyzyBR~thMIO74ena0;M1ScHb{Oc$KmCqu}j&y#qT$Pwn_{qIoYOu5}5b%j%?T z3CIJAf@!cQn;}k7wRD4DYaUE4xPBqz*T$W33%4{+PVRQO&lm5W{@ky_%pbrGz&iwxF$K*>H_l{U>mL4k+GAw$h~$^TsmKODUjUi;TpDo?m=d1~s+*EU@pzh0gGt;tY-V0MFQ0{;e1 zD^{82XAI2~JTGXh;nr}D-?sl(;H?E#Yxq_l_GhwbVE@1%cYwKqf&T#`gmXcWQGv;& zfkS{%shr8BgF{eJ$)%-3Kv2mE#97EEX9SjWVCi6(sLhBXr>C@qk>yXvLD!1doj@lu Nc)I$ztaD0e0sxr*Of>)i literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Building7.png b/CityGame/Resources/Building7.png new file mode 100644 index 0000000000000000000000000000000000000000..271a4b99d68f58975a64fcd067c96cf40afc52e4 GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|HhQ`^hE&A8 zy?&6lK|z4UA+t?wMccpb3l2?=UIp#*f9(=2UlMaXYwg{~VQatEd^!DEsX@1K%XWLW z`tk!(cA3A=GkiOEx$Qs8grKVQ=TqWhl47USPAOVnKgEPGqqB2983qId2;S+KtHk>LOOCS5y{(hC&G->~!YMYiQp)n6AzIe9Lu z|EcOJ*D!NybO7V?DC>Ix#?GGm0~igTe~DWM4fPUeeO literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Error.png b/CityGame/Resources/Error.png new file mode 100644 index 0000000000000000000000000000000000000000..1600d61fb2e72b106b7a0fad9ae59c98247e22f2 GIT binary patch literal 544 zcmV+*0^j|KP)Px$+DSw~RCr$PTH(@zAPk%D|IpjHO;x6Jy0`5{Pg%V5jpE1QGF*8o8B-n9vU9YzTC z_jcvTgW*}c)f@PBc0000Px$m`OxIRCr$Pn?cfpAPj};W!$^=G@i^Ox%V=EhfevY!&pfOP{gk*7ldhE-iryC z;c@fdaC843000951eRs_y9y}lx}Gw4p6949{~KJ%@i0Ik5E94z9xni{?7VlxgYfD6 zIF3;=cME{Td56x>L-c)^_kDjoN}UG)DFe1`i)zWQnWiba)-TZ5NcPRn0Ey!%&RA^D zfcPl@;;uQN%bNxXPx$R7pfZRCr$Po6!w}FbqVSjbJ1uVrfHa2V4i2I;8(w|b%LP)9MN3?0f5THIHUr0C3sa3N&x^s0i*ymfFkHL zMRWmt!1qVz7@?7dq4T6e5u^zEMq|1FT|npp+qOwhTxtcV=kGtS*`)~f3_z*it?T~; zfOPwBvZ#v!ZW5dHHvoVSzz0aFV(l1V7-AS2=+&6wC2D!WEWj)v%mS{m`sc+MA&d}4 z$d!b2fk<7zTL7Dzq(*dtX#rdb+#H73C>h|$jM5IOT>u3nPypNI8>h-rY?e-~0PEmX zcm)8!I8_>20oL8${X;kaO3-KH6as)Z=r;h0jf}kJ1>c_vP)Iku^8f$<07*qoM6N<$ Ef_mhnJ^%m! literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Road2.png b/CityGame/Resources/Road2.png new file mode 100644 index 0000000000000000000000000000000000000000..eee62e050aefc6f4d40a24c84635ef2d3a85e938 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|{&~7MhE&A8 zz2(T)Y{27ku|TD7%H+Z&GAlW@hMGH`%E{VVm2)FPfp^>EpB33_x8D2xc-Q*4{*qbZxZlf$eSP=r!mF9LoUFU(`|mX;*aOE76jhV$PszQIztgC zd5rlIBb&faafM9=cij{-)eN1_Ot}B}8?%l_NM6SS#tH_x26ia5M30aE08qk5)We%o zfYF6P&|!%Px*9b$pqdX1HVMldZh7k|6fuQ8v504Wux<-5Bp5th{an^LB{Ts5@Px$Oi4sRRCr$PnqdxuAPj}ajr2&K%p-ZEEi96lZH_)9A-3QCVv2k`+GkmM1plRF zS)Lvltm~RA>v9X=xcGlCLI5Z*et`%DAcOdX5Dvg61ORxg0<{WIjzUNU9FGA2q8@>w zg0Knz!0rjsG)=eu7MSO`mhex$45CHI`fUE>n1+EkT02IIxAP0~HMN>o- zzy~<8!uSAu06qX8fDgFp1Ga55byrlgoX$W5u6}S5GN>ojA4bd6}J9S(%LRlwxGmR zlh@fCYMi$MtN_ZSJwX6q??S6PH&g+6@?I*qr2+te0yqNX0Ft2b618TE!dHPBAaz{z w6HQLAXBku%SbM$+Kn^<64%Zf?jJE)I0Rjt0P+HyY3;+NC07*qoM6N<$g80{$g#Z8m literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Road3c.png b/CityGame/Resources/Road3c.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec0c9c75a2430c9f487cd6cedb1e499cfc39c74 GIT binary patch literal 369 zcmV-%0gnEOP)Px$D@jB_RCr$Po68NvAPhvIBPfZ=D2bAG#eOcEjpTs@ka)S|;)G*buiSAV{)003yfH74-YBvp0K^jv+gDZ1aX4@5l}Vh#R4G&DG-vPjlseI&=L)z0hjLuCEC35M zBt@Y?Xb>8N25;k~!7qjep+RU+GCC3>zZoHG)mL>k(zbL6tKW6dfb9Y30Dp-`yER~m zzv%b~0N@bl;#7c5G6_q{(R}7gN+OwJn#c|D(9{O4a$2jJ?I@mQIoT6#H9q=@mWM zU3$k>+|qykX79HTn+~sMaX9D1kd}5pd-9f*)zhDgSqB?8FxVWu^67MJYU5Ep$p$u! z`HWFX0=y2)=hVHrD-@f=1vjt=akU79v`$!c>qf#xb%qp%dPb83=C!Y$DJgNVE?^L8 zV7jYP#(X${fy;qWgMrmd;B}r}UBH5G*RFqhxAr#YJ)Y=4>I?}2JWY-U7ETMp?=~lK zKvaf>z7VW)1nB{qBC&AW>UWH+FGQDxN0=M9ZZ0{zP;=MOmtxDK=af}GW0jck<8kN2 zYhN3mUaNX_Px%nn^@KRCr$PnmbMdF%X6~LPDvKpov0(C@HB@(x%`5P;&szkRxycYB&G|S4b7n zK#6EpsVJdAAOj;D%U;h5+sQg*vVQ#E{4--mJ7{|T8T4F#Qvp;5^qfFV0c``E-%UP! zbKacJi-fJVsgQ6NMrj~a0AR%fjFKRT0Z_%420;XXE8d21blrGs#?wXj8D(^~I&OK( zJJVzZuvpHcHP{8=3U?=;dB6Ax~nxL_?D0K#7HqZ#x4Km|Z3h$06V z+T2cnDS&RghY#bGuiCctS|XVPV09`44e_wH3xOiu%prCF6@sRCAA~Fb_AmbqB`4E~ z*OnaNW+K=2p)$C*YFWW#4YD_3iw|vX=NMPLeNSNlKq@4407kqKl@dU*Hi#9U0{{gA zI|WJyfQ7Kp05A|(04ULyrU0fBgbqX-1E32+m-u1;Xt=;!gvMjsQP^&$v9_2b1+)Ng zP7@VC>gsQ&=ge(BC;vsswQ<=^G(*>*)&;kIxJti>ryTk=#095fQ zTu=cB+F^A-EWg~}d!GUZ2o*x83#?@ktN?y<0_%dV=xaDY(g8%5A*c-@5caJs^di*S zo&>3dv-bcDFc*S(@#%2pe?<-pSZaTj6u@rQ_gwD*7${r_8qv@00B{8rf|mGV08pHu zDZVHGF*j%nhxN#pAxY6Iacl)pVpLM@sX8Df?Go3j4k$4yDfd(zkdk(ZYkdLvA}vs2 S)*qz+0000Px$bV)=(RCr$PnBlF1Fbst09+`td7?eSnBYU(;RZCHt#_#F9lX~{?s{(3#pU;Nm zwk1Dq$@OmnAO|ETpcY7O01ZL61xhJ*luK%@?({JZ4nm0svY`C85Tfl2c(z*&Bn7i zkmfBg1KrOml|tny2cXEZ#FYbBDuv2Z4nUD*i7N-N kR0@@+9DpLr5;wgA9`(#dP%EEx%>V!Z07*qoM6N<$g1z&$lK=n! literal 0 HcmV?d00001 diff --git a/CityGame/Resources/Vent2.png b/CityGame/Resources/Vent2.png new file mode 100644 index 0000000000000000000000000000000000000000..d0581114d0ddc5793b5e3303db070a8ecc9b97eb GIT binary patch literal 514 zcmV+d0{#7oP)Px$yh%hsRCr$Pn9&WxAPhv)J(wedWY7$fIoP8WRgn-Sm=<4E$Cs}vjePd=L5OdQ z^Xulk{)GVO0Otg_1e_ayo1nM^LI`)1OJa;q{a7zLoEp$_0xfVeagh!%tq0Gb-A07etbqAds#0BsF5 z06DR3+m?ObMF-^PY6v|52n`hgbyp+^_5US=GXN+J2!Isy3_|PvHvqIWrUCTUWL<2} z85u&$0Z0uffU--{viKIjtOguF&#I;P41gI8IDp)Fmkw~T2P6x%HYqo6fffMC?w30U zln|ui^QLpDlVC1N`<$KzBJ~H8w#M{Zpbjva;3dBXODCk?F6RNIBW9;HttHTMTz&78 zsgwE=5Wj{v}aV9t40QYb7onV5L*2 zJm~-wSu1hr04tqB1V&PPx%Nl8RORCr$Pn%Qx~FbqWHK2(PaQK2ftb+C_Q=m};Jn&Q&rBH`t)j1GW!TJQk! z*e3ryCXatx0G0wKC$LgrasjMK5T?Ms?_X9ban8N`|Amjc7_tBy$3bWCd_Fe~z}kl? z03S^FLjipXpw@>802!2X?#=$b@2_ijAaVh)e9!^>1OQXRgNQ-M0l@S@1&}*1aT0+8LIb%29P%`%mEixLvL2unQCqEvr9ez^ z;k8eyPV^Lj=V0&vst45CR}*%!?wM5-Weg@}ql>DrRq(CYg$ih8pjP8(0zlJ^5i9b+ z5&3N+#PF*p+TvA!F%V><>17ZNo^d|~;NKe~i~y01I{?h>c6TX|8@vRDnlD`eXsR)S z}%P6~bkpfLNM$p$|+!qC)iLa*g-n{}OfSg)ntobqofTKXJ5BTjSizLoSpZ6? pjr7h^z(`-SB$lOs5^5v8^9`F>(r!#LqZa@G002ovPDHLkV1k`!8W;co literal 0 HcmV?d00001 diff --git a/CityGame/SourcedImage.cs b/CityGame/SourcedImage.cs new file mode 100644 index 0000000..05d5831 --- /dev/null +++ b/CityGame/SourcedImage.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace CityGame +{ + public class SourcedImage : Image + { + public Dictionary> Alternatives = new Dictionary>() + { + }; + + public static Dictionary loadedSources = new Dictionary(); + + public SourcedImage(string source) + { + Source = SourceToImage(source); + Height = 64; + Width = 64; + + ImageFailed += SourcedImage_ImageFailed; + } + + private void SourcedImage_ImageFailed(object? sender, ExceptionRoutedEventArgs e) + { + Debug.WriteLine("failed"); + } + + public BitmapSource SourceToImage(string src, UriKind kind = UriKind.Absolute) + { + string degs = src.Split(':').Last(); + string uri = src; + int deg = 0; + if (degs == "0" || degs == "90" || degs == "180" || degs == "270" || degs == "360" || degs == "450" || degs == "540" || degs == "630" || degs == "720") + { + deg = Convert.ToInt32(degs); + uri = string.Join(":", src.Split(':').Take(src.Split(':').Count() - 1).ToArray()); + } + string last = ""; + while (Alternatives.ContainsKey(uri) && uri != last) + { + last = uri; + List alts = Alternatives[uri]; + alts.Add(uri); + uri = alts[MainWindow.random.Next(0, alts.Count)]; + } + uri = Environment.CurrentDirectory + "\\Resources\\" + uri; + if (loadedSources.ContainsKey(src)) + { + return loadedSources[src]; + } + else + { + if(!File.Exists(uri)) + { + uri = Environment.CurrentDirectory + "\\Resources\\ErrorRed.png"; + } + loadedSources.Add(src, new TransformedBitmap(new BitmapImage(new Uri(uri, kind)), new RotateTransform(deg))); + return loadedSources[src]; + } + } + } +} \ No newline at end of file diff --git a/CityGame/Tile.cs b/CityGame/Tile.cs new file mode 100644 index 0000000..b95e8bc --- /dev/null +++ b/CityGame/Tile.cs @@ -0,0 +1,10 @@ +namespace CityGame +{ + public struct Tile + { + public int BlockID; + public TileType Type; + public int X; + public int Y; + } +} \ No newline at end of file diff --git a/CityGame/TileType.cs b/CityGame/TileType.cs new file mode 100644 index 0000000..c829311 --- /dev/null +++ b/CityGame/TileType.cs @@ -0,0 +1,17 @@ +namespace CityGame +{ + public enum TileType + { + Skyscraper = 100, + House = 101, + + Park = 200, + + Lake = 300, + River = 301, + + Road = 400, + Path = 401, + Bridge = 410 + } +} \ No newline at end of file