169 lines
5.6 KiB
C#

using Raylib_cs;
using Sand.ChunkPrototype;
const int screenWidth = 1280;
const int screenHeight = 800;
const int sidebarWidth = 220;
const int particleSize = 4;
const int simWidth = (screenWidth - sidebarWidth) / particleSize;
const int simHeight = screenHeight / particleSize;
const int brushRadius = 3;
var adapter = new PrototypeSparseSandAdapter(simWidth, simHeight);
var accumulator = 0f;
var fixedStep = 1f / 60f;
var stepCounter = 0;
var currentParticle = PrototypeParticleType.Sand;
var frameBuffer = new byte[simWidth * simHeight * 4];
Raylib.SetConfigFlags(ConfigFlags.ResizableWindow);
Raylib.InitWindow(screenWidth, screenHeight, "Sand Chunk Prototype");
Raylib.SetTargetFPS(120);
var frameImage = Raylib.GenImageColor(simWidth, simHeight, Color.Black);
var frameTexture = Raylib.LoadTextureFromImage(frameImage);
Raylib.UnloadImage(frameImage);
while (!Raylib.WindowShouldClose())
{
var dt = Raylib.GetFrameTime();
var mouse = Raylib.GetMousePosition();
var simMouseX = Math.Clamp((int)((mouse.X - sidebarWidth) / particleSize), 0, simWidth - 1);
var simMouseY = Math.Clamp((int)(mouse.Y / particleSize), 0, simHeight - 1);
var overWorld = mouse.X >= sidebarWidth;
if (Raylib.IsKeyPressed(KeyboardKey.C))
{
adapter = new PrototypeSparseSandAdapter(simWidth, simHeight);
accumulator = 0f;
stepCounter = 0;
}
if (Raylib.IsKeyPressed(KeyboardKey.One))
{
currentParticle = PrototypeParticleType.Sand;
}
if (Raylib.IsKeyPressed(KeyboardKey.Two))
{
currentParticle = PrototypeParticleType.Water;
}
if (Raylib.IsKeyPressed(KeyboardKey.Three))
{
currentParticle = PrototypeParticleType.Steam;
}
if (Raylib.IsKeyPressed(KeyboardKey.Four))
{
currentParticle = PrototypeParticleType.Wall;
}
if (Raylib.IsMouseButtonDown(MouseButton.Left) && overWorld)
{
PaintCircle(adapter, simMouseX, simMouseY, brushRadius, currentParticle, add: true);
}
if (Raylib.IsMouseButtonDown(MouseButton.Right) && overWorld)
{
PaintCircle(adapter, simMouseX, simMouseY, brushRadius, currentParticle, add: false);
}
accumulator += dt;
var maxSteps = 8;
while (accumulator >= fixedStep && maxSteps-- > 0)
{
adapter.World.ClearDirtyChunks();
adapter.Step();
stepCounter++;
if ((stepCounter % 30) == 0)
{
adapter.TrimResidency(marginChunks: 1);
}
accumulator -= fixedStep;
}
if (accumulator > fixedStep * 4f)
{
accumulator = fixedStep;
}
var rgbaFrame = adapter.BuildRgbaFrame();
rgbaFrame.CopyTo(frameBuffer);
unsafe
{
fixed (byte* pixels = frameBuffer)
{
Raylib.UpdateTexture(frameTexture, pixels);
}
}
Raylib.BeginDrawing();
Raylib.ClearBackground(new Color(8, 10, 14, 255));
Raylib.DrawRectangle(0, 0, sidebarWidth, screenHeight, new Color(20, 24, 30, 255));
Raylib.DrawTextureEx(frameTexture, new System.Numerics.Vector2(sidebarWidth, 0), 0f, particleSize, Color.White);
if (overWorld)
{
Raylib.DrawCircleLines((int)mouse.X, (int)mouse.Y, brushRadius * particleSize, new Color(255, 255, 255, 180));
}
DrawPanel(adapter, currentParticle);
Raylib.EndDrawing();
}
Raylib.UnloadTexture(frameTexture);
Raylib.CloseWindow();
static void PaintCircle(PrototypeSparseSandAdapter adapter, int centerX, int centerY, int radius, PrototypeParticleType type, bool add)
{
for (var dx = -radius; dx <= radius; dx++)
{
for (var dy = -radius; dy <= radius; dy++)
{
if ((dx * dx) + (dy * dy) > radius * radius)
{
continue;
}
var x = centerX + dx;
var y = centerY + dy;
if (x < 0 || y < 0 || x >= adapter.Width || y >= adapter.Height)
{
continue;
}
if (add)
{
adapter.AddParticle(x, y, type);
}
else
{
adapter.RemoveParticle(x, y);
}
}
}
}
static void DrawPanel(PrototypeSparseSandAdapter adapter, PrototypeParticleType currentParticle)
{
Raylib.DrawText("Chunk Proto", 12, 14, 28, new Color(110, 172, 228, 255));
DrawParticleButton(12, 60, "1 Sand", currentParticle == PrototypeParticleType.Sand, new Color(214, 188, 96, 255));
DrawParticleButton(12, 96, "2 Water", currentParticle == PrototypeParticleType.Water, new Color(72, 132, 232, 255));
DrawParticleButton(12, 132, "3 Steam", currentParticle == PrototypeParticleType.Steam, new Color(182, 196, 214, 255));
DrawParticleButton(12, 168, "4 Wall", currentParticle == PrototypeParticleType.Wall, new Color(96, 96, 104, 255));
Raylib.DrawText($"FPS {Raylib.GetFPS()}", 12, 228, 20, Color.White);
Raylib.DrawText($"Particles {adapter.ParticleCount}", 12, 252, 20, Color.White);
Raylib.DrawText($"Loaded Chunks {adapter.World.LoadedChunkCount}", 12, 276, 20, Color.White);
Raylib.DrawText($"Active Chunks {adapter.World.ActiveChunkCount}", 12, 300, 20, Color.White);
Raylib.DrawText($"Dirty Chunks {adapter.World.DirtyChunkCount}", 12, 324, 20, Color.White);
Raylib.DrawText("LMB paint", 12, 372, 18, Color.LightGray);
Raylib.DrawText("RMB erase", 12, 394, 18, Color.LightGray);
Raylib.DrawText("C clear", 12, 416, 18, Color.LightGray);
}
static void DrawParticleButton(int x, int y, string label, bool selected, Color color)
{
Raylib.DrawRectangleRounded(new Rectangle(x, y, 188, 28), 0.2f, 6, selected ? new Color(236, 236, 242, 255) : color);
Raylib.DrawText(label, x + 10, y + 5, 18, selected ? Color.Black : Color.Black);
}