using Godot; namespace FOU.Scripts.Elements; public class Element { public Color Color = Colors.Black; public Vector2I Position; public Chunk Chunk; public int Density; public int LastUpdate = -1; public int LastMove = 0; public int DiffuseSpeed = 10; public const int MAX_DIFFUSE_SPEED = 100; public const int STEPS_UNTIL_INACTIVE = 500; protected const float MAX_COLOR_VARIANCE = 0.1f; protected static readonly Vector2I VERTICAL_OPPOSITE = new Vector2I(-1, 1); private bool active = false; private Color originalColor; public Element(Element e) { Position = e.Position; Chunk = e.Chunk; LastMove = Engine.GetFramesDrawn(); } public Element(int x, int y, Chunk chunk) { Position.X = x; Position.Y = y; Chunk = chunk; LastMove = Engine.GetFramesDrawn(); Active = false; } public bool Active { get => active; set { if (active == value) return; active = value; Chunk.SetElementActive(this, value); SetDebugColors(value); } } /// /// base update method, checks if anything is to do at all /// /// /// false if there is nothing to do public virtual bool Update() { if (!Active) return false; if (LastUpdate == Engine.GetFramesDrawn()) return false; // already updated this frame LastUpdate = Engine.GetFramesDrawn(); return true; } public override string ToString() { return $"{GetType()} {Position}[{Chunk.Index}]"; } protected virtual void Tick() { Vector2I randomDirection = RandomDirectionDown(); if (Chunk.IsEmpty(Position + Vector2I.Down)) Chunk.Swap(this, Position + Vector2I.Down); else if (Chunk.IsEmpty(Position + randomDirection)) Chunk.Swap(this, Position + randomDirection); else if (Chunk.IsEmpty(Position + randomDirection * VERTICAL_OPPOSITE)) Chunk.Swap(this, Position + randomDirection * VERTICAL_OPPOSITE); if (GD.Randi() % MAX_DIFFUSE_SPEED > DiffuseSpeed) return; // ascend slower if (Chunk.Get(Position + randomDirection)?.Density < Density) Chunk.Swap(this, Position + Vector2I.Down); } protected Vector2I RandomDirectionDown() { int randomDirection = GD.Randi() % 2 != 0 ? 1 : -1; return Vector2I.Down // maybe also side + (GD.Randi() % 2 != 0 ? Vector2I.Zero : Vector2I.Right * randomDirection); } protected Color AddColorVariance(Color baseColor) { Color c = baseColor; c.R += (GD.Randf() - 1) * MAX_COLOR_VARIANCE; c.G += (GD.Randf() - 1) * MAX_COLOR_VARIANCE; c.B += (GD.Randf() - 1) * MAX_COLOR_VARIANCE; originalColor = c; return c; } private void SetDebugColors(bool isActive) { if (isActive) Color = originalColor; else if (Main.Instance.DebugVisualization) Color = new Color(0.2f, 0.2f, 0.2f); } }