UglyMike's Web Lair



Particle Systems in Basic-256 - Part 1

The aim of this particle tutorial, is to build a simple particle fountain, controlled by mouse, from the ground up.

At every interim step, it is the intention to have a working program so that you can see what the results are of the piecemeal changes. You can either cut ‘n paste the code in this document to the Basic-256 code window (although indentation gets lost….) or use the hyperlinks to the example programs.

What is a particle system?

Here, when we talk about a particle system, we will mean a collection of independent objects, represented by a simple shape or dot. Full-fledged particle systems can be used to model many irregular types of natural phenomena, such as explosions, fire, smoke, sparks, waterfalls, clouds, fog, petals, grass, bubbles, and so on. In this text, we will keep things a LOT simpler….

In a basic particle system, each particle has its own series of properties related to its behavior (for example, position, velocity, age, etc.)

Basic-256 Boiler plate

For building up our particle system program, we will use the following scaffolding

Fastgraphics # write to video buffer.
size_x=
800
size_y=
800 # good practice to put every constant in a variable.
graphsize size_x,size_y
# feel free to change the” size of your canvas
color black
rect 0,0,size_x-1,size_y-1
# start out with a nice black screen.
refresh
# dump the video buffer to screen
#Voila! This gives you a nice canvas to draw on.

Running this program (particle01.kbs) gives us a nice black background. Not really exciting yet….

zwart scherm

Our Particle Fountain

First, we need to define the specifics of our particle system. The particle system itself is stored into a multidimensional array, a grid if you like. The first element of the array denotes the number of particles in our system. (the number of lines on the grid) Here we will limit us to 300. (Feel free to adapt to the power of your system) The second denotes the number of properties each particle has. (the number of columns on the grid)

For an initial, minimal particle system, we will need x-position, y-position, x-velocity, y-velocity. This makes 4 properties in all so we dimension the array as

Partnum=300
Dim Particle (Partnum,4)
#define a particle system with 300 particles, each with 4 properties

Now we need to initialize it…

We will set up the particle system to start from the centre, so x-position and y-position will be 400 (half of the 800x800 graphsize)

For the x- and y-velocities, we will take a very small number, here between -0.25 and 0.25.

for p = 0 to Partnum-1
  Particle[p,0] = size_x/2
  Particle[p,1]= size_y/2
  Particle[p,2]= (rand-0.5)/
2 # velocity from -0.25 to 0.25
  Particle[p,3]= (rand-0.5)/
2 # velocity from -0.25 to 0.25
next p

Next, we can dump our particles to the screen. This however would just show a dot in the middle of our black screen where all particles are bunched up together. As a particle system however is a dynamic system, so we will have to update it continually and reshow it.

We update our particle system by adding the velocities to the respective positions, we show the new screen and we clear it again. Finally we loop it with a simple goto-loop

Loop:
for p = 0 to Partnum-1
#write all the particles to the buffer and update them
  color white
  plot (Particle[p,0],Particle[p,1])
  Particle[p,0]= Particle[p,0]+Particle[p,2]
  Particle[p,1]= Particle[p,1]+Particle[p,3]
next p
Refresh
#all particles shown updated on the screen
color black
rect 0,0, size_x-1,size_y-1
#initialize the screen to black again
goto Loop
# do it all again

Now, if we run this program (particle02.kbs) , we already get a nice star-burst effect, but it quickly fizzles out as most points move beyond the screen’s borders. (Feel free to change the number of particles and their velocities. Experimenting is fun!)

There are 2 easy ways to prevent this fizzling out, to keep the particle system constrained within the borders of the graphics area.

  • We bounce the particles of the screen borders by reversing the velocity direction for
    the impacted screen border (either x-velocity or y-velocity). This however turn chaotic very quickly

  • We reinitialize the particle once it moves out of view. It will now have the centre of our Particle system again

First option

In the loop where we update the x- and y-positions, we check if the particle has moved off the screen. If so we reverse the direction:

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  color white
  plot (Particle[p,0],Particle[p,1])
  Particle[p,0]= Particle[p,0]+Particle[p,2]
  if Particle[p,0] < 0 or Particle [p,0]>size_x then Particle[p,2]= -Particle[p,2]
  Particle[p,1]= Particle[p,1]+Particle[p,3]
  if Particle[p,1] < 0 or Particle [p,1]>size_y then Particle[p,3]= -Particle[p,3]
