7 Commits

Author SHA1 Message Date
f324122874 updated to godot 4.5 2025-10-26 18:30:27 +01:00
f932ae1bcd refactoring 2025-05-01 23:34:31 +02:00
c41cdd57c4 fixed activate not set on copy 2025-05-01 23:06:46 +02:00
e653f23a42 dirt shall only move downwards 2025-05-01 23:01:42 +02:00
6acccefa0a diffuse in both directions 2025-05-01 22:51:39 +02:00
28ada065a6 fixed stuck pixels 2025-05-01 22:50:35 +02:00
ea34b8ecc0 moved tick to process from physics process
fixed fall speed
improved naming
2025-05-01 22:46:51 +02:00
11 changed files with 73 additions and 39 deletions

View File

@@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.4.1"> <Project Sdk="Godot.NET.Sdk/4.5.1">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading> <EnableDynamicLoading>true</EnableDynamicLoading>

12
FOU.csproj.old.1 Normal file
View File

@@ -0,0 +1,12 @@
<Project Sdk="Godot.NET.Sdk/4.4.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
<ItemGroup>
<Content Include="benchmark.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="UI\" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,3 @@
using System.Reflection;
using FOU.Scripts;
using Godot; using Godot;
public partial class SettingsController : VBoxContainer public partial class SettingsController : VBoxContainer

View File

@@ -87,3 +87,10 @@ size_flags_vertical = 1
max_value = 10.0 max_value = 10.0
step = 0.01 step = 0.01
value = 1.0 value = 1.0
[node name="ToolbarMarginContainer2" parent="CanvasLayer/TopUI" instance=ExtResource("5_kry3j")]
layout_mode = 0
offset_left = 860.0
offset_top = 5.0
offset_right = 1060.0
offset_bottom = 69.0

View File

