using System; using FOU.Scripts.Elements; using Godot; namespace FOU.Scripts; public class Level { public Vector2I Resolution; private Chunk[,] chunks; private Image image; private int chunksPerX; private int chunksPerY; // per chunk: private int chunkResX; private int chunkResY; private float rainAmount = 0; public Level(Main main, int sizeX, int sizeY) { Resolution = new Vector2I(sizeX, sizeY); chunksPerX = main.ChunksPerAxis; chunksPerY = main.ChunksPerAxis; chunkResX = sizeX / chunksPerX; chunkResY = sizeY / chunksPerY; GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksPerX*chunksPerY} chunks ({chunkResX} * {chunkResY})"); image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); chunks = new Chunk[chunksPerX, chunksPerY]; int index = 0; // create all chunks for (int x = 0; x < chunksPerX; x++) { for (int y = 0; y < chunksPerY; y++) { chunks[x, y] = new Chunk(chunkResX, chunkResY, index++); } } // assign neighbors for (int x = 0; x < chunksPerX; x++) { for (int y = 0; y < chunksPerY; y++) { if (y > 0) chunks[x, y].NeighborN = chunks[x, y-1]; if (y < chunksPerY-1) chunks[x, y].NeighborS = chunks[x, y+1]; if (x > 0) chunks[x, y].NeighborE = chunks[x-1, y]; if (x < chunksPerX-1) chunks[x, y].NeighborW = chunks[x+1, y]; } } } public void Update() { MakeItRain(); foreach (Chunk c in chunks) c.Update(); } public void SetRainAmount(float amount) { rainAmount = amount; } public void StartBenchmark() { GD.Print("benchmark"); for (int x = 0; x < chunksPerX; x++) { for (int y = 0; y < chunksPerY; y++) { WritePixel(x * chunkResX/2, y * chunkResY/2, 100); } } } public Chunk[,] GetChunks() { return chunks; } private void MakeItRain() { if (rainAmount < .1f) return; int rainDrops = (int)Math.Round(rainAmount); for (int i = 0; i <= rainDrops; i++) { if (GD.Randf() < rainAmount) WritePixel((int)(GD.Randi() % (chunkResX * chunksPerX)), 0, 1); } } public void WritePixel(int x, int y, int size) { int halfsize = size/2; int startPtX = x % chunkResX; int startPtY = y % chunkResY; for (int i = -halfsize; i <= halfsize; i++) { for (int j = -halfsize; j <= halfsize; j++) { // calculate in-chunk coordinates int iteratorX = i; int iteratorY = j; int ptX = startPtX; int ptY = startPtY; // calculate chunk to write to int chunkX = x/chunkResX; // left of chunk if (startPtX + iteratorX < 0) { chunkX--; iteratorX = chunkResX + startPtX + iteratorX; ptX = startPtX + iteratorX; // right of chunk } else if (startPtX + iteratorX >= chunkResX) { chunkX++; ptX = startPtX + iteratorX - chunkResX; } else { ptX = startPtX + iteratorX; } int chunkY = y/chunkResY; // above chunk if (startPtY + iteratorY < 0) { chunkY--; ptY = chunkResY + (startPtY + iteratorY); // left of chunk } else if (startPtY + iteratorY >= chunkResY) { chunkY++; ptY = iteratorY % chunkResY; } else { ptY = startPtY + iteratorY; } // ignore everything outside if (chunkX < 0) continue; if (chunkX > chunksPerX) continue; if (chunkY < 0) continue; if (chunkY > chunksPerY) continue; chunks[chunkX, chunkY].WritePixel(ptX, ptY); } } } public Image DrawLevel() { for (int cx = 0; cx < chunksPerX; cx++) { for (int cy = 0; cy < chunksPerY; cy++) { for (int x = 0; x < chunkResX; x++) { for (int y = 0; y < chunkResY; y++) { // TODO: multithreading here! use Chunk.DrawLevel() and stitch images together image.SetPixel(cx*chunkResX + x, cy*chunkResY + y, chunks[cx,cy].Elements[x, y].Color); } } } } return image; } }