next p

If we now run the program with this updated loop (particle03.kbs), we quickly find us in a chaotic situation with particles bouncing all over the place.

There are several ways to improve on this:

  • Add gravity (add a small, positive increase to the y-velocity) after every iteration)

  • Dampen the bounce if y-position > size_y (reverse y-velocity and multiply with eg 0.7-0.75)

In the example programs, we define the gravity parameter next to the array definition and set it to 0.001. This is because on my system, I get about 500 full iteration loops per second. As we add gravity at every loop, velocity increases very quickly things tend to develop fast…. If you start pumping up the number of particles and of particle operations, this number will probably have to go up….

grav=0.001 # gravity increase

For the dampening, to get some randomization we dampen with a factor between 0.7 and 0.9

So, with added gravity and a bounce dampening:

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  color white
  plot (Particle[p,0],Particle[p,1])
  Particle[p,0]= Particle[p,0]+Particle[p,2]
  if Particle[p,0] < 0 or Particle [p,0]>size_x then   Particle[p,2]=-Particle[p,2]*(0.7+rand/5)
  Particle[p,1]= Particle[p,1]+Particle[p,3]
  if Particle[p,1] < 0 then Particle[p,3]= - Particle[p,3]
# bounce off ceiling
  if Particle [p,1]>size_y then Particle[p,3]= - Particle[p,3]*(0.7+rand/5)
#bounce + dampen
  Particle[p,3]= Particle[p,3]+grav
# artificial gravity
next p

Running the program now (particle04.kbs), we see a finite animation where the particles appear, get dragged to the bottom, bounce a few times and come to rest just beneath the screen.

I think the program is already starting to show some promise here…..

Second option

In the second option to improve the simple starburst (disregarding the gravity addition), we have to prevent our particles from escaping
the screen. This is done by reinitialising the particle to the starting position (centre) if the particle has moved off the screen.

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  color white
  plot (Particle[p,0],Particle[p,1])
  Particle[p,0]= Particle[p,0]+Particle[p,2]
  Particle[p,1]= Particle[p,1]+Particle[p,3]
  if Particle[p,0]< 0 or Particle [p,0]>size_x or Particle[p,1]< 0 or Particle [p,1]> size_y then
    Particle[p,0]= size_x/2
    Particle[p,1]= size_y/2
  endif
next p

If we now run the program (particle05.kbs) with this updated loop, we see a never ending stream of particles being emitted from the centre.

Bringing both options together

Hmmmm. In option one the particles come to rest and remain there indefinitely while in option two, the particles are being respawned…. How can we combine this?

Well, we do this by giving the particles a random lifetime (random between certain limits) and decreasing the lifetime at every loop. When the lifetime hits zero, we reinitialize the particle.

This lifetime will be a 5th property of the particle, so we have to change the size and the initialization of the array:

Dim Particle (300,5) #define a 300 particle system with 5 properties

for p = 0 to Partnum-1
  Particle[p,0] = size_x/2
  Particle[p,1]= size_y/2
# as we have gravity, we can moe this higher (eg size_y/6)
  Particle[p,2]= (rand-0.5)/5
# velocity from -0.1 to 0.1
  Particle[p,3]= (rand-0.5)/5
# velocity from -0.1 to 0.1
  Particle[p,4]= rand *1020
# play with this setting until you get a nice bouncy effect
next p

