/// <summary> /// Given a set of world coordinates, returns an array of cells. Evolves and adds chunks as necessary. /// </summary> private int[,] GetView(ViewPort viewPort) { // Determine which chunks are (partially or completely) within the bounding box of the view var lower = ConvertCellWorldCoordinateToChunkCoordinate(viewPort.XMin, viewPort.YMin); var upper = ConvertCellWorldCoordinateToChunkCoordinate(viewPort.XMax, viewPort.YMax); // If chunks overlapped by view are not 'inside', they are going to get evolved var evolveList = new List <Chunk>(); for (var posX = lower.X; posX <= upper.X; posX++) { for (var posY = lower.Y; posY <= upper.Y; posY++) { // Get chunk, if it does not exist: create it var key = GetChunkKey(posX, posY); Chunk chunk; if (!Chunks.TryGetValue(key, out chunk)) { chunk = new Chunk(this, ChunkSizeX, ChunkSizeY, Generations, Threshold, posX, posY, RockPercentage); Chunks[key] = chunk; } if (chunk.Type == Chunk.ChunkType.Edge) { chunk.Type = Chunk.ChunkType.Inside; evolveList.Add(chunk); // Get the neighboring chunks var added = AddAdjacentChunks(posX, posY); evolveList.AddRange(added); } } } // Clean up list (remove duplicates) evolveList = evolveList.Distinct().ToList(); if (evolveList.Count > 0) { Trace.WriteLine($"EvolveList.Count: {evolveList.Count}"); } RunEvolution(evolveList); // Mark 'inside' chunks as final foreach (var chunk in Chunks.Values) { if (chunk.Type == Chunk.ChunkType.Inside && !chunk.IsFinal) { chunk.MarkAsFinal(); } } // Determine size of view, create array var viewSizeX = viewPort.XMax - viewPort.XMin + 1; var viewSizeY = viewPort.YMax - viewPort.YMin + 1; var view = new int[viewSizeX, viewSizeY]; // Copy cells from chunks into array for (var x = viewPort.XMin; x <= viewPort.XMax; x++) { for (var y = viewPort.YMin; y <= viewPort.YMax; y++) { view[x - viewPort.XMin, y - viewPort.YMin] = GetFinalCell(x, y); } } return(view); }
static void Main(string[] args) { ConsoleKeyInfo key; var location = new Point(0, 0); var world = new World(); var drawGrid = false; do { Console.Clear(); int xMin = location.X - 0, xMax = location.X + world.ChunkSizeX - 1, yMin = location.Y - 0, yMax = location.Y + world.ChunkSizeY - 1; var viewPort = new ViewPort(xMin, yMin, xMax, yMax); var view = world.GetView(viewPort); for (var x = 0; x < (1 + xMax - xMin); x++) { for (var y = 0; y < (1 + yMax - yMin); y++) { var cell = view[y, x]; var color = Console.ForegroundColor; Console.ForegroundColor = cell == 1 ? ConsoleColor.DarkBlue : ConsoleColor.White; Console.Write("█"); Console.ForegroundColor = color; } Console.WriteLine(); } world.DrawImage(viewPort, drawGrid); Console.WriteLine("Number of chunks: " + world.Chunks.Keys.Count); Console.WriteLine($"Location: ({location.X}, {location.Y})"); Console.WriteLine("R: reset\tG: grid on/off\tQ: quit"); key = Console.ReadKey(); if (key.Key == ConsoleKey.LeftArrow) { location.X = location.X - world.MovementFactor; } if (key.Key == ConsoleKey.RightArrow) { location.X = location.X + world.MovementFactor; } if (key.Key == ConsoleKey.UpArrow) { location.Y = location.Y - world.MovementFactor; } if (key.Key == ConsoleKey.DownArrow) { location.Y = location.Y + world.MovementFactor; } if (key.Key == ConsoleKey.R) { world = new World(); } if (key.Key == ConsoleKey.G) { drawGrid = !drawGrid; } } while (key.Key != ConsoleKey.Q); }
/// <summary> /// Given a viewport, creates an image of the world and saves it to disc. /// </summary> public Image DrawImage(ViewPort viewPort, bool drawEdges = true, bool drawGrid = false, bool drawView = true, bool drawEdgesAsNoise = false, bool drawFinalAsNoise = false, bool colorizeInsideChunks = true) { var chunks = Chunks.Values.ToList(); if (!drawEdges) { chunks = chunks.Where(x => x.Type != Chunk.ChunkType.Edge).ToList(); } // Determine image size. var xMin = chunks.Min(x => x.PosX); var xMax = chunks.Max(x => x.PosX); var xDim = (1 + xMax - xMin) * ChunkSizeX * CellSize; var yMin = chunks.Min(x => x.PosY); var yMax = chunks.Max(x => x.PosY); var yDim = (1 + yMax - yMin) * ChunkSizeX * CellSize; var image = new Bitmap(xDim, yDim); using (var g = Graphics.FromImage(image)) { foreach (var chunk in chunks) { var chunkXRelative = chunk.PosX - xMin; var xTopLeft = chunkXRelative * ChunkSizeX * CellSize; var chunkYRelative = chunk.PosY - yMin; var yTopLeft = chunkYRelative * ChunkSizeY * CellSize; var solidColor = Brushes.DarkGray; var openColor = Brushes.DimGray; for (var x = 0; x < chunk.SizeX; x++) { for (var y = 0; y < chunk.SizeY; y++) { Brush brush; int block; if (chunk.IsFinal) { block = drawFinalAsNoise ? chunk.Noise[x, y] : chunk.Final[x, y]; brush = block == 1 ? (colorizeInsideChunks ? Brushes.ForestGreen : solidColor) : (colorizeInsideChunks ? Brushes.SaddleBrown : openColor); } else { block = drawEdgesAsNoise ? chunk.Noise[x, y] : chunk.Cells[x, y]; brush = block == 1 ? solidColor : openColor; } g.FillRectangle(brush, xTopLeft + x * CellSize, yTopLeft + y * CellSize, CellSize, CellSize); } } } if (drawGrid) { foreach (var chunk in chunks.OrderBy(x => x.Type)) { var chunkXRelative = chunk.PosX - xMin; var xTopLeft = chunkXRelative * ChunkSizeX * CellSize; var chunkYRelative = chunk.PosY - yMin; var yTopLeft = chunkYRelative * ChunkSizeY * CellSize; var color = chunk.Type == Chunk.ChunkType.Edge ? Color.Red : Color.Yellow; var pen = new Pen(color, 1.5f); g.DrawRectangle(pen, xTopLeft, yTopLeft, ChunkSizeX * CellSize - 1, ChunkSizeY * CellSize - 1); } } // Draw viewport. if (drawView) { // Calculate viewport // Determine which chunks are (partially or completely) within the bounding box of the view var xTranslation = Math.Abs(Math.Min(0, xMin) * ChunkSizeX * CellSize); var yTranslation = Math.Abs(Math.Min(0, yMin) * ChunkSizeY * CellSize); Console.WriteLine($"viewport: {viewPort}"); viewPort.Grow(CellSize, CellSize); Console.WriteLine($"viewport-grown: {viewPort}"); viewPort.Translate(xTranslation, yTranslation); Console.WriteLine($"viewport-translated: {viewPort}"); var rect = viewPort.GetRectangle(); g.DrawRectangle(new Pen(Color.Fuchsia, 2 * CellSize), rect); } } return(image); }