160 lines
4.8 KiB
C#
160 lines
4.8 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/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<Water>((int)(GD.Randi() % (chunkResX * chunksPerX)), 0, 1);
|
|
}
|
|
}
|
|
|
|
public void WritePixel<T>(int x, int y, int size) {
|
|
int halfsize = size/2;
|
|
|
|
for (int i = -halfsize; i <= halfsize; i++) {
|
|
for (int j = 0; j < 1; j++) {
|
|
// for (int j = -halfsize; j <= halfsize; j++) {
|
|
// calculate in-chunk coordinates
|
|
int inChunkX = x % chunkResX;
|
|
int inChunkY = y % chunkResY;
|
|
int brushX = i;
|
|
int brushY = j;
|
|
|
|
// calculate chunk to write to
|
|
int chunkX = x/chunkResX;
|
|
if (inChunkX + i < 0) {
|
|
chunkX--;
|
|
// 320 -22
|
|
brushX = chunkResX + inChunkX + i;
|
|
inChunkX = chunkResX - inChunkX;
|
|
} else if (inChunkX + i >= chunkResX) {
|
|
chunkX++;
|
|
inChunkX = 0;
|
|
brushX = i % chunkResX;
|
|
}
|
|
inChunkX += brushX;
|
|
|
|
if (chunkX < 0 || chunkX >= chunksPerX) {
|
|
GD.PrintErr($"Trying to write out of bounds: {x}:{y}");
|
|
return;
|
|
}
|
|
|
|
int chunkY = y/chunkResY;
|
|
if (inChunkY + j < 0) {
|
|
chunkY--;
|
|
brushY = chunkResY - (inChunkY + j);
|
|
inChunkY = chunkResY - inChunkY;
|
|
} else if (inChunkY + j >= chunkResY) {
|
|
chunkY++;
|
|
inChunkY = 0;
|
|
brushY = j % chunkResY;
|
|
}
|
|
inChunkY += brushY;
|
|
|
|
if (chunkY < 0 || chunkY >= chunksPerY) {
|
|
GD.PrintErr($"Trying to write out of bounds: {x}:{y}");
|
|
return;
|
|
}
|
|
|
|
chunks[chunkX, chunkY].WritePixel<T>(inChunkX, inChunkY);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|