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 .
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 screens 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) 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 wed 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 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 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 would
become: for
p = 0 to Partnum-1 #write the particles to the buffer and update
them 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! Particle[p,0]=
size_x/2 and Particle[spwani,0]=
size_x/2 and Particle[p,1]=
size_y/2 and Particle[spawni,1]=
size_y/2 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: becomes Loop: 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.
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
Particle[p,4] = 0
next
p
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
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
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
Like this:
become
Particle[p,0]=
mousex and Particle[spawni,0]= mousex
become
Particle[p,1]=
mousey and Particle[spawni,1]= mousey
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
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
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.