Files
FOU/Scripts/Level.cs

169 lines
4.9 KiB
C#

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<Dirt>((x * chunkResX) + chunkResX/2, (y * chunkResY) + 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<Water>((int)(GD.Randi() % (chunkResX * chunksPerX)), 0, 1);
}
}
public void WritePixel<T>(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<T>(ptX, ptY);
}
}
}
public Image DrawLevel() {
// chunk
for (int cx = 0; cx < chunksPerX; cx++) {
for (int cy = 0; cy < chunksPerY; cy++) {
// pixel in chunk
for (int x = 0; x < chunkResX; x++) {
for (int y = 0; y < chunkResY; y++) {
// TODO: multithreading here! use Chunk.DrawLevel() and stitch images together
if (chunks[cx, cy].Elements[x, y].WasMoved())
image.SetPixel(cx*chunkResX + x, cy*chunkResY + y, chunks[cx, cy].Elements[x, y].Color);
}
}
}
}
return image;
}
}