GithubHelp home page GithubHelp logo

hunar4321 / particle-life Goto Github PK

View Code? Open in Web Editor NEW
2.9K 29.0 287.0 52.94 MB

A simple program to simulate artificial life using attraction/reuplsion forces between many particles

License: MIT License

Makefile 0.01% C++ 35.64% HTML 61.46% Python 2.89%
cpp educational javascript simulation cellular-automata game-of-life generative-art particle-life particles

particle-life's Introduction

GitHub repo size GitHub

Particle Life Simulation

A simple program to simulate primitive Artificial Life using simple rules of attraction or repulsion among atom-like particles, producing complex self-organzing life-like patterns. Excluding the GUI elements, the code is less than a page. The video tutorial and walkthrough are available below.

Learn More Here (YouTube video tutorial):

https://youtu.be/0Kx4Y9TVMGg

Online Demo (JavaScript version):

Click here for a live demo (JavaScript):

Interface (C++ version)

Example Results

Some Interesting Patterns to Reproduce:

You do not need to be exact with the parameters to reproduce these patterns. The best way to get interesting patterns is to first try random parameter explorations, once you find an interesting pattern, try fine-tuning it gradually. To avoid becoming stuck at a local maximum, you can make some occasional big parameter jumps. In this way interesting and different patterns shall keep poping up.

To use:

Download this repo. unzip the file then go to /particle_life/bin/ folder and click on particle_life.exe

Code:

The source code is available in C++, JavaScript, and Python. Watch this YouTube video for a walkthrough tutorial: https://youtu.be/0Kx4Y9TVMGg

If you would like to contribute to the C++ program, the core algorithm is the first 100 lines of code at: "/particle_life/src/ofApp.cpp". The rest are GUI components and rendering controls which are provided by the openFrameworks library an opensource and easy-to-use image rendering library.

To start, download this repository then download openFrameworks library from here: https://openframeworks.cc/. Use openFramework's projectGenerator and import /particle_life/ folder to the project.

Alternatively, generate a new openFramework project and add ofxGui. Once the project files are generated replace the /src/ folder with the one provided here.

You can now compile the C++ code on your machine.

Other Ports:

The JavaScript code is as simple as this:

Also, look at the particle_life.html file for a more optimized version - thanks to those who have contributed.

<canvas id="life" width="500" height="500"></canvas>
<script>
  //Hunar Ahmad @ brainxyz
  m = document.getElementById("life").getContext("2d");
  draw = (x, y, c, s) => {
    m.fillStyle = c;
    m.fillRect(x, y, s, s);
  };
  atoms = [];
  atom = (x, y, c) => {
    return { x: x, y: y, vx: 0, vy: 0, color: c };
  };
  random = () => {
    return Math.random() * 400 + 50;
  };
  create = (number, color) => {
    group = [];
    for (let i = 0; i < number; i++) {
      group.push(atom(random(), random(), color));
      atoms.push(group[i]);
    }
    return group;
  };
  rule = (atoms1, atoms2, g) => {
    for (let i = 0; i < atoms1.length; i++) {
      fx = 0;
      fy = 0;
      for (let j = 0; j < atoms2.length; j++) {
        a = atoms1[i];
        b = atoms2[j];
        dx = a.x - b.x;
        dy = a.y - b.y;
        d = Math.sqrt(dx * dx + dy * dy);
        if (d > 0 && d < 80) {
          F = (g * 1) / d;
          fx += F * dx;
          fy += F * dy;
        }
      }
      a.vx = (a.vx + fx) * 0.5;
      a.vy = (a.vy + fy) * 0.5;
      a.x += a.vx;
      a.y += a.vy;
      if (a.x <= 0 || a.x >= 500) { a.vx *= -1; }
      if (a.y <= 0 || a.y >= 500) { a.vy *= -1; }
    }
  };
  yellow = create(200, "yellow");
  red = create(200, "red");
  green = create(200, "green");
  update = () => {
    rule(green, green, -0.32);
    rule(green, red, -0.17);
    rule(green, yellow, 0.34);
    rule(red, red, -0.1);
    rule(red, green, -0.34);
    rule(yellow, yellow, 0.15);
    rule(yellow, green, -0.2);
    m.clearRect(0, 0, 500, 500);
    draw(0, 0, "black", 500);
    for (i = 0; i < atoms.length; i++) {
      draw(atoms[i].x, atoms[i].y, atoms[i].color, 5);
    }
    requestAnimationFrame(update);
  };
  update();