Now that we have a life property, we also need to decrease it so we check for viability and if dead (ie life < 0), we reinitialize the particle:

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  color white
  plot (Particle[p,0],Particle[p,1])
  Particle[p,0]= Particle[p,0]+Particle[p,2]
  if Particle[p,0]<0 or Particle [p,0]>size_x then Particle[p,2]= -Particle[p,2]* (0.7+rand/5)
  Particle[p,1]= Particle[p,1]+Particle[p,3]
  if Particle[p,1] < 0 then Particle[p,3]= - Particle[p,3] # bounce off ceiling
  if Particle [p,1]>size_y then Particle[p,3]= - Particle[p,3]* (0.5+rand/5)#bounce + dampen
  Particle[p,3]= Particle[p,3]+grav # artificial gravity
  Particle[p,4]= Particle[p,4]-1
  if Particle[p,4]<0 then
    Particle[p,0] = size_x/2
    Particle[p,1]= size_y/2
    Particle[p,2]= (rand-0.5)/5 # velocity from -0.1 to 0.1
    Particle[p,3]= (rand-0.5)/5 # velocity from -0.1 to 0.1
    Particle[p,4]= rand *1020# play with this setting until you get a nice bouncy effect
  endif
next p

Running this program (particle06.kbs) already shows us a static particle fountain.

Some issues remain however and can be improved:

  • Color management:

currently, all particles are simply white. Based on the life parameter however, we can easily make the particles change color as they age.

  • Initial burst

The initial creation and initialization of the particles causes an unwanted effect at the start of the run as the particle system ‘explodes’ from the centre and respawning only occurs after some time, spoiling the effect a bit

Color Management

There are of course many ways to map the age to a color. We will simply translate the age value to RGB colors…. Replace the following code:

“color white”

with the code here:

  age=((Particle[p,4]/4) mod 255)
  if age > 85 then
     colblue = 255
     colgreen = 255
     colred = 255
     color rgb(colred,colgreen,colblue)
  else
    if age >170 then
       colblue = Particle[p,4] mod 255
       colgreen = 255
       colred = 255
       color rgb(colred,colgreen,colblue)
    else
      colblue = 0
      colgreen = Particle[p,4] mod 255
      colred = 255
      color rgb(colred,colgreen,colblue)
    endif
  endif

Initial Burst

The initial burst (the square full of particles that appears and bounces before the fountain really kicks in) is because we start the program by initializing all the particles in the system.

This of course also causes all particles to be alive at the chosen position at step 0

To prevent this, we need to spawn particles all the time on the fly (and not just when one particle dies since then we’d have to wait for the initial particles to start dying first..…)

For this, we replace the initialization of the Particle system so that all particles are DEAD (ie Particle [p,4]=0)

for p = 0 to Partnum - 1
  Particle[p,4] = 0
next p

Then, during the main loop, the first thing we do is to continuously create a number of particles (here, 3 particles at every iteration. The number of particles here will depend on the total number and on the power of your PC…)

for k = 1 to 3
  spawni=int(rand * Partnum)
# select a random particle
  if Particle[spawni,4] = 0 then
# if the particle is dead, create one
    Particle[spawni,0] = size_x/2
    Particle[spawni,1]= size_y/2
    Particle[spawni,2]= (rand-0.5)/5
# velocity from -0.1 to 0.1
    Particle[spawni,3]= (rand-0.5)/5
# velocity from -0.1 to 0.1
    Particle[spawni,4]= rand *1020
# play with this setting
  end if
next k

In the next loop (where we update the particles) we first check if the particle in question is dead and if so skip the rest of the loop.

So ,

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  age=((Particle[p,4]/4) mod 255)
  if age > 85 then
     colblue = 255
     colgreen = 255
     colred = 255
     color rgb(colred,colgreen,colblue)
  else
  …...
  endif
next p

would become:

for p = 0 to Partnum-1 #write the particles to the buffer and update them
  if Particle[p,4]>0 then
  age=((Particle[p,4]/4) mod 255)
  if age > 85 then
     colblue = 255
     colgreen = 255
     colred = 255
     color rgb(colred,colgreen,colblue)
  else
  …...
  endif
  endif
 endif
next p

Voila! That is all there is to it! Mind you, if your PC is very fast and if your particle's life duration is set too high, the piecemeal generation of new partivcles will be so fast that it will look as if the initial square is still there...

Fix this by giving you particles a shorter lifetime when creating them piecemeal but a longer one when respawning dead particles.

With these last changes, if we now run our program (particle07.kbs) we get from frame one, a nice particle fountain.

However, we did say we were going to control it with our mouse….

