Compare commits

...

10 Commits

17 changed files with 565 additions and 190 deletions

61
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Created by https://www.toptal.com/developers/gitignore/api/godot,jetbrains,csharp,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=godot,jetbrains,csharp,visualstudiocode
# Created by https://www.toptal.com/developers/gitignore/api/jetbrains+all,godot,csharp
# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains+all,godot,csharp
### Csharp ###
## Ignore Visual Studio temporary files, build results, and
@ -413,7 +413,7 @@ export_presets.cfg
.mono/
data_*/
### JetBrains ###
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
@ -492,49 +492,20 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
### JetBrains+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
.idea/*
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
.idea/sonarlint
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
### VisualStudioCode ###
!.vscode/*.code-snippets
# Local History for Visual Studio Code
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
# End of https://www.toptal.com/developers/gitignore/api/godot,jetbrains,csharp,visualstudiocode
# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,godot,csharp

View File

@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/.idea.Particles.iml
/contentModel.xml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -1 +0,0 @@
Particles

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

30
Main.cs
View File

@ -1,24 +1,44 @@
using Godot;
using System;
using Particles.ParticleSimulation;
public class Main : Node
{
public void StartSimulation(int seed, int nParticles)
public int Seed;
public float Zoom;
private int _nParticles;
public override void _Ready()
{
OS.MinWindowSize = new Vector2(1024, 600);
}
public void StartSimulation(int nParticles)
{
_nParticles = nParticles;
var particleSimulationPackedScene = GD.Load<PackedScene>("res://ParticleSimulation/ParticleSimulationScene.tscn");
var particleSimulationScene = particleSimulationPackedScene.Instance<ParticleSimulationScene>();
particleSimulationScene.Name = "Simulation";
particleSimulationScene.Name = Seed.ToString();
AddChild(particleSimulationScene);
particleSimulationScene.Initialize(seed, nParticles);
particleSimulationScene.Initialize(Seed, nParticles, Zoom);
GetNode<Control>("MainMenu").Hide();
//OS.WindowResizable = false;
}
public void ExitToMenu()
{
GetNode("Simulation").QueueFree();
GetNode(Seed.ToString()).QueueFree();
GetNode<Control>("MainMenu").Show();
GetNode<MainMenu>("MainMenu").RefreshSeedText();
}
public void RestartSimulation()
{
GetNode<ParticleSimulationScene>(Seed.ToString()).Hide();
GetNode(Seed.ToString()).QueueFree();
Seed = Mathf.Abs((int)GD.Randi());
StartSimulation(_nParticles);
}
}

View File

@ -1,5 +1,5 @@
using System.Globalization;
using Godot;
using System;
public class MainMenu : Control
{
@ -10,6 +10,14 @@ public class MainMenu : Control
private Button _toggleFullScreenButton;
private TextEdit _seedText;
private TextEdit _particleCountText;
private Button _randomizeButton;
private Label _zoomValue;
private HSlider _zoomSlider;
private Label _invalidLabel;
private string _prevSeedText;
private string _prevParticleCountText;
public override void _Ready()
{
@ -17,25 +25,83 @@ public class MainMenu : Control
_main = GetTree().Root.GetNode<Main>("Main");
_simulateButton = GetNode("MenuButtons").GetNode<Button>("SimulateButton");
_toggleFullScreenButton = GetNode("MenuButtons").GetNode<Button>("ToggleFullscreenButton");
_seedText = GetNode("MenuButtons").GetNode<TextEdit>("SeedText");
_particleCountText = GetNode("MenuButtons").GetNode<TextEdit>("ParticleCountText");
_seedText = GetNode("MenuButtons").GetNode("Inputs").GetNode("Seed").GetNode<TextEdit>("SeedText");
_particleCountText = GetNode("MenuButtons").GetNode("Inputs").GetNode("ParticleCount").GetNode<TextEdit>("ParticleCountText");
_randomizeButton = GetNode("MenuButtons").GetNode("Inputs").GetNode("Seed").GetNode<Button>("RandomizeButton");
_zoomValue = GetNode("MenuButtons").GetNode("Inputs").GetNode("Zoom").GetNode<Label>("ZoomValue");
_zoomSlider = GetNode("MenuButtons").GetNode("Inputs").GetNode("Zoom").GetNode<HSlider>("ZoomSlider");
_invalidLabel = GetNode<Label>("InvalidLabel");
// Connect signals
_simulateButton.Connect("pressed", this, nameof(_OnSimulatePressed));
_toggleFullScreenButton.Connect("pressed", this, nameof(_OnToggleFullscreenPressed));
_randomizeButton.Connect("pressed", this, nameof(_OnRandomizePressed));
_zoomSlider.Connect("value_changed", this, nameof(_OnZoomSliderChange));
_seedText.Connect("text_changed", this, nameof(_OnSeedTextChange));
_particleCountText.Connect("text_changed", this, nameof(_OnParticleCountTextChange));
// Random seed
GD.Randomize();
var randomSeed = (int)GD.Randi();
_seedText.Text = randomSeed.ToString();
var randomSeed = Mathf.Abs((int)GD.Randi());
_main.Seed = randomSeed;
RefreshSeedText();
// Set default previous values
_prevSeedText = _seedText.Text;
_prevParticleCountText = _particleCountText.Text;
}
public void _OnParticleCountTextChange()
{
var particleCountCheck = int.TryParse(_particleCountText.Text, out var nParticles);
if (!particleCountCheck && !_particleCountText.Text.Empty())
{
ShowInvalid();
_particleCountText.Text = _prevParticleCountText;
}
else if (!_particleCountText.Text.Empty())
{
_prevParticleCountText = _particleCountText.Text;
}
}
public void _OnSeedTextChange()
{
var seedCheck = int.TryParse(_seedText.Text, out var seed);
if (!seedCheck && !_seedText.Text.Empty())
{
ShowInvalid();
_seedText.Text = _prevSeedText;
}
else if (!_seedText.Text.Empty())
{
_prevSeedText = _seedText.Text;
}
}
public void _OnZoomSliderChange(float value)
{
_zoomValue.Text = value.ToString(CultureInfo.InvariantCulture);
_main.Zoom = value;
}
public void RefreshSeedText()
{
_seedText.Text = _main.Seed.ToString();
_prevSeedText = _seedText.Text;
}
public void _OnSimulatePressed()
{
// Start simulation with seed and number of particles
var nParticles = _particleCountText.Text.ToInt();
var seed = _seedText.Text.ToInt();
_main.StartSimulation(seed, nParticles);
if (_seedText.Text.Empty() || _particleCountText.Text.Empty())
{
ShowInvalid();
return;
}
_main.Zoom = (float)_zoomSlider.Value;
_main.Seed = int.Parse(_seedText.Text);
_main.StartSimulation(int.Parse(_particleCountText.Text));
}
public void _OnToggleFullscreenPressed()
@ -43,6 +109,13 @@ public class MainMenu : Control
OS.WindowFullscreen = !OS.WindowFullscreen;
}
public void _OnRandomizePressed()
{
var randomSeed = Mathf.Abs((int)GD.Randi());
_main.Seed = randomSeed;
RefreshSeedText();
}
public override void _Input(InputEvent @event)
{
// Quit only if menu is visible
@ -51,4 +124,19 @@ public class MainMenu : Control
GetTree().Quit();
}
}
private async void ShowInvalid()
{
GetNode<Tween>("InvalidTween").ResetAll();
GetNode<Timer>("InvalidTimer").Stop();
GetNode<Timer>("InvalidTimer").WaitTime = 3.0f;
_invalidLabel.Modulate = new Color(1, 1, 1, 1);
var invalidTimer = GetNode<Timer>("InvalidTimer");
invalidTimer.Start();
await ToSignal(invalidTimer, "timeout");
var invalidTween = GetNode<Tween>("InvalidTween");
invalidTween.InterpolateProperty(_invalidLabel, "modulate:a", 1, 0, 1);
invalidTween.Start();
await ToSignal(invalidTween, "tween_all_completed");
}
}

View File

@ -14,85 +14,134 @@ anchor_right = 1.0
anchor_bottom = 1.0
theme = ExtResource( 1 )
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MenuButtons" type="VBoxContainer" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_top = 0.582
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -150.0
margin_top = -132.0
margin_right = 150.0
margin_bottom = 337.685
anchor_bottom = 0.582
margin_left = -304.0
margin_top = -172.5
margin_right = 304.0
margin_bottom = 172.5
custom_constants/separation = 12
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ParticleCountLabel" type="Label" parent="MenuButtons"]
margin_right = 300.0
margin_bottom = 27.0
text = "Number of Particles"
align = 1
[node name="Inputs" type="HBoxContainer" parent="MenuButtons"]
margin_right = 608.0
margin_bottom = 138.0
alignment = 1
[node name="ParticleCountText" type="TextEdit" parent="MenuButtons"]
margin_top = 39.0
margin_right = 300.0
margin_bottom = 103.769
rect_min_size = Vector2( 0, 64.769 )
text = "1000"
[node name="Seed" type="VBoxContainer" parent="MenuButtons/Inputs"]
margin_right = 200.0
margin_bottom = 138.0
rect_min_size = Vector2( 200, 0 )
[node name="SeedLabel" type="Label" parent="MenuButtons"]
margin_top = 115.0
margin_right = 300.0
margin_bottom = 142.0
text = "Optional Seed Number"
[node name="SeedLabel" type="Label" parent="MenuButtons/Inputs/Seed"]
margin_right = 200.0
margin_bottom = 21.0
text = "Seed Number"
align = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SeedText" type="TextEdit" parent="MenuButtons"]
margin_top = 154.0
margin_right = 300.0
margin_bottom = 218.769
[node name="SeedText" type="TextEdit" parent="MenuButtons/Inputs/Seed"]
margin_top = 25.0
margin_right = 200.0
margin_bottom = 89.769
rect_min_size = Vector2( 0, 64.769 )
text = "12345"
[node name="RandomizeButton" type="Button" parent="MenuButtons/Inputs/Seed"]
margin_top = 93.0
margin_right = 200.0
margin_bottom = 138.251
text = "Randomize!"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ParticleCount" type="VBoxContainer" parent="MenuButtons/Inputs"]
margin_left = 204.0
margin_right = 404.0
margin_bottom = 138.0
rect_min_size = Vector2( 200, 0 )
[node name="ParticleCountLabel" type="Label" parent="MenuButtons/Inputs/ParticleCount"]
margin_right = 200.0
margin_bottom = 21.0
text = "Particle Count"
align = 1
[node name="ParticleCountText" type="TextEdit" parent="MenuButtons/Inputs/ParticleCount"]
margin_top = 25.0
margin_right = 200.0
margin_bottom = 90.0
rect_min_size = Vector2( 0, 65 )
text = "1000"
[node name="Zoom" type="VBoxContainer" parent="MenuButtons/Inputs"]
margin_left = 408.0
margin_right = 608.0
margin_bottom = 138.0
rect_min_size = Vector2( 200, 0 )
[node name="ZoomLabel" type="Label" parent="MenuButtons/Inputs/Zoom"]
margin_right = 200.0
margin_bottom = 21.0
text = "World Size"
align = 1
[node name="ZoomValue" type="Label" parent="MenuButtons/Inputs/Zoom"]
margin_top = 25.0
margin_right = 200.0
margin_bottom = 46.0
text = "1.4"
align = 1
[node name="ZoomSlider" type="HSlider" parent="MenuButtons/Inputs/Zoom"]
margin_top = 50.0
margin_right = 200.0
margin_bottom = 92.0
min_value = 0.5
max_value = 5.0
step = 0.1
value = 1.4
[node name="SimulateButton" type="Button" parent="MenuButtons"]
margin_top = 230.0
margin_right = 300.0
margin_bottom = 281.251
margin_top = 150.0
margin_right = 608.0
margin_bottom = 195.251
text = "Simulate!"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Warning" type="Label" parent="MenuButtons"]
margin_top = 293.0
margin_right = 300.0
margin_bottom = 338.0
margin_top = 207.0
margin_right = 608.0
margin_bottom = 252.0
custom_fonts/font = SubResource( 1 )
text = "Simulation cannot be resized
once simulation starts!"
align = 1
[node name="HBoxContainer" type="HBoxContainer" parent="MenuButtons"]
margin_top = 350.0
margin_right = 300.0
margin_bottom = 350.0
margin_top = 264.0
margin_right = 608.0
margin_bottom = 264.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ToggleFullscreenButton" type="Button" parent="MenuButtons"]
margin_top = 362.0
margin_right = 300.0
margin_bottom = 413.251
text = "Toggle Fullscreen"
margin_top = 276.0
margin_right = 608.0
margin_bottom = 321.251
text = "Toggle Fullscreen!"
[node name="Logo" type="TextureRect" parent="."]
show_behind_parent = true
@ -108,7 +157,41 @@ rect_scale = Vector2( 0.35, 0.35 )
mouse_filter = 2
texture = ExtResource( 2 )
__meta__ = {
"_edit_lock_": true,
"_edit_use_anchors_": false
}
[connection signal="pressed" from="MenuButtons/ToggleFullscreenButton" to="." method="_on_ToggleFullscreen_pressed"]
[node name="Controls" type="Label" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -183.0
margin_top = -81.0
margin_right = -10.0
margin_bottom = -12.0
custom_fonts/font = SubResource( 1 )
text = "Controls
R to Restart
Esc to Exit"
align = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="InvalidLabel" type="Label" parent="."]
modulate = Color( 1, 1, 1, 0 )
margin_left = 15.0
margin_top = 16.0
margin_right = 226.0
margin_bottom = 43.0
text = "Invalid Inputs!"
uppercase = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="InvalidTween" type="Tween" parent="."]
[node name="InvalidTimer" type="Timer" parent="."]
one_shot = true

View File

@ -3,7 +3,6 @@
[ext_resource path="res://ParticleSimulation/ParticleNode.cs" type="Script" id=1]
[ext_resource path="res://textures/particle_noborder.png" type="Texture" id=2]
[node name="ParticleNode" type="Node2D"]
script = ExtResource( 1 )

View File

@ -7,17 +7,39 @@ public class ParticleSimulationScene : Node2D
{
private Node2D _particleNodes;
private Camera2D _camera;
private Tween _cameraTween;
private Vector2 _cameraZoomTarget;
private Vector2 _cameraPosTarget;
private float _maxZoom;
private Vector2 _spaceSize;
private const float CameraZoomSpeed = 0.5f;
private ParticleSimulation _particleSimulation;
public float PhysicsInterpolationFraction;
public void Initialize(int seed, int nParticles)
private bool _wasInteractPrevEnabled;
private Vector2 _prevMousePos;
public void Initialize(int seed, int nParticles, float zoom)
{
_wasInteractPrevEnabled = false;
_prevMousePos = new Vector2();
_maxZoom = zoom;
_camera = GetNode<Camera2D>("Camera2D");
_cameraTween = GetNode<Tween>("CameraTween");
_particleNodes = GetNode<Node2D>("ParticleNodes");
_cameraZoomTarget = _camera.Zoom;
_cameraPosTarget = _camera.Position;
GD.Seed((ulong)seed);
GD.Print("Last Seed: " + seed);
var viewSize = GetViewportRect().Size;
var zoom = GetNode<Camera2D>("Camera2D").Zoom;
var spaceSize = new Vector2(viewSize.x * zoom.x, viewSize.y * zoom.y);
_camera.Zoom = new Vector2(zoom, zoom);
var spaceSize = viewSize * zoom;
_spaceSize = spaceSize;
_particleSimulation = new ParticleSimulation
{
SpaceSize = spaceSize
@ -28,14 +50,128 @@ public class ParticleSimulationScene : Node2D
public override void _Process(float delta)
{
// Game state inputs
if (Input.IsActionJustPressed("quit"))
GetParent<Main>().ExitToMenu();
if (Input.IsActionJustPressed("reset")) GetTree().ReloadCurrentScene();
if (Input.IsActionJustPressed("reset"))
GetParent<Main>().RestartSimulation();
if (Input.IsActionPressed("enable_interaction"))
{
GetNode<Sprite>("InteractionCircleSprite").Show();
GetNode<Sprite>("InteractionCircleSprite").Position = GetGlobalMousePosition();
}
else
{
GetNode<Sprite>("InteractionCircleSprite").Hide();
}
var shouldTweenStop = false;
if (Input.IsActionJustReleased("zoom_in"))
{
shouldTweenStop = true;
// Zoom
_cameraZoomTarget -= new Vector2(0.1f, 0.1f);
// Movement
var mousePos = GetGlobalMousePosition();
var posDelta = _cameraPosTarget - mousePos;
posDelta = posDelta.Clamped(500f);
_cameraPosTarget -= posDelta * 0.2f;
}
if (Input.IsActionJustReleased("zoom_out"))
{
shouldTweenStop = true;
// Zoom
_cameraZoomTarget += new Vector2(0.1f, 0.1f);
// Movement
var mousePos = GetGlobalMousePosition();
var posDelta = _cameraPosTarget - mousePos;
posDelta = posDelta.Clamped(500f);
_cameraPosTarget += posDelta * 0.2f;
}
var cameraDir = new Vector2();
if (Input.IsActionPressed("up"))
cameraDir += new Vector2(0, -1);
if (Input.IsActionPressed("down"))
cameraDir += new Vector2(0, 1);
if (Input.IsActionPressed("left"))
cameraDir += new Vector2(-1, 0);
if (Input.IsActionPressed("right"))
cameraDir += new Vector2(1, 0);
if (cameraDir.LengthSquared() != 0)
{
shouldTweenStop = true;
cameraDir = cameraDir.Normalized();
_cameraPosTarget += cameraDir * 1000f * delta;
}
if (Input.IsActionPressed("key_zoom_in"))
{
shouldTweenStop = true;
_cameraZoomTarget -= new Vector2(0.01f, 0.01f) * (delta * 60f);
}
if (Input.IsActionPressed("key_zoom_out"))
{
shouldTweenStop = true;
_cameraZoomTarget += new Vector2(0.01f, 0.01f) * (delta * 60f);
}
if (shouldTweenStop)
{
_cameraTween.StopAll();
_cameraZoomTarget.x = Mathf.Clamp(_cameraZoomTarget.x, 0.01f, _maxZoom);
_cameraZoomTarget.y = Mathf.Clamp(_cameraZoomTarget.y, 0.01f, _maxZoom);
_cameraPosTarget.x = Mathf.Clamp(_cameraPosTarget.x,
0f - (_maxZoom - _cameraZoomTarget.x) * (_spaceSize.x / (Mathf.Sqrt2 * 2)),
0f + (_maxZoom - _cameraZoomTarget.x) * (_spaceSize.x / (Mathf.Sqrt2 * 2)));
_cameraPosTarget.y = Mathf.Clamp(_cameraPosTarget.y,
0f - (_maxZoom - _cameraZoomTarget.y) * (_spaceSize.y / (Mathf.Sqrt2 * 2)),
0f + (_maxZoom - _cameraZoomTarget.y) * (_spaceSize.y / (Mathf.Sqrt2 * 2)));
_cameraTween.InterpolateProperty(_camera, "zoom", _camera.Zoom, _cameraZoomTarget, CameraZoomSpeed,
Tween.TransitionType.Quint, Tween.EaseType.Out);
_cameraTween.InterpolateProperty(_camera, "position", _camera.Position, _cameraPosTarget, CameraZoomSpeed,
Tween.TransitionType.Quint, Tween.EaseType.Out);
_cameraTween.Start();
}
PhysicsInterpolationFraction = Engine.GetPhysicsInterpolationFraction();
}
public override void _PhysicsProcess(float delta)
{
if (Input.IsActionPressed("enable_interaction"))
{
if (_wasInteractPrevEnabled)
{
var mouseVel = GetGlobalMousePosition() - _prevMousePos;
mouseVel /= 5f;
_prevMousePos = GetGlobalMousePosition();
_particleSimulation.SetInteractionCircle(GetGlobalMousePosition() + (_spaceSize / 2.0f), 70f, mouseVel);
}
else
{
_wasInteractPrevEnabled = true;
_prevMousePos = GetGlobalMousePosition();
_particleSimulation.SetInteractionCircle(GetGlobalMousePosition() + (_spaceSize / 2.0f), 70f, Vector2.Zero);
}
}
else
{
_wasInteractPrevEnabled = false;
}
_particleSimulation.Update();
foreach (var id in _particleSimulation.LastParticlesRemoved)
{
@ -50,7 +186,7 @@ public class ParticleSimulationScene : Node2D
{
var simulationParticle = _particleSimulation.GetParticle(particleNode.SimulationId);
particleNode.LastSimulationPosition = particleNode.Position;
particleNode.CurrentSimulationPosition = simulationParticle.Position;
particleNode.CurrentSimulationPosition = simulationParticle.Position - (_spaceSize / 2.0f);
particleNode.SetColor(simulationParticle.Type.Hue, simulationParticle.Health,
Mathf.Clamp(simulationParticle.AverageSpeed / 1.5f, 1f, 1f));
particleNode.WasTeleportedLast = simulationParticle.WasTeleportedLast;

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=3 format=2]
[ext_resource path="res://ParticleSimulation/ParticleSimulationScene.cs" type="Script" id=1]
[ext_resource path="res://textures/interaction_circle.png" type="Texture" id=2]
[node name="ParticleSimulationScene" type="Node2D"]
script = ExtResource( 1 )
@ -9,6 +9,13 @@ script = ExtResource( 1 )
[node name="ParticleNodes" type="Node2D" parent="."]
[node name="Camera2D" type="Camera2D" parent="."]
anchor_mode = 0
current = true
zoom = Vector2( 1.35, 1.35 )
smoothing_speed = 100.0
[node name="CameraTween" type="Tween" parent="."]
[node name="InteractionCircleSprite" type="Sprite" parent="."]
modulate = Color( 1, 1, 1, 0.313726 )
scale = Vector2( 0.75, 0.75 )
texture = ExtResource( 2 )

View File

@ -20,9 +20,9 @@ namespace Particles.ParticleSimulation
private readonly List<ParticleType> _particleTypes = new List<ParticleType>();
// task list if multi-threaded
#if MULTITHREADED
private readonly List<Task> _tasks = new List<Task>();
#endif
#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>();
@ -53,15 +53,15 @@ namespace Particles.ParticleSimulation
LastParticlesAdded.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
#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)
UpdateParticle(id);
#endif
#endif
// used to ensure only one particle is moved per update
var movedParticle = false;
@ -80,10 +80,11 @@ namespace Particles.ParticleSimulation
continue;
}
}
var position = particle.Position;
particle.Velocity = particle.Velocity.Clamped(5f);
position += particle.Velocity;
particle.Velocity *= 0.855f; // friction
particle.Velocity *= 0.855f; // friction
if (position.x > SpaceSize.x)
{
position.x -= SpaceSize.x;
@ -105,6 +106,7 @@ namespace Particles.ParticleSimulation
position.y += SpaceSize.y;
particle.WasTeleportedLast = true;
}
/*
particle.AddAverageSpeedValue(particle.Velocity.Length());
@ -165,7 +167,7 @@ namespace Particles.ParticleSimulation
foreach (var type2 in _particleTypes)
type1.AddRelationship(type2,
new ParticleRelationshipProps(ParticleCollisionRadius, (float) GD.RandRange(25, 55),
(float)GD.RandRange(-0.675, 0.7)));
(float) GD.RandRange(-0.675, 0.7)));
}
private void CreateRandomParticle()
@ -216,7 +218,7 @@ namespace Particles.ParticleSimulation
private void UpdateParticle(object i)
{
var id = (int)i;
var id = (int) i;
var particle1 = _particles[id];
var closeCount = 0;
foreach (var p2 in _particles)
@ -257,22 +259,26 @@ namespace Particles.ParticleSimulation
{
if (distance <= mid)
{
particleForce = 1f / ((1f / props.Force) + Mathf.Pow(Mathf.E, -4 * (distance - props.MinRadius - 1f)));
particleForce = 1f / ((1f / props.Force) +
Mathf.Pow(Mathf.E, -4 * (distance - props.MinRadius - 1f)));
}
else
{
particleForce = 1f / ((1f / props.Force) + Mathf.Pow(Mathf.E, 4 * (distance - props.MaxRadius + 1f)));
particleForce = 1f / ((1f / props.Force) +
Mathf.Pow(Mathf.E, 4 * (distance - props.MaxRadius + 1f)));
}
}
else
{
if (distance <= mid)
{
particleForce = -1f / ((-1f / props.Force) + Mathf.Pow(Mathf.E, -4 * (distance - props.MinRadius - 1f)));
particleForce = -1f / ((-1f / props.Force) +
Mathf.Pow(Mathf.E, -4 * (distance - props.MinRadius - 1f)));
}
else
{
particleForce = -1f / ((-1f / props.Force) + Mathf.Pow(Mathf.E, 4 * (distance - props.MaxRadius + 1f)));
particleForce = -1f / ((-1f / props.Force) +
Mathf.Pow(Mathf.E, 4 * (distance - props.MaxRadius + 1f)));
}
}
@ -286,5 +292,16 @@ namespace Particles.ParticleSimulation
else
particle1.Health += HealthDelta * PositiveHealthMultiplier;
}
public void SetInteractionCircle(Vector2 position, float radius, Vector2 velocity)
{
foreach (var p in _particles.Select(i => i.Value))
{
if (position.DistanceTo(p.Position) <= radius)
{
p.Velocity += velocity;
}
}
}
}
}

View File

@ -29,9 +29,59 @@ quit={
"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)
]
}
up={
"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":87,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
down={
"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":16777234,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
left={
"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":65,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
right={
"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":16777233,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
zoom_in={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
]
}
zoom_out={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
]
}
key_zoom_in={
"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":69,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
key_zoom_out={
"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":81,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
enable_interaction={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
]
}
[mono]
project/assembly_name="Particles"
profiler/enabled=true
[physics]

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/interaction_circle.png-10aab2660a95f68c88825c76c59d9be8.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://textures/interaction_circle.png"
dest_files=[ "res://.import/interaction_circle.png-10aab2660a95f68c88825c76c59d9be8.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

View File

@ -1,7 +1,11 @@
[gd_resource type="Theme" load_steps=34 format=2]
[ext_resource path="res://ui/UIpack_vector.svg" type="Texture" id=1]
[ext_resource path="res://ui/ColorTube-Regular.ttf" type="DynamicFontData" id=2]
[ext_resource path="res://ui/kenvector_future.ttf" type="DynamicFontData" id=2]
[sub_resource type="DynamicFont" id=33]
size = 18
font_data = ExtResource( 2 )
[sub_resource type="StyleBoxTexture" id=1]
texture = ExtResource( 1 )
@ -173,9 +177,6 @@ region = Rect2( 1007, 450, 39, 31 )
texture = ExtResource( 1 )
region_rect = Rect2( 1051, 317, 4, 100 )
[sub_resource type="DynamicFont" id=33]
font_data = ExtResource( 2 )
[resource]
default_font = SubResource( 33 )
Button/colors/font_color = Color( 0, 0, 0, 1 )
@ -184,7 +185,7 @@ Button/colors/font_color_focus = Color( 0, 0, 0, 1 )
Button/colors/font_color_hover = Color( 0.34902, 0.34902, 0.34902, 1 )
Button/colors/font_color_pressed = Color( 0.388235, 0.388235, 0.388235, 1 )
Button/constants/hseparation = 2
Button/fonts/font = null
Button/fonts/font = SubResource( 33 )
Button/styles/disabled = SubResource( 1 )
Button/styles/focus = SubResource( 2 )
Button/styles/hover = SubResource( 3 )
@ -197,7 +198,7 @@ CheckBox/colors/font_color_hover_pressed = Color( 0.34902, 0.34902, 0.34902, 1 )
CheckBox/colors/font_color_pressed = Color( 0.388235, 0.388235, 0.388235, 1 )
CheckBox/constants/check_vadjust = 0
CheckBox/constants/hseparation = 4
CheckBox/fonts/font = null
CheckBox/fonts/font = SubResource( 33 )
CheckBox/icons/checked = SubResource( 6 )
CheckBox/icons/radio_checked = SubResource( 7 )
CheckBox/icons/radio_unchecked = SubResource( 8 )
@ -215,7 +216,7 @@ CheckButton/colors/font_color_hover_pressed = Color( 0.388235, 0.388235, 0.38823
CheckButton/colors/font_color_pressed = Color( 0.388235, 0.388235, 0.388235, 1 )
CheckButton/constants/check_vadjust = 0
CheckButton/constants/hseparation = 4
CheckButton/fonts/font = null
CheckButton/fonts/font = SubResource( 33 )
CheckButton/icons/off = SubResource( 31 )
CheckButton/icons/off_disabled = SubResource( 31 )
CheckButton/icons/on = SubResource( 32 )
@ -241,7 +242,7 @@ LineEdit/colors/font_color_selected = Color( 0.894118, 0.894118, 0.894118, 1 )
LineEdit/colors/font_color_uneditable = Color( 0.88, 0.88, 0.88, 0.5 )
LineEdit/colors/selection_color = Color( 0.34902, 0.34902, 0.34902, 1 )
LineEdit/constants/minimum_spaces = 12
LineEdit/fonts/font = null
LineEdit/fonts/font = SubResource( 33 )
LineEdit/icons/clear = null
LineEdit/styles/focus = SubResource( 16 )
LineEdit/styles/normal = SubResource( 17 )
@ -252,7 +253,7 @@ OptionButton/colors/font_color_hover = Color( 0.34902, 0.34902, 0.34902, 1 )
OptionButton/colors/font_color_pressed = Color( 0, 0, 0, 1 )
OptionButton/constants/arrow_margin = 2
OptionButton/constants/hseparation = 2
OptionButton/fonts/font = null
OptionButton/fonts/font = SubResource( 33 )
OptionButton/icons/arrow = SubResource( 18 )
OptionButton/styles/disabled = null
OptionButton/styles/focus = null
@ -266,7 +267,7 @@ PopupMenu/colors/font_color_disabled = Color( 0.4, 0.4, 0.4, 0.8 )
PopupMenu/colors/font_color_hover = Color( 0.388235, 0.388235, 0.388235, 1 )
PopupMenu/constants/hseparation = 4
PopupMenu/constants/vseparation = 32
PopupMenu/fonts/font = null
PopupMenu/fonts/font = SubResource( 33 )
PopupMenu/icons/checked = SubResource( 20 )
PopupMenu/icons/radio_checked = SubResource( 26 )
PopupMenu/icons/radio_unchecked = SubResource( 27 )
@ -283,7 +284,7 @@ TextEdit/colors/bookmark_color = Color( 0.08, 0.49, 0.98, 1 )
TextEdit/colors/brace_mismatch_color = Color( 1, 0.2, 0.2, 1 )
TextEdit/colors/breakpoint_color = Color( 0.8, 0.8, 0.4, 0.2 )
TextEdit/colors/caret_background_color = Color( 0, 0, 0, 1 )
TextEdit/colors/caret_color = Color( 0.88, 0.88, 0.88, 1 )
TextEdit/colors/caret_color = Color( 0, 0, 0, 1 )
TextEdit/colors/code_folding_color = Color( 0.8, 0.8, 0.8, 0.8 )
TextEdit/colors/completion_background_color = Color( 0.17, 0.16, 0.2, 1 )
TextEdit/colors/completion_existing_color = Color( 0.87, 0.87, 0.87, 0.13 )
@ -308,7 +309,7 @@ TextEdit/constants/completion_lines = 7
TextEdit/constants/completion_max_width = 50
TextEdit/constants/completion_scroll_width = 3
TextEdit/constants/line_spacing = 4
TextEdit/fonts/font = null
TextEdit/fonts/font = SubResource( 33 )
TextEdit/icons/fold = null
TextEdit/icons/folded = null
TextEdit/icons/space = null