</script>

Related topics: Particle Life Simulation, Primordial Soup - Evolution, Conway's game of life, Cellular automata, Self organzing patterns,

This project was inspired by: Jeffery Ventrella's Clusters http://www.ventrella.com/Clusters/. I do not have access to Ventrella's code but I guess the main difference of this project from the other particle life projects is that I did not implement collision detection and this made simulating thousands of particles possible in real-time. Also, I added GUI controls to change the parameters in real-time allowing easy fine-tuning and exploration, hence, I was able to find some never-seen-before patterns emerge form some extremely simple models of relations. The code here is probably an order of magnitude simpler than any other Artificial Life codes out there because I started this code solely as an educational material for non-programmers and general audience to prove the point that complexity can arise from simplicity.

Todos:

  1. Adding the ability to save and load parameters (so that people can easily share the interesting models they find)
  2. Ability to add more particle types (currently it is fixed to four particle types)
  3. Currently, the biggest bottleneck is the nested for-loops (which calculate the pairwise distance among all particles) making the computational complexity quadratic. It would be amazing if we could find a way around.
  4. Alternative to point 3, computing the pairwise distances are embarrassingly parallel so it can be computed on GPU.
  5. Adding the ability to resize the screen and improving boundary-checking as many fast moving particles can escape the screen bounds.
  6. Adding a more intuitive UI so that it gives the ability for a finer control over the parameters.
  7. Adding a randomize button or, even better, having a simple meta rule to mutate the initial rule continously and recursively. This way the patterns will never get stuck on a local maximum and will keep changing!
  8. A better way to fine-tune is to use an evolutionary algorithm to select and optimize the parameters but one needs to write a fitness function for that. I currently don't know what fitness function corresponds to in the realm of this program. In our world the fitness function is competition and survival of the fittest. However, here we fine-tune and select the parameters that produce interesting patterns for us but the word "interesting" is easier to say than to define!

particle-life's People

Contributors

anasqiblawi avatar arduano avatar brandleesee avatar dangarfield avatar dlatikaynen avatar edb02 avatar esrrhs avatar hunar4321 avatar jillytaboga avatar ker2x avatar romeov avatar rpominov avatar skal65535 avatar thekiromen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

particle-life's Issues

[Feature request] Animated parameter change over time.

In the "Control panel" on the left, it would be cool if the parameters could slowly animate towards random values, so it's possible to see how everything in the system changes when the parameters change over time.

For example:
You click on the "Animate" button (Better name?), and it randomly generates a "Target value" for each slider.
Then the slider value SLOWLY (like 0.001 speed or random speed, or something) moves towards that target value.
When the slider reaches the target area, it waits for some time, then a new target value is chosen & it restarts moving towards THAT new target value instead.

Different sliders will have different distances to their target value,

  • you could either allow the system to generate new target values for that slider whenever that slider reaches its target (after some delay?),
    OR, you can "sync" up the system in (at least) 2 ways:
  • Wait for ALL sliders to reach their targets before generating new targets for all sliders (with a delay, just to see if the system stabilizes).
  • Or, just after generating the targets, it measures the distance needed to travel, and adjusts the travel speed for each slider to be exactly the speed needed for every slider to reach its target at the same time (eg. 20 seconds from now, all sliders will reach the target).

Preferably there would be an option to toggle between all these 3 "sync" options, but that's maybe wishing too much?

Superfluid