Well, this is quite simple! All we need to do is to initialize the x- and y-locations to the mouse positions!
Like this:

Particle[p,0]= size_x/2 and Particle[spwani,0]= size_x/2
become
Particle[p,0]= mousex and Particle[spawni,0]= mousex

and

Particle[p,1]= size_y/2 and Particle[spawni,1]= size_y/2
become
Particle[p,1]= mousey and Particle[spawni,1]= mousey

Running the program now would immediately start the fountain at location 0,0 (seeing that the mouse coordinates have not yet been initialized).

We can fix this by simply checking if mousex is greater than 0 right at the start of the Loop contruct:

Loop:
for k = 1 to 3
  spawni=int(rand * Partnum)
# select a random particle
  if Particle[spawni,4] = 0 then
# if the particle is dead, create one
    Particle[spawni,0]= mousex
    Particle[spawni,1]= mousey
    Particle[spawni,2]= (rand-0.5)/5
# velocity from -0.1 to 0.1
    Particle[spawni,3]= (rand-0.5)/5
# velocity from -0.1 to 0.1
    Particle[spawni,4]= rand *1020
# play with this setting
  end if
next k

becomes

Loop:
if mousex > 0 then
  for k = 1 to 3
    spawni=int(rand * Partnum) # select a random particle
    if Particle[spawni,4] = 0 then # if the particle is dead, create one
      Particle[spawni,0]= mousex
      Particle[spawni,1]= mousey
      Particle[spawni,2]= (rand-0.5)/5 # velocity from -0.1 to 0.1
      Particle[spawni,3]= (rand-0.5)/5 # velocity from -0.1 to 0.1
      Particle[spawni,4]= rand *1020 # play with this setting
    end if
  next k
endif

Voila! We now have Basic-256 program (particle08.kbs) that gives us a nice particle fountain controlled by the mouse!!

If you PC is fast enough, you can swap points for circles This can be seen in the final Basic-256 program (particle08c.kbs) where we just add a line between line 57 and 58

You can now start to experiment with increasing the screen dimension or the number of particles, changing the gravity parameter or the life duration, changing the speed at which particles are ejected (currently, we are using (rand-0.5)/0.5 for both x- & y-directions), etc. etc.

That was it for this first particle tutorial! There are still lots of things we could add in this sytem we just created here, like:

  • dead particles that are persitant and stick around so we get a gradual buildup of red detritus at the bottom.

  • smallish lines/blocks in the view port that act as particle deflectors (particles would bounce of these)

All the best,

UglyMike.




Very Old Feedbacks:

08/09/2013: Love having you involved in the BASIC256 community. Jim

04/08/2013: This is one awesome blog.Really looking forward to read more. Will read on...

24/07/2013: Great stuff, man. Keep up the good work!

24/07/2013: Thank you ever so for you article post.Thanks Again. Great.

20/04/2013: Thanks for sharing, this is a fantastic article. Keep writing.

25/03/2013: Excellent work!

01/02/2013: Hey, thanks for the article post.Thanks Again. Great

25/11/2012: On the particle Tutorial: Thanks for sharing, this is a fantastic article post. Really Great.

26/08/2012: Thanks for a Basic, so simple yet so hard. lrcvs

28/02/2012: Thanks for the nice programming tutorials. I appreciate your efforts!!

16/02/2012: Awesome, I found it Basic256 by accident while reading through stackoverflow.com recommendations for new programmers. You are doing a great job demonstrating advanced programming concepts in KB256! Thanks & all the best!


10/0/2024
Resurrected the site and updated most of the programs to be compatible with 2.0.0.11.

11/09/2013
Added Aqua inspired BTK2 routines to the site.

23/08/2013
Lots of older programs were horribly broken. Everything now runs ok again under 0.9.9.64.

22/08/2013
Added "Percolation" to the "BTK2 Demo Programs" section.

06/03/2013
Added "Basic Paint" to the "BTK2 Demo Programs" section.

23/11/2012
Added "Critters" to the "BTK2 Demo Programs" sectionto and a Flood-It game to "Other Programs".

27/10/2012
Updated BTK to BTK2 (CALL/SUBROUTINE) and added a BTK2 overall demo program.