This commit is contained in:
orosmatthew 2021-12-29 15:08:26 -05:00
parent 430e05e921
commit 7e968df4a6
17 changed files with 188 additions and 83 deletions

11
Main.cs
View File

@ -12,14 +12,17 @@ public class Main : Node2D
public override void _Ready()
{
_particleNodes = GetNode<Node2D>("ParticlesNodes");
_particleNodes = GetNode<Node2D>("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>("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;
}
}

View File

@ -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 )

View File

@ -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<Node2D>().GetParent<Main>().PhysicsInterpolationFraction)
: CurrentSimulationPosition;

View File

@ -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 )

View File

@ -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;
}
}
}

View File

@ -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<int, Particle> _particles = new Dictionary<int, Particle>();
private readonly List<ParticleType> _particleTypes = new List<ParticleType>();
private readonly List<Task> _tasks = new List<Task>();
// task list if multi-threaded
#if MULTITHREADED
private readonly List<Task> _tasks = new List<Task>();
#endif
// updated on every simulation update
public List<int> LastParticlesAdded { get; private set; } = new List<int>();
// ReSharper disable once CollectionNeverUpdated.Global
public List<int> LastParticlesRemoved { get; private set; } = new List<int>();
// 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;
}
}
}

View File

@ -1,7 +1,5 @@
<Project Sdk="Godot.NET.Sdk/3.3.0">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<Configurations>Debug;ExportDebug;ExportRelease;Release</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -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

View File

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">INFO</s:String></wpf:ResourceDictionary>

7
default_env.tres Normal file
View File

@ -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 )

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -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

BIN
textures/particle_old.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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