diff --git a/Main.cs b/Main.cs index 033ae29..f7607ff 100644 --- a/Main.cs +++ b/Main.cs @@ -1,15 +1,20 @@ using System.Collections.Generic; +using System.Linq; using Godot; public class Main : Node2D { + private const int ParticleScreenPadding = 16; + private readonly List _particleTypes = new List(); + private List _particles; public override void _Ready() { GD.Randomize(); - InitializeParticleTypes(5); - InitializeParticles(50); + InitializeParticleTypes(10); + InitializeParticles(200); + _particles = GetNode("Particles").GetChildren().Cast().ToList(); } public override void _Process(float delta) @@ -18,6 +23,11 @@ public class Main : Node2D if (Input.IsActionJustPressed("reset")) GetTree().ReloadCurrentScene(); } + public override void _PhysicsProcess(float delta) + { + UpdateParticles(); + } + private void InitializeParticleTypes(int nTypes) { for (var i = 0; i < nTypes; i++) @@ -28,6 +38,10 @@ public class Main : Node2D }; _particleTypes.Add(type); } + + foreach (var type1 in _particleTypes) + foreach (var type2 in _particleTypes) + type1.AddRelationship(type2, 20, (float) GD.RandRange(25, 60), (float) GD.RandRange(-0.33, 0.35)); } private void InitializeParticles(int nParticles) @@ -40,7 +54,7 @@ public class Main : Node2D GetNode("Particles").AddChild(particle); particle.Position = GetRandomParticlePosition(); particle.Type = _particleTypes[typeCount]; - + if (typeCount < _particleTypes.Count - 1) typeCount++; else @@ -50,10 +64,58 @@ public class Main : Node2D private Vector2 GetRandomParticlePosition() { - const int padding = 32; var viewportRect = GetViewportRect(); - var position = new Vector2((float) GD.RandRange(padding, viewportRect.Size.x - padding), - (float) GD.RandRange(padding, viewportRect.Size.y - padding)); + var position = new Vector2( + (float) GD.RandRange(ParticleScreenPadding, viewportRect.Size.x - ParticleScreenPadding), + (float) GD.RandRange(ParticleScreenPadding, viewportRect.Size.y - ParticleScreenPadding)); return position; } + + private void UpdateParticles() + { + var viewportRect = GetViewportRect(); + foreach (var p1 in _particles) + { + foreach (var p2 in _particles) + { + if (p1 == p2) + continue; + var distance = p1.Position.DistanceTo(p2.Position); + if (distance > 60f) + continue; + var direction = p1.Position.DirectionTo(p2.Position); + + // collision force + if (distance < 20) + { + const float collisionStretch = 1f; + const float collisionOffset = 13f; + const float collisionFlatten = 1f; + var rawCollisionForce = -Mathf.Pow(Mathf.E, -(collisionStretch * distance - collisionOffset)) / + collisionFlatten; + var clampedCollisionForce = Mathf.Clamp(rawCollisionForce, -1f, 1f); + p1.Velocity += direction * clampedCollisionForce; + } + // particle relationship force + + var props = p1.Type.GetRelationship(p2.Type); + if (props.Force != 0f && distance >= props.MinRadius && distance <= props.MaxRadius) + { + var slope = props.Force / ((props.MaxRadius - props.MinRadius) / 2f); + var rawParticleForce = -slope * Mathf.Abs(distance - (props.MinRadius + props.MaxRadius) / 2f) + + props.Force; + p1.Velocity += direction * rawParticleForce; + } + + p1.Velocity = p1.Velocity.Clamped(3f); + } + + var position = p1.Position; + position += p1.Velocity; + p1.Velocity *= 0.95f; + position.x = Mathf.Clamp(position.x, ParticleScreenPadding, viewportRect.Size.x - ParticleScreenPadding); + position.y = Mathf.Clamp(position.y, ParticleScreenPadding, viewportRect.Size.y - ParticleScreenPadding); + p1.Position = position; + } + } } \ No newline at end of file diff --git a/Particle.cs b/Particle.cs index e111f38..a1872aa 100644 --- a/Particle.cs +++ b/Particle.cs @@ -5,6 +5,8 @@ public class Particle : Node2D private Sprite _spriteNode; private ParticleType _type; + public Vector2 Velocity { get; set; } + public ParticleType Type { get => _type; diff --git a/Particle.tscn b/Particle.tscn index 36effd2..3156c79 100644 --- a/Particle.tscn +++ b/Particle.tscn @@ -7,4 +7,5 @@ script = ExtResource( 2 ) [node name="Sprite" type="Sprite" parent="."] +scale = Vector2( 0.25, 0.25 ) texture = ExtResource( 1 ) diff --git a/ParticleType.cs b/ParticleType.cs index b18cdfb..5d7c966 100644 --- a/ParticleType.cs +++ b/ParticleType.cs @@ -17,11 +17,11 @@ public struct ParticleRelationshipProps public class ParticleType { - private float _hue; - private readonly Dictionary _particleRelationships = new Dictionary(); + private float _hue; + public float Hue { get => _hue; @@ -35,4 +35,9 @@ public class ParticleType var props = new ParticleRelationshipProps(minRadius, maxRadius, force); _particleRelationships[type] = props; } + + public ParticleRelationshipProps GetRelationship(ParticleType type) + { + return _particleRelationships[type]; + } } \ No newline at end of file diff --git a/Particles.csproj b/Particles.csproj index ceaf2bb..647872a 100644 --- a/Particles.csproj +++ b/Particles.csproj @@ -1,5 +1,7 @@ net472 + Debug;ExportDebug;ExportRelease;Release + AnyCPU \ No newline at end of file diff --git a/Particles.sln b/Particles.sln index 6d75ae5..f96954d 100644 --- a/Particles.sln +++ b/Particles.sln @@ -7,13 +7,16 @@ Global Debug|Any CPU = Debug|Any CPU ExportDebug|Any CPU = ExportDebug|Any CPU ExportRelease|Any CPU = ExportRelease|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E15A1F42-C497-4EDE-8944-84CB055B33CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E15A1F42-C497-4EDE-8944-84CB055B33CB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU - {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU - {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU + {E15A1F42-C497-4EDE-8944-84CB055B33CB}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU + {E15A1F42-C497-4EDE-8944-84CB055B33CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E15A1F42-C497-4EDE-8944-84CB055B33CB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/project.godot b/project.godot index 34ab24b..af2a5df 100644 --- a/project.godot +++ b/project.godot @@ -16,10 +16,8 @@ config/icon="res://icon.png" [display] -window/size/width=1920 -window/size/height=1080 -window/size/resizable=false -window/size/borderless=true +window/size/width=1600 +window/size/height=900 [input]