From 34aee98a6a52cbf367e55ebe7b2cd14adfc10b8d Mon Sep 17 00:00:00 2001 From: rogo Date: Sun, 27 Oct 2024 14:08:19 +0100 Subject: [PATCH 1/9] added benchmark function added .txt for benchmark results fixed generating level message --- FOU.csproj | 3 +++ Scripts/Level.cs | 14 ++++++++++++-- Scripts/Main.cs | 6 +++++- benchmark.txt | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 benchmark.txt diff --git a/FOU.csproj b/FOU.csproj index 088aa3d..f39cf71 100644 --- a/FOU.csproj +++ b/FOU.csproj @@ -3,4 +3,7 @@ net6.0 true + + + \ No newline at end of file diff --git a/Scripts/Level.cs b/Scripts/Level.cs index a471dc1..def3dd1 100644 --- a/Scripts/Level.cs +++ b/Scripts/Level.cs @@ -22,8 +22,6 @@ public class Level { private float rainAmount = 0; public Level(Main main, int sizeX, int sizeY) { - GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksX*chunksY} chunks ({chunkResX} * {chunkResY})"); - Resolution = new Vector2I(sizeX, sizeY); chunksX = main.ChunksPerAxis; chunksY = main.ChunksPerAxis; @@ -31,6 +29,8 @@ public class Level { chunkResX = sizeX / chunksX; chunkResY = sizeY / chunksY; + GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksX*chunksY} chunks ({chunkResX} * {chunkResY})"); + image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); chunks = new Chunk[chunksX, chunksY]; @@ -66,6 +66,15 @@ public class Level { rainAmount = amount; } + public void StartBenchmark() { + GD.Print("benchmark"); + for (int x = 0; x < chunksX; x++) { + for (int y = 0; y < chunksY; y++) { + chunks[x, y].WritePixel(chunkResX/2, chunkResY/2, 100); + } + } + } + private void MakeItRain() { if (rainAmount < .1f) return; @@ -87,6 +96,7 @@ public class Level { 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); } } diff --git a/Scripts/Main.cs b/Scripts/Main.cs index 9efc559..43ab965 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -51,6 +51,10 @@ public partial class Main : Node2D { mLevel.WritePixel((int)mappedX, (int)mappedY, BrushSize); } - } else base._UnhandledInput(@event); + } else if (@event is InputEventKey keyEvent && keyEvent.Pressed) { + if (keyEvent.Keycode == Key.F9) + mLevel.StartBenchmark(); + } + else base._UnhandledInput(@event); } } diff --git a/benchmark.txt b/benchmark.txt new file mode 100644 index 0000000..b247ef3 --- /dev/null +++ b/benchmark.txt @@ -0,0 +1,15 @@ +# Benchmark + +## Settings +- Texture Resolution: 0.5 +- CHunks per Axis: 2 +- Rain Amount: 0 + +## Measurements: +### original (no optimization): +- idle: 42 - 44 fps +- benchmark: 24 fps minimum + +### only active: +- idle: 100 fps +- benchmark: 36 fps minimum From d1dac0b855f8d3f9eadd1fa1f50ace30a4fd09dc Mon Sep 17 00:00:00 2001 From: rogo Date: Sun, 27 Oct 2024 14:44:14 +0100 Subject: [PATCH 2/9] added simple activeElements list --- Scenes/main.tscn | 2 -- Scripts/Chunk.cs | 31 ++++++++++++++++++++++++------- Scripts/Elements/Element.cs | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Scenes/main.tscn b/Scenes/main.tscn index 9b78cab..af11d31 100644 --- a/Scenes/main.tscn +++ b/Scenes/main.tscn @@ -6,9 +6,7 @@ [node name="Main" type="Node2D"] script = ExtResource("1_k1i8e") -DebugVisualization = true BrushSize = 2 -TextureResolution = 0.35 [node name="CanvasLayer" type="CanvasLayer" parent="."] diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index b178496..ab0ffdf 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using FOU.Scripts.Elements; using Godot; @@ -15,6 +16,7 @@ public class Chunk { private readonly Image image; private readonly int sizeX; private readonly int sizeY; + private readonly List activeElements = new List(); public Chunk(int x, int y, int index) { Index = index; @@ -33,11 +35,14 @@ public class Chunk { } public void Update() { - for (int x = 0; x < sizeX; x++) { - for (int y = 0; y < sizeY; y++) { - if (Elements[x,y] != null) - Elements[x,y].Update(); - } + // for (int x = 0; x < sizeX; x++) { + // for (int y = 0; y < sizeY; y++) { + // if (Elements[x,y] != null) + // Elements[x,y].Update(); + // } + // } + foreach (Element e in activeElements) { + e.Update(); } } @@ -52,12 +57,15 @@ public class Chunk { int Y = Mathf.Clamp(y + j, 0, sizeY-1); object o = Activator.CreateInstance(type, X, Y, this); - if (Elements[X,Y].GetType() != type) - Elements[X,Y] = o as Element; + if (Elements[X,Y].GetType() != type) { + Elements[X, Y] = o as Element; + activeElements.Add(Elements[X, Y]); + } } } } + // TODO: use this function and stitch together partial images in Level public Image DrawLevel() { for (int x = 0; x < sizeX; x++) { for (int y = 0; y < sizeY; y++) { @@ -67,6 +75,15 @@ public class Chunk { return image; } + public void SetElementActive(Element e, bool active) { + if (e.Active == active) return; + + if (active) + activeElements.Add(e); + else + activeElements.Remove(e); + } + public void Swap(Element what, Vector2I pos) { Swap(what, Get(pos)); } diff --git a/Scripts/Elements/Element.cs b/Scripts/Elements/Element.cs index 3b9185e..cb24643 100644 --- a/Scripts/Elements/Element.cs +++ b/Scripts/Elements/Element.cs @@ -38,6 +38,7 @@ public class Element { get => active; set { active = value; + Chunk.SetElementActive(this, active); if (active) Color = originalColor; @@ -98,5 +99,4 @@ public class Element { originalColor = c; return c; } - } From 383e1343eff76471159905a4b47e4943a686076c Mon Sep 17 00:00:00 2001 From: rogo Date: Sun, 3 Nov 2024 14:56:07 +0100 Subject: [PATCH 3/9] WiP: deactivated array elements --- Scenes/FPSLabel.cs | 3 ++- Scenes/main.tscn | 13 ++++++++++++- Scripts/Chunk.cs | 14 +++++++++++--- Scripts/Elements/Element.cs | 20 +++++++++++++------- Scripts/Level.cs | 5 ++++- Scripts/Main.cs | 28 ++++++++++------------------ 6 files changed, 52 insertions(+), 31 deletions(-) diff --git a/Scenes/FPSLabel.cs b/Scenes/FPSLabel.cs index a204847..55f8f8d 100644 --- a/Scenes/FPSLabel.cs +++ b/Scenes/FPSLabel.cs @@ -2,7 +2,8 @@ using Godot; public partial class FPSLabel : Label { - bool ShowFPS = true; + [Export] + public bool ShowFPS = true; // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { diff --git a/Scenes/main.tscn b/Scenes/main.tscn index af11d31..e113c39 100644 --- a/Scenes/main.tscn +++ b/Scenes/main.tscn @@ -1,11 +1,13 @@ -[gd_scene load_steps=4 format=3 uid="uid://cf34vk5r055dx"] +[gd_scene load_steps=5 format=3 uid="uid://cf34vk5r055dx"] [ext_resource type="Script" path="res://Scripts/Main.cs" id="1_k1i8e"] [ext_resource type="Script" path="res://Scenes/FPSLabel.cs" id="2_8cb7y"] [ext_resource type="Script" path="res://Scenes/SettingsController.cs" id="3_a4w6m"] +[ext_resource type="Script" path="res://Scenes/PerfDetails.cs" id="3_u2p48"] [node name="Main" type="Node2D"] script = ExtResource("1_k1i8e") +DebugVisualization = true BrushSize = 2 [node name="CanvasLayer" type="CanvasLayer" parent="."] @@ -32,6 +34,15 @@ text = "FPS: 0 " script = ExtResource("2_8cb7y") +[node name="PerfDetails" type="Label" parent="CanvasLayer/TopUI"] +layout_mode = 0 +offset_top = 30.0 +offset_right = 76.0 +offset_bottom = 67.0 +theme_override_font_sizes/font_size = 10 +text = "Active Elements: 0" +script = ExtResource("3_u2p48") + [node name="Settings" type="VBoxContainer" parent="CanvasLayer/TopUI"] layout_mode = 1 anchors_preset = 1 diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index ab0ffdf..9050333 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using FOU.Scripts.Elements; using Godot; @@ -16,7 +17,7 @@ public class Chunk { private readonly Image image; private readonly int sizeX; private readonly int sizeY; - private readonly List activeElements = new List(); + private readonly HashSet activeElements; public Chunk(int x, int y, int index) { Index = index; @@ -30,6 +31,8 @@ public class Chunk { } } + activeElements = new HashSet(sizeX * sizeY); + image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); image.Fill(Colors.Black); } @@ -59,7 +62,7 @@ public class Chunk { if (Elements[X,Y].GetType() != type) { Elements[X, Y] = o as Element; - activeElements.Add(Elements[X, Y]); + Elements[X, Y].Active = true; } } } @@ -78,12 +81,17 @@ public class Chunk { public void SetElementActive(Element e, bool active) { if (e.Active == active) return; - if (active) + GD.Print($"setting {e} to {active}"); + if (active && e.GetType() != typeof(Element)) activeElements.Add(e); else activeElements.Remove(e); } + public int ActiveElemetnsCount() { + return activeElements.Count; + } + public void Swap(Element what, Vector2I pos) { Swap(what, Get(pos)); } diff --git a/Scripts/Elements/Element.cs b/Scripts/Elements/Element.cs index cb24643..c0c9731 100644 --- a/Scripts/Elements/Element.cs +++ b/Scripts/Elements/Element.cs @@ -18,7 +18,7 @@ public class Element { protected const float MAX_COLOR_VARIANCE = 0.1f; protected static readonly Vector2I VERTICAL_OPPOSITE = new Vector2I(-1, 1); - private bool active = true; + private bool active = false; private Color originalColor; public Element(Element e) { @@ -32,18 +32,17 @@ public class Element { Position.Y = y; Chunk = chunk; LastMove = Engine.GetFramesDrawn(); + Active = false; } public bool Active { get => active; set { - active = value; - Chunk.SetElementActive(this, active); + if (active == value) return; - if (active) - Color = originalColor; - else if (Main.Instance.DebugVisualization) - Color = new Color(0.2f, 0.2f, 0.2f); + active = value; + Chunk.SetElementActive(this, value); + SetDebugColors(value); } } @@ -99,4 +98,11 @@ public class Element { 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); + } } diff --git a/Scripts/Level.cs b/Scripts/Level.cs index def3dd1..add31b8 100644 --- a/Scripts/Level.cs +++ b/Scripts/Level.cs @@ -18,7 +18,6 @@ public class Level { private int chunkResX; private int chunkResY; - private bool enableRain = false; private float rainAmount = 0; public Level(Main main, int sizeX, int sizeY) { @@ -75,6 +74,10 @@ public class Level { } } + public Chunk[,] GetChunks() { + return chunks; + } + private void MakeItRain() { if (rainAmount < .1f) return; diff --git a/Scripts/Main.cs b/Scripts/Main.cs index 43ab965..fea1519 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -9,35 +9,27 @@ public partial class Main : Node2D { [Export] public int BrushSize = 5; [Export] public float TextureResolution = 0.5f; [Export] public int ChunksPerAxis = 2; - - [Export] - public float RainAmount { - get => rainAmount; - set { - rainAmount = value; - mLevel.SetRainAmount(rainAmount); - } - } + [Export] public float RainAmount = 0; public static Main Instance; + public Level Level; private TextureRect mLevelDrawer; - private Level mLevel; private bool enableRain; private float rainAmount; public override void _Ready() { - mLevel = new Level(this, (int)(GetViewportRect().Size.X * TextureResolution), + Level = new Level(this, (int)(GetViewportRect().Size.X * TextureResolution), (int)(GetViewportRect().Size.Y * TextureResolution)); - mLevel.SetRainAmount(rainAmount); + Level.SetRainAmount(rainAmount); mLevelDrawer = GetNode("CanvasLayer/LevelDrawer"); Instance = this; } public override void _Process(double delta) { - mLevel.Update(); - mLevelDrawer.Texture = ImageTexture.CreateFromImage(mLevel.DrawLevel()); + Level.Update(); + mLevelDrawer.Texture = ImageTexture.CreateFromImage(Level.DrawLevel()); } public override void _UnhandledInput(InputEvent @event) { @@ -46,14 +38,14 @@ public partial class Main : Node2D { if (eventMouseButton.IsPressed()) { Vector2 mouse = GetViewport().GetMousePosition(); - float mappedX = mouse.X / (GetViewportRect().Size.X / mLevel.Resolution.X); - float mappedY = mouse.Y / (GetViewportRect().Size.Y / mLevel.Resolution.Y); + float mappedX = mouse.X / (GetViewportRect().Size.X / Level.Resolution.X); + float mappedY = mouse.Y / (GetViewportRect().Size.Y / Level.Resolution.Y); - mLevel.WritePixel((int)mappedX, (int)mappedY, BrushSize); + Level.WritePixel((int)mappedX, (int)mappedY, BrushSize); } } else if (@event is InputEventKey keyEvent && keyEvent.Pressed) { if (keyEvent.Keycode == Key.F9) - mLevel.StartBenchmark(); + Level.StartBenchmark(); } else base._UnhandledInput(@event); } From 8ebaa9e987639b85c216ab4a4bef519592d14ace Mon Sep 17 00:00:00 2001 From: rogo Date: Wed, 18 Dec 2024 20:48:01 +0100 Subject: [PATCH 4/9] fixed elements not simulating updated to godot 4.3 --- FOU.csproj | 2 +- Scripts/Chunk.cs | 4 ---- Scripts/Elements/Element.cs | 2 +- Scripts/Main.cs | 1 - project.godot | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/FOU.csproj b/FOU.csproj index f39cf71..29d95d9 100644 --- a/FOU.csproj +++ b/FOU.csproj @@ -1,4 +1,4 @@ - + net6.0 true diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index 9050333..3af20de 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using FOU.Scripts.Elements; using Godot; @@ -79,9 +78,6 @@ public class Chunk { } public void SetElementActive(Element e, bool active) { - if (e.Active == active) return; - - GD.Print($"setting {e} to {active}"); if (active && e.GetType() != typeof(Element)) activeElements.Add(e); else diff --git a/Scripts/Elements/Element.cs b/Scripts/Elements/Element.cs index c0c9731..60e141a 100644 --- a/Scripts/Elements/Element.cs +++ b/Scripts/Elements/Element.cs @@ -61,7 +61,7 @@ public class Element { } public override string ToString() { - return $"{GetType()} {Position}[{Chunk.Index}]"; + return $"{GetType()} {Position}[{Chunk.Index}] {active}"; } protected virtual void Tick() { diff --git a/Scripts/Main.cs b/Scripts/Main.cs index fea1519..37dcdf9 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -1,4 +1,3 @@ -using System.Reflection; using FOU.Scripts; using FOU.Scripts.Elements; using Godot; diff --git a/project.godot b/project.godot index c221214..37bb172 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="FOU" run/main_scene="res://Scenes/main.tscn" -config/features=PackedStringArray("4.2", "C#", "Forward Plus") +config/features=PackedStringArray("4.3", "C#", "Forward Plus") config/icon="res://icon.svg" [dotnet] From 4e6b1d642c5fc186a62ec8dc07e06c07c0158d9d Mon Sep 17 00:00:00 2001 From: rogo Date: Sat, 21 Dec 2024 15:08:55 +0100 Subject: [PATCH 5/9] fixed collection access/modification --- Scripts/Chunk.cs | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index 3af20de..c94da6c 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -17,6 +17,8 @@ public class Chunk { private readonly int sizeX; private readonly int sizeY; private readonly HashSet activeElements; + private readonly HashSet toAddElements = new(); + private readonly HashSet toRemoveElements = new(); public Chunk(int x, int y, int index) { Index = index; @@ -37,15 +39,17 @@ public class Chunk { } public void Update() { - // for (int x = 0; x < sizeX; x++) { - // for (int y = 0; y < sizeY; y++) { - // if (Elements[x,y] != null) - // Elements[x,y].Update(); - // } - // } - foreach (Element e in activeElements) { + foreach (Element e in activeElements) e.Update(); - } + + // apply changes: + foreach (Element removeElement in toRemoveElements) + activeElements.Remove(removeElement); + toRemoveElements.Clear(); + + foreach (Element addElement in toAddElements) + activeElements.Add(addElement); + toAddElements.Clear(); } public void WritePixel(int x, int y, int size) { @@ -67,21 +71,9 @@ public class Chunk { } } - // TODO: use this function and stitch together partial images in Level - public Image DrawLevel() { - for (int x = 0; x < sizeX; x++) { - for (int y = 0; y < sizeY; y++) { - image.SetPixel(x,y, Elements[x,y].Color); - } - } - return image; - } - public void SetElementActive(Element e, bool active) { - if (active && e.GetType() != typeof(Element)) - activeElements.Add(e); - else - activeElements.Remove(e); + if (active) toAddElements.Add(e); + else toRemoveElements.Remove(e); } public int ActiveElemetnsCount() { From 71db6513f22094e7dd67bd32c7ab86b326f9ad9e Mon Sep 17 00:00:00 2001 From: rogo Date: Sat, 21 Dec 2024 23:04:01 +0100 Subject: [PATCH 6/9] improved handling of colors improved debug colors refactoring --- Scenes/PerfDetails.cs | 20 +++++++++++ Scripts/Chunk.cs | 66 ++++++++++++++++++++++++++++--------- Scripts/Elements/Dirt.cs | 2 +- Scripts/Elements/Element.cs | 41 +++++++++++++---------- Scripts/Elements/Liquid.cs | 2 +- Scripts/Elements/Solid.cs | 2 +- Scripts/Elements/Water.cs | 2 +- 7 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 Scenes/PerfDetails.cs diff --git a/Scenes/PerfDetails.cs b/Scenes/PerfDetails.cs new file mode 100644 index 0000000..219ee7c --- /dev/null +++ b/Scenes/PerfDetails.cs @@ -0,0 +1,20 @@ +using FOU.Scripts; +using Godot; + +public partial class PerfDetails : Label +{ + [Export] + public bool ShowDetails = true; + + public override void _Process(double delta) + { + Text = ""; + if (!ShowDetails) return; + + int activeElements = 0; + foreach (Chunk c in Main.Instance.Level.GetChunks()) + activeElements += c.ActiveElementsCount(); + + Text += $"Active Elements: {activeElements}"; + } +} diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index c94da6c..cab7041 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -34,7 +34,7 @@ public class Chunk { activeElements = new HashSet(sizeX * sizeY); - image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); + image = Image.CreateEmpty(sizeX, sizeY, false, Image.Format.Rgb8); image.Fill(Colors.Black); } @@ -43,13 +43,28 @@ public class Chunk { e.Update(); // apply changes: - foreach (Element removeElement in toRemoveElements) - activeElements.Remove(removeElement); - toRemoveElements.Clear(); + if (toRemoveElements.Count > 0) { + foreach (Element removeElement in toRemoveElements) { + activeElements.Remove(removeElement); + removeElement.ResetColor(); + } + toRemoveElements.Clear(); + } - foreach (Element addElement in toAddElements) - activeElements.Add(addElement); - toAddElements.Clear(); + if (toAddElements.Count > 0) { + foreach (Element addElement in toAddElements) { + activeElements.Add(addElement); + addElement.SetDebugColor(Colors.Green); + } + toAddElements.Clear(); + } + } + + public void SetElementActive(Element e, bool active) { + if (e.GetType() == typeof(Element) && active) return; + + if (active) AddToChunk(e); + else RemoveFromChunk(e); } public void WritePixel(int x, int y, int size) { @@ -63,20 +78,21 @@ public class Chunk { int Y = Mathf.Clamp(y + j, 0, sizeY-1); object o = Activator.CreateInstance(type, X, Y, this); - if (Elements[X,Y].GetType() != type) { - Elements[X, Y] = o as Element; - Elements[X, Y].Active = true; + // check if not empty: + if (Elements[X,Y].GetType() != typeof(Element)) { + return; } + + // if (Elements[X,Y].GetType() != type) { + Elements[X, Y].Chunk.RemoveFromChunk(Elements[X, Y]); + Elements[X, Y] = o as Element; + Elements[X, Y].Active = true; + // } } } } - public void SetElementActive(Element e, bool active) { - if (active) toAddElements.Add(e); - else toRemoveElements.Remove(e); - } - - public int ActiveElemetnsCount() { + public int ActiveElementsCount() { return activeElements.Count; } @@ -124,6 +140,12 @@ public class Chunk { GD.PrintErr("Trying to swap null"); return; } + + if (what.Chunk != swapTo.Chunk) { + what.Chunk.RemoveFromChunk(what); + swapTo.Chunk.AddToChunk(what); + } + Element temp = new Element(what); what.Position = swapTo.Position; @@ -137,4 +159,16 @@ public class Chunk { what.Active = true; swapTo.Active = true; } + + public override string ToString() { + return $"Chunk {Index}"; + } + + private void RemoveFromChunk(Element e) { + toRemoveElements.Add(e); + } + + private void AddToChunk(Element e) { + toAddElements.Add(e); + } } diff --git a/Scripts/Elements/Dirt.cs b/Scripts/Elements/Dirt.cs index e55b14e..f6e5653 100644 --- a/Scripts/Elements/Dirt.cs +++ b/Scripts/Elements/Dirt.cs @@ -5,7 +5,7 @@ namespace FOU.Scripts.Elements; public class Dirt : Solid { public Dirt(int x, int y, ref Chunk chunk) : base(x, y, ref chunk) { - Color = AddColorVariance(Colors.Brown); + color = AddColorVariance(Colors.Brown); Density = 10; DiffuseSpeed = 50; } diff --git a/Scripts/Elements/Element.cs b/Scripts/Elements/Element.cs index 60e141a..29fad70 100644 --- a/Scripts/Elements/Element.cs +++ b/Scripts/Elements/Element.cs @@ -3,35 +3,35 @@ 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 Vector2I Position; - public int DiffuseSpeed = 10; - public const int MAX_DIFFUSE_SPEED = 100; - public const int STEPS_UNTIL_INACTIVE = 500; + protected int Density; + protected int DiffuseSpeed = 10; + protected Color color = Colors.Black; + protected const int MAX_DIFFUSE_SPEED = 100; + protected const int STEPS_UNTIL_INACTIVE = 500; protected const float MAX_COLOR_VARIANCE = 0.1f; protected static readonly Vector2I VERTICAL_OPPOSITE = new Vector2I(-1, 1); + protected int lastMove = 0; private bool active = false; + private int lastUpdate = -1; private Color originalColor; public Element(Element e) { Position = e.Position; Chunk = e.Chunk; - LastMove = Engine.GetFramesDrawn(); + lastMove = Engine.GetFramesDrawn(); } public Element(int x, int y, Chunk chunk) { Position.X = x; Position.Y = y; Chunk = chunk; - LastMove = Engine.GetFramesDrawn(); + lastMove = Engine.GetFramesDrawn(); Active = false; } @@ -42,10 +42,12 @@ public class Element { active = value; Chunk.SetElementActive(this, value); - SetDebugColors(value); + // SetDebugColor(value, new Color(0.2f, 0.2f, 0.2f)); } } + public Color Color => color; + /// /// base update method, checks if anything is to do at all /// @@ -54,8 +56,8 @@ public class Element { public virtual bool Update() { if (!Active) return false; - if (LastUpdate == Engine.GetFramesDrawn()) return false; // already updated this frame - LastUpdate = Engine.GetFramesDrawn(); + if (lastUpdate == Engine.GetFramesDrawn()) return false; // already updated this frame + lastUpdate = Engine.GetFramesDrawn(); return true; } @@ -99,10 +101,13 @@ public class Element { 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); + public void ResetColor() { + color = originalColor; + } + + public void SetDebugColor(Color color) { + if (!Main.Instance.DebugVisualization) return; + + this.color = color; } } diff --git a/Scripts/Elements/Liquid.cs b/Scripts/Elements/Liquid.cs index 1d40ae6..ef1fe19 100644 --- a/Scripts/Elements/Liquid.cs +++ b/Scripts/Elements/Liquid.cs @@ -9,7 +9,7 @@ public abstract class Liquid : Element { public override bool Update() { if (!base.Update()) return false; - if (LastMove + STEPS_UNTIL_INACTIVE < Engine.GetFramesDrawn()) Active = false; + if (lastMove + STEPS_UNTIL_INACTIVE < Engine.GetFramesDrawn()) Active = false; Tick(); diff --git a/Scripts/Elements/Solid.cs b/Scripts/Elements/Solid.cs index 0257ed4..a9803ca 100644 --- a/Scripts/Elements/Solid.cs +++ b/Scripts/Elements/Solid.cs @@ -7,7 +7,7 @@ public abstract class Solid : Element { public override bool Update() { if (!base.Update()) return false; - if (LastMove + STEPS_UNTIL_INACTIVE < Engine.GetFramesDrawn()) Active = false; + if (lastMove + STEPS_UNTIL_INACTIVE < Engine.GetFramesDrawn()) Active = false; Tick(); diff --git a/Scripts/Elements/Water.cs b/Scripts/Elements/Water.cs index 200f2b5..aeb93b8 100644 --- a/Scripts/Elements/Water.cs +++ b/Scripts/Elements/Water.cs @@ -5,7 +5,7 @@ namespace FOU.Scripts.Elements; public class Water : Liquid { public Water(int x, int y, ref Chunk chunk) : base(x, y, ref chunk) { - Color = AddColorVariance(Colors.Blue); + color = AddColorVariance(Colors.Blue); Density = 1; } From 5045b4421e551fa5d959bb4d6ca14b4a9a2f62da Mon Sep 17 00:00:00 2001 From: rogo Date: Thu, 17 Apr 2025 20:21:24 +0200 Subject: [PATCH 7/9] fixed inactivity timer --- Scripts/Chunk.cs | 2 ++ Scripts/Elements/Element.cs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index cab7041..7486d7b 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -157,7 +157,9 @@ public class Chunk { swapTo.Chunk.Elements[swapTo.Position.X, swapTo.Position.Y] = swapTo; what.Active = true; + what.Moved(); swapTo.Active = true; + swapTo.Moved(); } public override string ToString() { diff --git a/Scripts/Elements/Element.cs b/Scripts/Elements/Element.cs index 29fad70..62fe24c 100644 --- a/Scripts/Elements/Element.cs +++ b/Scripts/Elements/Element.cs @@ -110,4 +110,8 @@ public class Element { this.color = color; } + + public void Moved() { + lastMove = Engine.GetFramesDrawn(); + } } From 882a12862e6fd9d73e9a94c0ef68234232e8e171 Mon Sep 17 00:00:00 2001 From: rogo Date: Thu, 17 Apr 2025 20:26:43 +0200 Subject: [PATCH 8/9] updated to 4.4 --- Scenes/FPSLabel.cs.uid | 1 + Scenes/PerfDetails.cs.uid | 1 + Scenes/SettingsController.cs.uid | 1 + Scenes/main.tscn | 8 ++++---- Scripts/Chunk.cs.uid | 1 + Scripts/Elements/Dirt.cs.uid | 1 + Scripts/Elements/Element.cs.uid | 1 + Scripts/Elements/Liquid.cs.uid | 1 + Scripts/Elements/Solid.cs.uid | 1 + Scripts/Elements/Water.cs.uid | 1 + Scripts/Level.cs.uid | 1 + Scripts/Main.cs.uid | 1 + 12 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 Scenes/FPSLabel.cs.uid create mode 100644 Scenes/PerfDetails.cs.uid create mode 100644 Scenes/SettingsController.cs.uid create mode 100644 Scripts/Chunk.cs.uid create mode 100644 Scripts/Elements/Dirt.cs.uid create mode 100644 Scripts/Elements/Element.cs.uid create mode 100644 Scripts/Elements/Liquid.cs.uid create mode 100644 Scripts/Elements/Solid.cs.uid create mode 100644 Scripts/Elements/Water.cs.uid create mode 100644 Scripts/Level.cs.uid create mode 100644 Scripts/Main.cs.uid diff --git a/Scenes/FPSLabel.cs.uid b/Scenes/FPSLabel.cs.uid new file mode 100644 index 0000000..7ff74b6 --- /dev/null +++ b/Scenes/FPSLabel.cs.uid @@ -0,0 +1 @@ +uid://d3cbk8f7lckbr diff --git a/Scenes/PerfDetails.cs.uid b/Scenes/PerfDetails.cs.uid new file mode 100644 index 0000000..7171816 --- /dev/null +++ b/Scenes/PerfDetails.cs.uid @@ -0,0 +1 @@ +uid://52grhydeyy0t diff --git a/Scenes/SettingsController.cs.uid b/Scenes/SettingsController.cs.uid new file mode 100644 index 0000000..6f68b87 --- /dev/null +++ b/Scenes/SettingsController.cs.uid @@ -0,0 +1 @@ +uid://dxmkbb5f1t368 diff --git a/Scenes/main.tscn b/Scenes/main.tscn index e113c39..16de3fc 100644 --- a/Scenes/main.tscn +++ b/Scenes/main.tscn @@ -1,9 +1,9 @@ [gd_scene load_steps=5 format=3 uid="uid://cf34vk5r055dx"] -[ext_resource type="Script" path="res://Scripts/Main.cs" id="1_k1i8e"] -[ext_resource type="Script" path="res://Scenes/FPSLabel.cs" id="2_8cb7y"] -[ext_resource type="Script" path="res://Scenes/SettingsController.cs" id="3_a4w6m"] -[ext_resource type="Script" path="res://Scenes/PerfDetails.cs" id="3_u2p48"] +[ext_resource type="Script" uid="uid://cmvvubxfvdca7" path="res://Scripts/Main.cs" id="1_k1i8e"] +[ext_resource type="Script" uid="uid://d3cbk8f7lckbr" path="res://Scenes/FPSLabel.cs" id="2_8cb7y"] +[ext_resource type="Script" uid="uid://dxmkbb5f1t368" path="res://Scenes/SettingsController.cs" id="3_a4w6m"] +[ext_resource type="Script" uid="uid://52grhydeyy0t" path="res://Scenes/PerfDetails.cs" id="3_u2p48"] [node name="Main" type="Node2D"] script = ExtResource("1_k1i8e") diff --git a/Scripts/Chunk.cs.uid b/Scripts/Chunk.cs.uid new file mode 100644 index 0000000..76de819 --- /dev/null +++ b/Scripts/Chunk.cs.uid @@ -0,0 +1 @@ +uid://r17upkbkmfiy diff --git a/Scripts/Elements/Dirt.cs.uid b/Scripts/Elements/Dirt.cs.uid new file mode 100644 index 0000000..4e6a188 --- /dev/null +++ b/Scripts/Elements/Dirt.cs.uid @@ -0,0 +1 @@ +uid://80esqy0cardd diff --git a/Scripts/Elements/Element.cs.uid b/Scripts/Elements/Element.cs.uid new file mode 100644 index 0000000..1735331 --- /dev/null +++ b/Scripts/Elements/Element.cs.uid @@ -0,0 +1 @@ +uid://b5lme1c4rx15n diff --git a/Scripts/Elements/Liquid.cs.uid b/Scripts/Elements/Liquid.cs.uid new file mode 100644 index 0000000..a3d57e6 --- /dev/null +++ b/Scripts/Elements/Liquid.cs.uid @@ -0,0 +1 @@ +uid://bqx36wisy7127 diff --git a/Scripts/Elements/Solid.cs.uid b/Scripts/Elements/Solid.cs.uid new file mode 100644 index 0000000..5fe51ca --- /dev/null +++ b/Scripts/Elements/Solid.cs.uid @@ -0,0 +1 @@ +uid://ur56t06r7n4l diff --git a/Scripts/Elements/Water.cs.uid b/Scripts/Elements/Water.cs.uid new file mode 100644 index 0000000..f167cfc --- /dev/null +++ b/Scripts/Elements/Water.cs.uid @@ -0,0 +1 @@ +uid://k8id5egjc7x8 diff --git a/Scripts/Level.cs.uid b/Scripts/Level.cs.uid new file mode 100644 index 0000000..bc25504 --- /dev/null +++ b/Scripts/Level.cs.uid @@ -0,0 +1 @@ +uid://bkwbjagt8s01s diff --git a/Scripts/Main.cs.uid b/Scripts/Main.cs.uid new file mode 100644 index 0000000..75a805e --- /dev/null +++ b/Scripts/Main.cs.uid @@ -0,0 +1 @@ +uid://cmvvubxfvdca7 From 7f31c8c3d510ea3e30ff3d89ec7b17df399e8415 Mon Sep 17 00:00:00 2001 From: rogo Date: Fri, 18 Apr 2025 01:11:10 +0200 Subject: [PATCH 9/9] WiP: chunk overdraw fix --- FOU.csproj | 4 +-- Scenes/main.tscn | 1 + Scripts/Chunk.cs | 32 +++++++---------- Scripts/Level.cs | 91 +++++++++++++++++++++++++++++++++++++----------- Scripts/Main.cs | 6 +++- benchmark.txt | 15 +++++--- project.godot | 2 +- 7 files changed, 103 insertions(+), 48 deletions(-) diff --git a/FOU.csproj b/FOU.csproj index 29d95d9..70ab8a3 100644 --- a/FOU.csproj +++ b/FOU.csproj @@ -1,6 +1,6 @@ - + - net6.0 + net8.0 true diff --git a/Scenes/main.tscn b/Scenes/main.tscn index 16de3fc..187b0df 100644 --- a/Scenes/main.tscn +++ b/Scenes/main.tscn @@ -9,6 +9,7 @@ script = ExtResource("1_k1i8e") DebugVisualization = true BrushSize = 2 +RainAmount = 1.0 [node name="CanvasLayer" type="CanvasLayer" parent="."] diff --git a/Scripts/Chunk.cs b/Scripts/Chunk.cs index 7486d7b..ece2b90 100644 --- a/Scripts/Chunk.cs +++ b/Scripts/Chunk.cs @@ -67,29 +67,23 @@ public class Chunk { else RemoveFromChunk(e); } - public void WritePixel(int x, int y, int size) { - int halfsize = size/2; + public void WritePixel(int x, int y) { + if (x < 0 || x >= sizeX || y < 0 || y >= sizeY) { + GD.PrintErr($"Out of bounds for chunk: {x}:{y}"); + return; + } Type type = typeof(T); + object o = Activator.CreateInstance(type, x, y, this); - for (int i = -halfsize; i <= halfsize; i++) { - for (int j = -halfsize; j <= halfsize; j++) { - int X = Mathf.Clamp(x + i, 0, sizeX-1); - int Y = Mathf.Clamp(y + j, 0, sizeY-1); - object o = Activator.CreateInstance(type, X, Y, this); - - // check if not empty: - if (Elements[X,Y].GetType() != typeof(Element)) { - return; - } - - // if (Elements[X,Y].GetType() != type) { - Elements[X, Y].Chunk.RemoveFromChunk(Elements[X, Y]); - Elements[X, Y] = o as Element; - Elements[X, Y].Active = true; - // } - } + // check if not empty: + if (Elements[x,y].GetType() != typeof(Element)) { + return; } + + Elements[x, y].Chunk.RemoveFromChunk(Elements[x, y]); + Elements[x, y] = o as Element; + Elements[x, y].Active = true; } public int ActiveElementsCount() { diff --git a/Scripts/Level.cs b/Scripts/Level.cs index add31b8..e39de58 100644 --- a/Scripts/Level.cs +++ b/Scripts/Level.cs @@ -11,8 +11,8 @@ public class Level { private Chunk[,] chunks; private Image image; - private int chunksX; - private int chunksY; + private int chunksPerX; + private int chunksPerY; // per chunk: private int chunkResX; @@ -22,34 +22,34 @@ public class Level { public Level(Main main, int sizeX, int sizeY) { Resolution = new Vector2I(sizeX, sizeY); - chunksX = main.ChunksPerAxis; - chunksY = main.ChunksPerAxis; + chunksPerX = main.ChunksPerAxis; + chunksPerY = main.ChunksPerAxis; - chunkResX = sizeX / chunksX; - chunkResY = sizeY / chunksY; + chunkResX = sizeX / chunksPerX; + chunkResY = sizeY / chunksPerY; - GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksX*chunksY} chunks ({chunkResX} * {chunkResY})"); + GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksPerX*chunksPerY} chunks ({chunkResX} * {chunkResY})"); image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); - chunks = new Chunk[chunksX, chunksY]; + chunks = new Chunk[chunksPerX, chunksPerY]; int index = 0; // create all chunks - for (int x = 0; x < chunksX; x++) { - for (int y = 0; y < chunksY; y++) { + 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 < chunksX; x++) { - for (int y = 0; y < chunksY; y++) { + 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 < chunksY-1) chunks[x, y].NeighborS = 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 < chunksX-1) chunks[x, y].NeighborW = chunks[x+1, y]; + if (x < chunksPerX-1) chunks[x, y].NeighborW = chunks[x+1, y]; } } } @@ -67,9 +67,9 @@ public class Level { public void StartBenchmark() { GD.Print("benchmark"); - for (int x = 0; x < chunksX; x++) { - for (int y = 0; y < chunksY; y++) { - chunks[x, y].WritePixel(chunkResX/2, chunkResY/2, 100); + for (int x = 0; x < chunksPerX; x++) { + for (int y = 0; y < chunksPerY; y++) { + WritePixel(x * chunkResX/2, y * chunkResY/2, 100); } } } @@ -85,17 +85,66 @@ public class Level { for (int i = 0; i <= rainDrops; i++) { if (GD.Randf() < rainAmount) - WritePixel((int)(GD.Randi() % (chunkResX * chunksX)), 0, 1); + WritePixel((int)(GD.Randi() % (chunkResX * chunksPerX)), 0, 1); } } public void WritePixel(int x, int y, int size) { - chunks[x/chunkResX, y/chunkResY].WritePixel(x % chunkResX, y % chunkResY, 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(inChunkX, inChunkY); + } + } } public Image DrawLevel() { - for (int cx = 0; cx < chunksX; cx++) { - for (int cy = 0; cy < chunksY; cy++) { + 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++) { diff --git a/Scripts/Main.cs b/Scripts/Main.cs index 37dcdf9..b8ca1c9 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -26,8 +26,12 @@ public partial class Main : Node2D { Instance = this; } - public override void _Process(double delta) { + public override void _PhysicsProcess(double delta) { + base._PhysicsProcess(delta); Level.Update(); + } + + public override void _Process(double delta) { mLevelDrawer.Texture = ImageTexture.CreateFromImage(Level.DrawLevel()); } diff --git a/benchmark.txt b/benchmark.txt index b247ef3..bc9fca6 100644 --- a/benchmark.txt +++ b/benchmark.txt @@ -1,15 +1,22 @@ -# Benchmark +# Benchmark + +Start from editor not rider! ## Settings + - Texture Resolution: 0.5 - CHunks per Axis: 2 - Rain Amount: 0 ## Measurements: + ### original (no optimization): + - idle: 42 - 44 fps - benchmark: 24 fps minimum -### only active: -- idle: 100 fps -- benchmark: 36 fps minimum +### performance-improvements (71db6513f22094e7dd67bd32c7ab86b326f9ad9e) + +- idle before: 89 +- benchmark: 33 +- idle after: 75 diff --git a/project.godot b/project.godot index 37bb172..f95826d 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="FOU" run/main_scene="res://Scenes/main.tscn" -config/features=PackedStringArray("4.3", "C#", "Forward Plus") +config/features=PackedStringArray("4.4", "C#", "Forward Plus") config/icon="res://icon.svg" [dotnet]