Hi! Viscosity quantifies the internal frictional force between adjacent layers of fluid that are in relative motion. So, Viscosity is a characteristic of the substance. So in this application it should be a parameter of the substance, i.e. the colour. So each colour should have its own viscosity. If a user wants to define red particles as superfluid they can do so by setting the red viscosity to zero.
I'd like to do that, but I have no idea how to define the velocity calculation on each color. I have defined the viscosity for each color, but I don't know how I could insert it into the p1.vx and p2.vy velocity calculation (how to make p1.vx and p2.vy refer to each color separately). Any ideas? Can you help me?
ofxFloatSlider viscoSliderR;
ofxFloatSlider viscoSliderG;
ofxFloatSlider viscoSliderW;
ofxFloatSlider viscoSliderB;
ofxFloatSlider viscoSliderO;
ofxFloatSlider viscoSliderK;
ofxFloatSlider viscoSliderC;
ofxFloatSlider viscoSliderD;
and
float viscosityR = 0.3F;
float viscosityG = 0.4F;
float viscosityW = 0.1F;
float viscosityB = 0.6F;
float viscosityO = 0.5F;
float viscosityK = 0.7F;
float viscosityC = 0.8F;
float viscosityD = 0.0F;
and
viscosityR = viscoSliderR;
viscosityG = viscoSliderG;
viscosityW = viscoSliderW;
viscosityB = viscoSliderB;
viscosityO = viscoSliderO;
viscosityK = viscoSliderK;
viscosityC = viscoSliderC;
viscosityD = viscoSliderD;

webgl version

This project inspired me to create a general but high performant sandbox for 2d particle simulations! The simulation is done on the GPU so it's a lot faster.

https://capsadmin.github.io/webgl-particles/

Click the hamburger icon in the top left corner and select particle life from the dropdown menu.

It's not 100% the same, but I included the ability to use javascript code in the CONFIG block that generates the rules similar to how you do it.

Source code can be found here:
https://github.com/CapsAdmin/webgl-particles

START/RESET button

I have to hold down the START/RESET button for the simulation in the exe file to work.

Simultaneous attractive and repulsive forces in the same particle

Hi! I want a particle of a certain colour to attract and repel a particle of another colour simultaneously, on different beams and with different intensities. In the original application, a particle either attracts or repels another particle, depending on the sign of the intensity of the interaction force.
I started by defining interactions as follows:
void interaction(std::vector* Group1, const std::vector* Group2, float G, float Gradius, float A, float Aradius, float viscosity, float Gprobability, float Aprobability);
"G" would be "powerSlider_a_" for pull force, "Gradius" would be "vSlider_a_" for pull force, "A" would be "powerSlider_r_" for repelling force, "Aradius" would be "vSlider_r_" for repelling force.
Defining interactions would be of the form:
if (numberSliderR > 0) interaction(&green, &red, powerSlider_a_GR, vSlider_a_GR, powerSlider_r_GR, vSlider_r_GR, viscosityG, probability_a_GR, probability_r_GR);

However, I have no idea how the calculation of forces and velocities should be defined.

I try to defined:

void ofApp::interaction(std::vector* Group1, const std::vector* Group2, const float G, const float Gradius, const float A, const float Aradius, const float viscosity, const float Gprobability, const float Aprobability)
{
const float g = G / -100; //Gravity coefficient
const float a = A / 100; //Anti-Gravity coefficient
const auto group1size = Group1->size();
const auto group2size = Group2->size();
const bool radius_toggle = radiusToogle;

But I don't know if it's good.

Then I modified this:
//Calculate the force in given bounds.
if ((r < (Gradius * Gradius - Aradius * Aradius) || radius_toggle) && r != 0.0F)
{
fx += (dx / std::sqrt(dx * dx + dy * dy));
fy += (dy / std::sqrt(dx * dx + dy * dy));
}
}

				//Calculate new velocity
				p1.vx = (p1.vx + (fx * (g + a))) * (1 - viscosity);
				p1.vy = (p1.vx + (fx * (g + a))) * (1 - viscosity) + worldGravity;

But I don't know if it's good.

It must be kept in mind that each type of force has its intensity and range of action and this must be clearly defined in the application.

There would be three situations:
when Gradius > Aradius;
when Gradius = Aradius;
when Gradius < Aradius.

For each of them I think the formulas for force and velocity should be defined.

For example: Blue can attract White with an intensity of 20, on a radius of 100, and at the same time repel White with an intensity of 30 but on a radius of 40. Then White can attract Blue with an intensity of 30 on a radius of 70, but simultaneously repel it with an intensity of 50 on a radius of 60. So White can be caught by the attraction of Blue but cannot approach it at less than 60, because it repels Blue with an intensity of 50 which is greater than the attraction of 30 it has to Blue at a radius of 70. At a distance of 60, there is a neutral force of zero intensity between Blue and White.

