diff --git a/Main.cs b/Main.cs index 7f4c6f3..e0aa4b9 100644 --- a/Main.cs +++ b/Main.cs @@ -12,14 +12,17 @@ public class Main : Node2D public override void _Ready() { - _particleNodes = GetNode("ParticlesNodes"); + _particleNodes = GetNode("ParticleNodes"); GD.Randomize(); - var randomSeed = GD.Randi(); + ulong randomSeed = GD.Randi(); GD.Seed(randomSeed); GD.Print("Last Seed: " + randomSeed); + var viewSize = GetViewportRect().Size; + var zoom = GetNode("Camera2D").Zoom; + var spaceSize = new Vector2(viewSize.x * zoom.x, viewSize.y * zoom.y); _particleSimulation = new ParticleSimulation { - SpaceSize = GetViewportRect().Size * 1.15f + SpaceSize = spaceSize }; _particleSimulation.Initialize(); foreach (var id in _particleSimulation.LastParticlesAdded) CreateParticleNode(id); @@ -51,7 +54,7 @@ public class Main : Node2D particleNode.CurrentSimulationPosition = simulationParticle.Position; particleNode.SetColor(simulationParticle.Type.Hue, simulationParticle.Health, Mathf.Clamp(simulationParticle.AverageSpeed / 1.5f, 1f, 1f)); - particleNode.ScreenWrappedLast = simulationParticle.ScreenWrappedLast; + particleNode.WasTeleportedLast = simulationParticle.WasTeleportedLast; } } diff --git a/Main.tscn b/Main.tscn index 820ba09..d3c1728 100644 --- a/Main.tscn +++ b/Main.tscn @@ -5,9 +5,9 @@ [node name="Main" type="Node2D"] script = ExtResource( 1 ) -[node name="ParticlesNodes" type="Node2D" parent="."] +[node name="ParticleNodes" type="Node2D" parent="."] [node name="Camera2D" type="Camera2D" parent="."] anchor_mode = 0 current = true -zoom = Vector2( 1.15, 1.15 ) +zoom = Vector2( 1.35, 1.35 ) diff --git a/ParticleNode.cs b/ParticleNode.cs index 403d2d0..9f23ef2 100644 --- a/ParticleNode.cs +++ b/ParticleNode.cs @@ -9,7 +9,7 @@ public class ParticleNode : Node2D public Vector2 CurrentSimulationPosition = new Vector2(); public Vector2 LastSimulationPosition; - public bool ScreenWrappedLast = false; + public bool WasTeleportedLast = true; public int SimulationId; public override void _Ready() @@ -20,7 +20,7 @@ public class ParticleNode : Node2D public override void _Process(float delta) { - Position = ScreenWrappedLast == false + Position = WasTeleportedLast == false ? LastSimulationPosition.LinearInterpolate(CurrentSimulationPosition, GetParent().GetParent
().PhysicsInterpolationFraction) : CurrentSimulationPosition; diff --git a/ParticleNode.tscn b/ParticleNode.tscn index eb89554..2bd8f95 100644 --- a/ParticleNode.tscn +++ b/ParticleNode.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=2] [ext_resource path="res://ParticleNode.cs" type="Script" id=1] -[ext_resource path="res://textures/particle.png" type="Texture" id=2] +[ext_resource path="res://textures/particle_noborder.png" type="Texture" id=2] [node name="ParticleNode" type="Node2D"] script = ExtResource( 1 ) diff --git a/ParticleSimulation/Particle.cs b/ParticleSimulation/Particle.cs index 69e19b9..58f2e1d 100644 --- a/ParticleSimulation/Particle.cs +++ b/ParticleSimulation/Particle.cs @@ -7,7 +7,7 @@ namespace Particles.ParticleSimulation private float _health = 1f; public Vector2 Position = new Vector2(); - public bool ScreenWrappedLast = true; + public bool WasTeleportedLast = true; public Vector2 Velocity = new Vector2(); public Particle(int id, ParticleType type) @@ -33,5 +33,10 @@ namespace Particles.ParticleSimulation { AverageSpeed = 0.99f * AverageSpeed + 0.01f * speed; } + + public void ResetAverageSpeed() + { + AverageSpeed = 1f; + } } } \ No newline at end of file diff --git a/ParticleSimulation/ParticleSimulation.cs b/ParticleSimulation/ParticleSimulation.cs index 5fce004..68436ec 100644 --- a/ParticleSimulation/ParticleSimulation.cs +++ b/ParticleSimulation/ParticleSimulation.cs @@ -1,27 +1,39 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +#define MULTITHREADED + +using System.Collections.Generic; +using System.Linq; using Godot; +#if MULTITHREADED + using System.Threading.Tasks; +#endif namespace Particles.ParticleSimulation { public class ParticleSimulation { - + // size of simulation space public Vector2 SpaceSize; + // dictionary of particles with particle Id being the key private readonly Dictionary _particles = new Dictionary(); private readonly List _particleTypes = new List(); - private readonly List _tasks = new List(); - + + // task list if multi-threaded + #if MULTITHREADED + private readonly List _tasks = new List(); + #endif + + // updated on every simulation update public List LastParticlesAdded { get; private set; } = new List(); - // ReSharper disable once CollectionNeverUpdated.Global public List LastParticlesRemoved { get; private set; } = new List(); + // counts up for each particle added private int _idCount; private const int MaxParticles = 1100; - private const int MaxParticleTypes = 12; + private const int MaxParticleTypes = 10; + private const float HealthDelta = 0.005f; private const float NegativeHealthMultiplier = 2f; private const float PositiveHealthMultiplier = 4f; @@ -32,35 +44,41 @@ namespace Particles.ParticleSimulation { for (var i = 0; i < MaxParticleTypes; i++) CreateRandomParticleType(); - //for (var i = 0; i < MaxParticles; i++) - // CreateRandomParticle(); } public void Update() { LastParticlesRemoved.Clear(); LastParticlesAdded.Clear(); - _tasks.Clear(); + + // update all particles + #if MULTITHREADED + _tasks.Clear(); + foreach (var id in _particles.Keys) + _tasks.Add(Task.Factory.StartNew(UpdateParticle, id)); + Task.WaitAll(_tasks.ToArray()); + #else foreach (var id in _particles.Keys) - _tasks.Add(Task.Factory.StartNew(UpdateParticle, id)); - Task.WaitAll(_tasks.ToArray()); - var deletedParticle = false; - foreach (var p in _particles) + UpdateParticle(id); + #endif + + // used to ensure only one particle is moved per update + var movedParticle = false; + + foreach (var particle in _particles.Select(p => p.Value)) { - var particle = p.Value; - particle.ScreenWrappedLast = false; - if (deletedParticle == false && particle.Health == 0f) + particle.WasTeleportedLast = false; + if (movedParticle == false && particle.Health == 0f) { - if (GD.Randf() < 0.2f) + if (GD.Randf() < 0.1f) { particle.Position = GetRandomParticlePosition(); - particle.ScreenWrappedLast = true; - //LastParticlesRemoved.Add(p.Key); - deletedParticle = true; + particle.WasTeleportedLast = true; + particle.Health = 1f; + movedParticle = true; continue; } } - var position = particle.Position; particle.Velocity = particle.Velocity.Clamped(5f); position += particle.Velocity; @@ -68,52 +86,48 @@ namespace Particles.ParticleSimulation if (position.x > SpaceSize.x) { position.x -= SpaceSize.x; - particle.ScreenWrappedLast = true; + particle.WasTeleportedLast = true; } else if (position.x < 0) { position.x += SpaceSize.x; - particle.ScreenWrappedLast = true; + particle.WasTeleportedLast = true; } if (position.y > SpaceSize.y) { position.y -= SpaceSize.y; - particle.ScreenWrappedLast = true; + particle.WasTeleportedLast = true; } else if (position.y < 0) { position.y += SpaceSize.y; - particle.ScreenWrappedLast = true; + particle.WasTeleportedLast = true; } - - particle.AddAverageSpeedValue(particle.Position.DistanceTo(position)); /* - if (particle.AverageSpeed < 0.3f) + particle.AddAverageSpeedValue(particle.Velocity.Length()); + + if (particle.AverageSpeed < 0.5f) particle.Health -= HealthDelta * NegativeHealthMultiplier; else - particle.Health += HealthDelta; - */ - if (deletedParticle == false && particle.Health == 0f) + particle.Health += HealthDelta * PositiveHealthMultiplier; + + if (movedParticle == false && particle.Health == 0f) { - if (GD.Randf() < 0.2f) + if (GD.Randf() < 0.1f) { - //LastParticlesRemoved.Add(p.Key); particle.Position = GetRandomParticlePosition(); - particle.ScreenWrappedLast = true; - deletedParticle = true; + particle.ResetAverageSpeed(); + particle.WasTeleportedLast = true; + particle.Health = 1f; + movedParticle = true; continue; } } - + */ particle.Position = position; } - - foreach (var id in LastParticlesRemoved) - { - _particles.Remove(id); - } - + // ReSharper disable once InvertIf if (_particles.Count < MaxParticles) { @@ -132,6 +146,13 @@ namespace Particles.ParticleSimulation } } + // ReSharper disable once UnusedMember.Local + private void RemoveParticle(int id) + { + _particles.Remove(id); + LastParticlesRemoved.Add(id); + } + private void CreateRandomParticleType() { var type = new ParticleType() @@ -192,7 +213,7 @@ namespace Particles.ParticleSimulation return _particles[id]; } - private Task UpdateParticle(object i) + private void UpdateParticle(object i) { var id = (int)i; var particle1 = _particles[id]; @@ -206,15 +227,17 @@ namespace Particles.ParticleSimulation var distanceSquared = particle1.Position.DistanceSquaredTo(position); if (distanceSquared > (55f * 55f)) continue; - var direction = particle1.Position.DirectionTo(position); if (distanceSquared < (35f * 35f)) closeCount++; // collision force float distance; + Vector2 direction; + if (distanceSquared < (ParticleCollisionRadius * ParticleCollisionRadius)) { + direction = particle1.Position.DirectionTo(position); distance = particle1.Position.DistanceTo(position); var collisionForce = 1f / (0.35f + Mathf.Pow(Mathf.E, -1.15f * (distance - 12f))) - 1f / 0.35f; particle1.Velocity += direction * collisionForce; @@ -225,6 +248,7 @@ namespace Particles.ParticleSimulation if (props.Force != 0f && distanceSquared >= props.MinRadius * props.MinRadius && distanceSquared <= props.MaxRadius * props.MaxRadius) { + direction = particle1.Position.DirectionTo(position); distance = particle1.Position.DistanceTo(position); var mid = (props.MinRadius + props.MaxRadius) / 2f; float particleForce; @@ -256,12 +280,10 @@ namespace Particles.ParticleSimulation } } - if (closeCount > 50) + if (closeCount > 70) particle1.Health -= HealthDelta * NegativeHealthMultiplier; else particle1.Health += HealthDelta * PositiveHealthMultiplier; - - return Task.CompletedTask; } } } diff --git a/Particles.csproj b/Particles.csproj index 647872a..db88a8d 100644 --- a/Particles.csproj +++ b/Particles.csproj @@ -1,7 +1,5 @@ - - net472 - Debug;ExportDebug;ExportRelease;Release - AnyCPU - + + net472 + \ No newline at end of file diff --git a/Particles.sln b/Particles.sln index f96954d..388aa17 100644 --- a/Particles.sln +++ b/Particles.sln @@ -1,22 +1,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Particles", "Particles.csproj", "{E15A1F42-C497-4EDE-8944-84CB055B33CB}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Particles", "Particles.csproj", "{87802628-5B53-4FFD-8ACF-E7227985842E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution 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 = 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 + {87802628-5B53-4FFD-8ACF-E7227985842E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87802628-5B53-4FFD-8ACF-E7227985842E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87802628-5B53-4FFD-8ACF-E7227985842E}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {87802628-5B53-4FFD-8ACF-E7227985842E}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {87802628-5B53-4FFD-8ACF-E7227985842E}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {87802628-5B53-4FFD-8ACF-E7227985842E}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU EndGlobalSection EndGlobal diff --git a/Particles.sln.DotSettings.user b/Particles.sln.DotSettings.user deleted file mode 100644 index f591ba1..0000000 --- a/Particles.sln.DotSettings.user +++ /dev/null @@ -1,2 +0,0 @@ - - INFO \ No newline at end of file diff --git a/default_env.tres b/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..2fdf457 Binary files /dev/null and b/icon.ico differ diff --git a/project.godot b/project.godot index b83d025..b32a24f 100644 --- a/project.godot +++ b/project.godot @@ -13,26 +13,30 @@ config_version=4 config/name="Particles" run/main_scene="res://Main.tscn" config/icon="res://icon.png" +config/windows_native_icon="res://icon.ico" [display] -window/size/width=1920 -window/size/height=1080 window/size/resizable=false window/size/borderless=true +window/size/fullscreen=true [input] -quit={ -"deadzone": 0.5, -"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":16777217,"unicode":0,"echo":false,"script":null) - ] -} reset={ "deadzone": 0.5, -"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":82,"unicode":0,"echo":false,"script":null) +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":82,"physical_scancode":0,"unicode":0,"echo":false,"script":null) ] } +quit={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} + +[mono] + +profiler/enabled=true [physics] @@ -45,3 +49,4 @@ quality/driver/driver_name="GLES2" vram_compression/import_etc=true vram_compression/import_etc2=false environment/default_clear_color=Color( 0, 0, 0, 1 ) +environment/default_environment="res://default_env.tres" diff --git a/textures/particle.png b/textures/particle.png index 73190c3..47b4f19 100644 Binary files a/textures/particle.png and b/textures/particle.png differ diff --git a/textures/particle_noborder.png b/textures/particle_noborder.png new file mode 100644 index 0000000..55b789f Binary files /dev/null and b/textures/particle_noborder.png differ diff --git a/textures/particle_noborder.png.import b/textures/particle_noborder.png.import new file mode 100644 index 0000000..5cca5c8 --- /dev/null +++ b/textures/particle_noborder.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/particle_noborder.png-2c964d106064b04cd1632e2feec7d5d8.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://textures/particle_noborder.png" +dest_files=[ "res://.import/particle_noborder.png-2c964d106064b04cd1632e2feec7d5d8.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +process/normal_map_invert_y=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/textures/particle_old.png b/textures/particle_old.png new file mode 100644 index 0000000..73190c3 Binary files /dev/null and b/textures/particle_old.png differ diff --git a/textures/particle_old.png.import b/textures/particle_old.png.import new file mode 100644 index 0000000..6be5f19 --- /dev/null +++ b/textures/particle_old.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/particle_old.png-70319fb8cbbe1fe7999a1d4ae575ed1d.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://textures/particle_old.png" +dest_files=[ "res://.import/particle_old.png-70319fb8cbbe1fe7999a1d4ae575ed1d.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +process/normal_map_invert_y=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0