@@ -61,7 +61,7 @@ public class Chunk {
} }
public void SetElementActive(Element e, bool active) { public void SetElementActive(Element e, bool active) {
if (e.GetType() == typeof(Element) && active) return; if (e.GetType() == typeof(Element)) return;
if (active) AddToChunk(e); if (active) AddToChunk(e);
else RemoveFromChunk(e); else RemoveFromChunk(e);

View File

@@ -6,48 +6,51 @@ public class Element{
public Chunk Chunk; public Chunk Chunk;
public Vector2I Position; public Vector2I Position;
public int Density;
protected int Density;
protected int DiffuseSpeed = 10; protected int DiffuseSpeed = 10;
protected Color color = Colors.Black; protected Color color = Colors.Black;
protected const int MAX_DIFFUSE_SPEED = 100; protected const int MAX_DIFFUSE_SPEED = 100;
protected const int STEPS_UNTIL_INACTIVE = 500; 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 static readonly Vector2I VERTICAL_OPPOSITE = new Vector2I(-1, 1);
private const float MAX_COLOR_VARIANCE = 0.1f;
private bool active = false; private bool active = false;
private bool markedForUpdate = true;
private int lastUpdate = -1; private int lastUpdate = -1;
private int lastMove = 0; private int lastMove = 0;
private Color originalColor; private Color originalColor;
private bool markedForUpdate = false;
public Element(Element e) { public Element(Element e) {
Position = e.Position; Position = e.Position;
Chunk = e.Chunk; Chunk = e.Chunk;
lastMove = Engine.GetFramesDrawn(); Active = e.active;
lastMove = e.lastMove;
lastUpdate = e.lastUpdate;
Chunk.SetElementActive(this, Active);
} }
public Element(int x, int y, Chunk chunk) { public Element(int x, int y, Chunk chunk) {
Position.X = x; Position.X = x;
Position.Y = y; Position.Y = y;
Chunk = chunk; Chunk = chunk;
Active = true; lastMove = Engine.GetFramesDrawn();
Chunk.SetElementActive(this, Active);
} }
public bool Active { public bool Active {
get => active; get => active;
set { set {
if (active == value) return; if (active == value) return;
active = value; active = value;
Chunk.SetElementActive(this, value); Chunk.SetElementActive(this, value);
lastMove = Engine.GetFramesDrawn();
if (!active) if (active) {
ResetColor();
else
Moved(); Moved();
} else {
ResetColor();
}
} }
} }
@@ -68,7 +71,6 @@ public class Element{
return false; // already updated this frame return false; // already updated this frame
lastUpdate = frame; lastUpdate = frame;
return true; return true;
} }
@@ -76,25 +78,8 @@ public class Element{
return $"{GetType()} {Position}[{Chunk.Index}] {active}"; return $"{GetType()} {Position}[{Chunk.Index}] {active}";
} }
protected virtual void Tick() { 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; // descend slower
if (Chunk.Get(Position + randomDirection)?.Density < Density)
Chunk.Swap(this, Position + Vector2I.Down);
}
/// <returns>-1, 0 or 1</returns>
protected Vector2I RandomDirectionDown() { protected Vector2I RandomDirectionDown() {
int randomDirection = GD.Randi() % 2 != 0 ? 1 : -1; int randomDirection = GD.Randi() % 2 != 0 ? 1 : -1;
@@ -102,6 +87,13 @@ public class Element{
+ (GD.Randi() % 2 != 0 ? Vector2I.Zero : Vector2I.Right * randomDirection); + (GD.Randi() % 2 != 0 ? Vector2I.Zero : Vector2I.Right * randomDirection);
} }
/// <returns>-1, 0 or 1</returns>
protected Vector2I RandomDirection() {
int randomDirection = GD.Randi() % 2 != 0 ? 1 : -1;
return (GD.Randi() % 2 != 0 ? Vector2I.Zero : Vector2I.Right * randomDirection);
}
protected Color AddColorVariance(Color baseColor) { protected Color AddColorVariance(Color baseColor) {
Color c = baseColor; Color c = baseColor;
c.R += (GD.Randf() - 1) * MAX_COLOR_VARIANCE; c.R += (GD.Randf() - 1) * MAX_COLOR_VARIANCE;
@@ -128,7 +120,7 @@ public class Element{
MarkForUpdate(); MarkForUpdate();
} }
public bool MarkedForUpdate() { public bool IsMarkedForUpdate() {
return markedForUpdate; return markedForUpdate;
} }

View File

@@ -17,7 +17,7 @@ public abstract class Liquid : Element {
return true; // not necessarily end, subclasses could do some more things return true; // not necessarily end, subclasses could do some more things
} }
protected override void Tick() { protected virtual void Tick() {
Vector2I randomDirection = RandomDirectionDown(); Vector2I randomDirection = RandomDirectionDown();
if (randomDirection.Y != 0) if (randomDirection.Y != 0)
randomDirection *= Vector2I.Left * (int)(GD.Randi() % MAX_VERTICAL_SPREAD); randomDirection *= Vector2I.Left * (int)(GD.Randi() % MAX_VERTICAL_SPREAD);

View File

@@ -14,4 +14,29 @@ public abstract class Solid : Element {
return true; // not necessarily end, subclasses could do some more things return true; // not necessarily end, subclasses could do some more things
} }
protected virtual void Tick() {
Vector2I randomDirection = RandomDirectionDown();
// fall speed reduction:
if (GD.Randi() % MAX_DIFFUSE_SPEED > DiffuseSpeed) return; // descend slower
if (Chunk.IsEmpty(Position + Vector2I.Down))
Chunk.Swap(this, Position + Vector2I.Down);
else if (Chunk.IsEmpty(Position + Vector2I.Down + randomDirection))
Chunk.Swap(this, Position + Vector2I.Down + randomDirection);
else if (Chunk.IsEmpty(Position + Vector2I.Down + randomDirection * VERTICAL_OPPOSITE))
Chunk.Swap(this, Position + Vector2I.Down + randomDirection * VERTICAL_OPPOSITE);
// density check
if (Chunk.Get(Position + Vector2I.Down)?.Density < Density)
Chunk.Swap(this, Position + Vector2I.Down);
else if (Chunk.Get(Position + Vector2I.Down + randomDirection)?.Density < Density)
Chunk.Swap(this, Position + Vector2I.Down + randomDirection);
else if (Chunk.Get(Position + Vector2I.Down + randomDirection * VERTICAL_OPPOSITE)?.Density < Density)
Chunk.Swap(this, Position + Vector2I.Down + randomDirection * VERTICAL_OPPOSITE);
}
} }

View File

@@ -30,7 +30,7 @@ public class Level {
GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksPerX*chunksPerY} chunks ({chunkResX} * {chunkResY})"); GD.Print($"Generating level ({sizeX}:{sizeY}) with {chunksPerX*chunksPerY} chunks ({chunkResX} * {chunkResY})");
image = Image.Create(sizeX, sizeY, false, Image.Format.Rgb8); image = Image.CreateEmpty(sizeX, sizeY, false, Image.Format.Rgb8);
chunks = new Chunk[chunksPerX, chunksPerY]; chunks = new Chunk[chunksPerX, chunksPerY];
int index = 0; int index = 0;
@@ -165,7 +165,7 @@ public class Level {
for (int y = 0; y < chunkResY; y++) { for (int y = 0; y < chunkResY; y++) {
// TODO: multithreading here! use Chunk.DrawLevel() and stitch images together // TODO: multithreading here! use Chunk.DrawLevel() and stitch images together
if (chunks[cx, cy].Elements[x, y].MarkedForUpdate()) { if (chunks[cx, cy].Elements[x, y].IsMarkedForUpdate()) {
image.SetPixel(cx * chunkResX + x, cy * chunkResY + y, chunks[cx, cy].Elements[x, y].Color); image.SetPixel(cx * chunkResX + x, cy * chunkResY + y, chunks[cx, cy].Elements[x, y].Color);
chunks[cx, cy].Elements[x, y].MarkForUpdate(false); chunks[cx, cy].Elements[x, y].MarkForUpdate(false);
} }

View File

@@ -36,10 +36,10 @@ public partial class Main : Node2D {
public override void _PhysicsProcess(double delta) { public override void _PhysicsProcess(double delta) {
base._PhysicsProcess(delta); base._PhysicsProcess(delta);
Level.Update();
} }
public override void _Process(double delta) { public override void _Process(double delta) {
Level.Update();
mLevelDrawer.Texture?.Dispose(); mLevelDrawer.Texture?.Dispose();
mLevelDrawer.Texture = ImageTexture.CreateFromImage(Level.DrawLevel()); mLevelDrawer.Texture = ImageTexture.CreateFromImage(Level.DrawLevel());
} }

View File

@@ -12,7 +12,7 @@ config_version=5
config/name="FOU" config/name="FOU"
run/main_scene="res://Scenes/main.tscn" run/main_scene="res://Scenes/main.tscn"
config/features=PackedStringArray("4.4", "C#", "Forward Plus") config/features=PackedStringArray("4.5", "C#", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[dotnet] [dotnet]