Any ideas? Any help?

Updating state is not really done "correctly"

As all the rules modify state, later rules are influenced by the effects of earlier rules... if this should be a "correct" simulation, all forces had to be calculated first, then applied to to the state. But the simulation is much more interesting with this bug ;)

release binary version doesn't seems to use openMP

Hi there, thank you for your awesome code.

the binary release I downloaded seems to have the same performance of my compiled code with openMP disabled. So I assume that openMP is indeed disabled.

(without openMP: 17fps. with openMP: 50fps)

I don't think there is any drawback in enabling it in the release binary

[Feature Request] A) Import/Export Weights/Params - and B) Time-dependent functions as a parameter

Hi, I have two requests,

1: Is it possible to import/export the weights as a CSV file or something similar so we can share parameters
2: Is it possible to include an input function for a time-dependent perturbation as a parameter. Maybe just a simple function which defaults to y(t) = x. but allows us to add in our own perturbations eg y(t) = sin(t) to perturb the potential as a function of time? Where t is whatever time unit is used for each 'step' of course.

migrating to openGL 4.3 and other various breaking change

For some time now, I'm considering the idea of a few options :

  • migrating to openGL 4.3 (any graphic card less than 10 years old should do the job) for visual effect shader and/or compute shader
  • rewriting the whole C++ code using a lighter/faster framework (that would allow C++20 too)
  • modify the existing cpp code
  • create another C++ directory inside the same project
  • create another project entirely

Any opinion on this @hunar4321 ?

A random idea

Hi there,

I'm testing some idea in the C++ code. it appears to works.

instead of testing all points relative to all other points when computing distance & interaction, just pick a random sample of point. It look visually similar and show similar behavior. This allow to add much more point to the simulation.

I just add a simple if(random) between the outer loop and inner loop. even with 10% chance, it still not too bad.

some pseudo code :

	for (auto i = 0; i < group1size; i++) {
                // ...
                if(ofRandom() < 0.5) (
		        for (auto j = 0; j < group2size; j++) {
                                // ...
                        }
                 }
         }

vcomp140.dll not found

when I run the program it always says "VCOMP140.dll was not found, try reinstalling the program" how do I fix this?

  • OS : WINDOWS 10

WTF

I dont know who the hell wrote this hellish unpythonic buggy abomination
THIS is the worst python program I have ever seen
Lucky for you I'll write a better implementation don't ever touch the holy python with your unpythonic hands ever again

[Feature request] Spawn or destroy pixels based off rules

I'm thinking something like the game of life where more pixels are spawned, or killed based off how many others are around them (and distance). Could be set to say reds die if there's too many blues close or something like that. Or maybe a red has a 50% chance of dying, and that % goes up the closer the nearest blue pixel is.

I haven't thought of the full implementation details, but it might be a good addition.

Particle Weights

I think having particle weights would be cool. Obviously, you made it without weights for simplicity, but I think it could be an interesting addition.

[Feature request] Distance-based force

The current simulation applies a force that is independent of distance. If the distance is 3 or 30 the force applied is the same.

suppose dx = 3 ; dy = 0
then r = sqrt(dx*dx + dy*dy) = 3
then fx  = dx / r = 1

or

suppose dx = 30 ; dy = 0
then r = sqrt(dx*dx + dy*dy) = 30
then fx  = dx / r = 1

There is a force that does not depend on distance, and then stops at some threshold; it is the Strong force, but it is mainly for the quarks inside an atom nucleus, not for artificial life. It would be interesting to use some force that depends on distance, because that would apply to real life forms. Maybe 1/d² (gravity, electromagnetism in a 3d world), 1/d (gravity or electromagnetism in a 2d world), van der waals force which can take into account the size of the particles, or Lennard-Jones which is the force between molecules. The interesting thing with Lennard-Jones is that at close distances it pushes molecules apart and at far distances it pulls them closer. This can create really interesting patterns. There is also a generalization of Lennard-Jones called Mie potential that might be useful for adapting Lennard-Jones to work in 2d.

Before you try these, I have to warn: I did try some of these and I think it will be a bit of work. It is easy to change the formula in the code. But I think all the other numbers in the code like the 0.5 and the -100 to +100 values and the G / -100 are all designed to work with the original distance-irrelevant force, and I think all of those would have to be somehow tweaked to handle distance.

Bounds checking is insufficient

The current JS code and the C++ code too are checking

    if(a.x <= 0 || a.x >= 500){ a.vx *=-1 }
    if(a.y <= 0 || a.y >= 500){ a.vy *=-1 }

This is not enough to keep the particles inside the box. You can test this by checking how many are inside the box:

    const inRange = (p) => 0 <= p.x && p.x < 500 && 0 <= p.y && p.y < 500
    console.log(yellow.filter(inRange).length, red.filter(inRange).length, green.filter(inRange).length)

The reason is that it reverses the velocity but doesn't apply right away, so the next update the velocity might change to be the wrong sign again. To ensure they stay inside the box you need to have them bounce on this frame and change the velocity, like this:

        WIDTH = 500
        HEIGHT = 500
        if (a.x < 0) { a.x = -a.x; a.vx *= -1; }
        if (a.x >= WIDTH) { a.x = 2*WIDTH - a.x; a.vx *= -1; }
        if (a.y < 0) { a.y = -a.y; a.vy *= -1; }
        if (a.y >= HEIGHT) { a.y = 2*HEIGHT - a.y; a.vy *= -1; }

With this code, the particles all stay inside the box. They might get be pushed out to the outer edges of the box but at least all of them stay on screen.

Out of the window

Hello,
When I run particle_life.exe, the simulation is out of the window. I only see a quarter of the simulation, as if the app thinks my screen is bigger than it really is. How I can fix it ?
Thank you in advance,
Jules

200+ FPS (on an simple laptop)

i'm still busy refactoring and i'm currently relying on intel's oneAPI and TBB for multithreading.
But you can check the code here https://github.com/ker2x/particle-life/tree/oneapi-dpl/particle_life/src , and perhaps backport the modification to a normal compiler and normal lib. (or i'll dot it myself some day i guess).

It's not fully optimized yet but, notable change :

  • Using Vertex Buffer (vbo) instead of bruteforcing call to circle.
	void Draw(colorGroup group)
	{
		ofSetColor(group.color);
		vbo.setVertexData(group.pos.data(), group.pos.size(), GL_DYNAMIC_DRAW);
		vbo.draw(GL_POINTS, 0, group.pos.size());

	}
  • Using SOA instead of AOS. better possible vectorization, and it was needed to efficiently use VBO anyway
struct colorGroup {
	std::vector<ofVec2f> pos;
	std::vector<float> vx;
	std::vector<float> vy;
	ofColor color;
};
  • it should also allow to add more color more easily (i hope)

  • major cleanup of interaction code

void ofApp::interaction(colorGroup& Group1, const colorGroup& Group2, 
		const float G, const float radius, bool boundsToggle) const
{
	
	assert(Group1.pos.size() % 64 == 0);
	assert(Group2.pos.size() % 64 == 0);
	
	const float g = G / -100;	// attraction coefficient

//		oneapi::tbb::parallel_for(
//			oneapi::tbb::blocked_range<size_t>(0, group1size), 
//			[&Group1, &Group2, group1size, group2size, radius, g, this]
//			(const oneapi::tbb::blocked_range<size_t>& r) {

	for (size_t i = 0; i < Group1.pos.size(); i++)
	{
		float fx = 0;	// force on x
		float fy = 0;	// force on y
		
		for (size_t j = 0; j < Group2.pos.size(); j++)
		{
			const float distance = Group1.pos[i].distance(Group2.pos[j]);
			if ((distance < radius)) {
				const float force = 1 / std::max(std::numeric_limits<float>::epsilon(), distance);	// avoid dividing by zero
				fx += ((Group1.pos[i].x - Group2.pos[j].x) * force);
				fy += ((Group1.pos[i].y - Group2.pos[j].y) * force);
			}
		}

		// Wall Repel
		if (wallRepel > 0.0F)
		{
			if (Group1.pos[i].x < wallRepel) Group1.vx[i] += (wallRepel - Group1.pos[i].x) * 0.1;
			if (Group1.pos[i].x > boundWidth - wallRepel) Group1.vx[i] += (boundWidth - wallRepel - Group1.pos[i].x) * 0.1;
			if (Group1.pos[i].y < wallRepel) Group1.vy[i] += (wallRepel - Group1.pos[i].y) * 0.1;
			if (Group1.pos[i].y > boundHeight - wallRepel) Group1.vy[i] += (boundHeight - wallRepel - Group1.pos[i].y) * 0.1;
		}

		// Viscosity & gravity
		Group1.vx[i] = (Group1.vx[i] + (fx * g)) * (1.0 - viscosity);
		Group1.vy[i] = (Group1.vy[i] + (fy * g)) * (1.0 - viscosity) + worldGravity;
//		Group1.vx[i] = std::fmaf(Group1.vx[i], (1.0F - viscosity), std::fmaf(fx, g, 0.0F));
//		Group1.vy[i] = std::fmaf(Group1.vy[i], (1.0F - viscosity), std::fmaf(fy, g, worldGravity));

		//Update position
		Group1.pos[i].x += Group1.vx[i];
		Group1.pos[i].y += Group1.vy[i];
	}

	if (boundsToggle) {
		for (auto& p : Group1.pos)
		{
			p.x = std::min(std::max(p.x, 0.0F), static_cast<float>(boundWidth));
			p.y = std::min(std::max(p.y, 0.0F), static_cast<float>(boundHeight));
		}
	}	
}

i still have some crap to clean :)

  • using oneapi::parallel_invoke for parallelization
	oneapi::tbb::parallel_invoke(
		[&] { interaction(red,   red,   powerSliderRR, vSliderRR, boundsToggle); },
		[&] { interaction(red,   green, powerSliderRR, vSliderRG, boundsToggle); },
		[&] { interaction(red,   blue,  powerSliderRR, vSliderRB, boundsToggle); },
		[&] { interaction(red,   white, powerSliderRR, vSliderRW, boundsToggle); },
		[&] { interaction(green, red,   powerSliderGR, vSliderGR, boundsToggle); },
		[&] { interaction(green, green, powerSliderGG, vSliderGG, boundsToggle); },
		[&] { interaction(green, blue,  powerSliderGB, vSliderGB, boundsToggle); },
		[&] { interaction(green, white, powerSliderGW, vSliderGW, boundsToggle); },
		[&] { interaction(blue,  red,   powerSliderBR, vSliderBR, boundsToggle); },
		[&] { interaction(blue,  green, powerSliderBG, vSliderBG, boundsToggle); },
		[&] { interaction(blue,  blue,  powerSliderBB, vSliderBB, boundsToggle); },
		[&] { interaction(blue,  white, powerSliderBW, vSliderBW, boundsToggle); },
		[&] { interaction(white, red,   powerSliderWR, vSliderWR, boundsToggle); },
		[&] { interaction(white, green, powerSliderWG, vSliderWG, boundsToggle); },
		[&] { interaction(white, blue,  powerSliderWB, vSliderWB, boundsToggle); },
		[&] { interaction(white, white, powerSliderWW, vSliderWW, boundsToggle); }
	);

this is me slowly learning to use oneAPI and SYCL in order to offload all the parallel code to the GPU in the future (in a new project)

The biggest performance improvement come from the use of SOA and VBO.

"Number" setting is not working properly

Definitely not 1

The number of atoms does not seem to add up. All the particles of that colour disappear when the number hits zero, but beyond that, there seems to be no change in the number of particles.

2022-08-29.21-58-35.mp4

In this example, I changed the number of blue particles, but it seems to be an issue with all the colours. It's nothing major, but hopefully, it will be fixed soon.

[P.S. This issue was found on the .exe version of the program. I have not used the JS version yet, so I do not know if this issue exists there]

[Edit: It seems like when I reset the simulation, the changes seem to apply, though it would be neat if there were a way to change the number of cells while the simulations are running, like the other parameters]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.