Another atypical tutorial for this site. (Is any of them "typical"??)
This gives you the sourcecode for something "simple"... but complex! But doesn't do a lot of explaining. The sourcecode, though I say it myself, is elegant and "powerful". Also flexible.
Furthermore, while what it gives you is "pretty", it isn't particularly useful, as it stands. It is more of a starting point.
With it, you could create a simulation of bees swarming, ships moving in the English Channel, etc, etc. (I wrote it as a starting point for re-creating a program I wrote for the Acorn Archimedes in the 1980s. That program simulated a population of mobile protists, each with a simple genetic character, and they evolved as the simulation ran.)
Or just have fun with pretty animations. Or expand the ability of your brain to work with arrays in your programming.
The following static image, enhanced with Serif's PhotoPlus, really doesn't do the program justice. What you can't see here is that the "amoebas" are, in a somewhat un-lifelike symmetry, streaming across the page on parallel paths.
I've posted the .exe on its own for you to download so that you can see the animation in action. Download LTN199.exe, Streaming Amoebas
And, as promised, you can also download the Lazarus sourcecode.
At the heart of this is what happens when its timer times out... which in "Prestissimo" mode it nominally does once a millisecond. (I'm not sure how the system copes with the fact that the timer times out more quickly than the OnTimer event handler executes... maybe the timer is disabled while the code is executing? I haven't done any of that explicitly, however, and the code runs for hours without crashing. Pretty cool endorsement of the way Lazarus is put together, don't you think?)
Anyway... When the timer times out, "all" that happens is...
ShowAmoebas; MoveAmoebas; inc(wCycles); if wCycles>60000 then wCycles:=0;//Could add "cycles of cycles" counter, to //track overflows.... but want to keep this fast! laCycles.caption:=inttostr(wCycles);
... of which only the first two lines are at all "clever".
(Digression... I think it was working with arrays of smart LEDs (WS2812s) driven by an Arduino recently that "inspired" me to take this elegant approach.)
Everything in the program revolves around a few arrays.
MoveAmoebas makes changes to the contents of the arrays... and does a few other things. (More on this in a moment.)
ShowAmoebas simply reads what is in the arrays (and a crucial pointer), and from that paints pixels on the screen.
Let's look "behind the scenes" a little; let's look into the mechanism behind the illusion of the "movement" of the amoebas. (Or birds or ships or whatever you want to simulate!) The following shows one amoeba, first as it was at a moment in time, and then as it was in the next moment....
"The amoeba" is the one dark blue cell. It is "moving" to the right. "Behind it" (to its left), there is a "fading trail" showing where it has been. Depending on your monitor, you will see a pale blue pixel just to the left of the amoeba, and a paler blue pixel to the left of that. The pixel above the "Note A" pointer is drawn in white. (More on that anon!)
(In the .exe supplied with this tutorial, the "trails" are longer. You can change the length of the trail by changing the value in kMaxPixelsIndex.)
That amoeba is represented inside the program by one row of four elements in the array WhereX plus one row of four elements in the array WhereY.
To keep things simple, we'll talk only of the values in, and manipulation of WhereX. Of course, similar things are happening to and with WhereY, although as long as all the amoebas stream across the page horizontally, the code for the values in WhereY doesn't have to be as complex as that for WhereX... although the relevant code for ShowAmoebas was fully developed as fast as the code for WhereX. In MoveAmoebas, full development was restricted to changing what was in WhereX, and the code for WhereY, while inserted alongside, and parallel to the WhereX code, is not as fully developed.
Obviously, during ShowAmoebas, a lot of pixels are plotted on the screen. And, at first, you might thing you need some sort of "erase" stage, to get rid of the old "ink".
Well... yes and no. Look at the example of one amoeba just above: If, in "time=x+1", you draw the three "new" blue squares, you will have overwritten two of the old squares. They don't need to be erased. The only old blue square that needs erasing is the old "end of trail" (the one with x coordinate=12).
While it may seem that we've drawn just three pixels, in fact we draw four... three in different shades of blue, and one in the background color. That "oldest bit of trail" is drawn in the background color not because you are going to "see" it, but to blot out oldest pixel of the old trail.
You could of course say that you'd hold the position of the amoeba in element 0 of the array, the most recent trail pixel's coordinate in element 1, and so on.
And if you did, drawing the new screen with ShowAmoebas would be really simple.
But you'd pay a time penalty. All of the coordinates of all of the pixels would have to be moved "across" the WhereX and WhereY arrays between each generation!
Instead, the arrays are used like this...
Initially (If we have a trail as long as the one in the illustration), we start with the following in the row for this amoeba...
11 12 13 14
However, for the next generation (time=x+1), only the value in the first element of the row was changed. The whole row became....
15 12 13 14
The secret to this is the variable "bColPointerHead". Initially, it held 3, then it was changed to 0. The "3" said that "at the moment, the amoeba's X (and Y) coordinate(s) is stored in column "3" of the array." And, in the next generation, the amoeba's X coordinate could be found in column "0" of the array. (The first column being "named" "the zeroth", as is usual inside code.)
It works! It takes some clever code to make it work.. but that's what's going on, inside the program.
In a related vein: There is a table of what color to use for the amoeba, for the freshest pixel of the trail, the next freshest, etc.
Again: The values in the array are not moved around as the program runs. The software knows how to pick the right one.
The ShowAmoebas routine works as follows. When I speak of "an element" of an amoeba, I mean....
(pseudo-code) For each element of each amoeba... do.. For each amoeba... do... Plot a pixel, in the relevant color (End "do each amoeba") (End "do each element)
"Yeah, yeah... big deal", I hear you saying. Fine! Go out write an equivalent program! You'll find it a bit more fraught than you thought it might be!
Or, to see just what is going on in the program you've been given, try any of the following. (If anyone is teaching Lazarus to a class, they are welcome to "set" these challenges to students. I'd be interested to hear about the results...
It would be a simple matter of extending some of the arrays to an additional dimension to provide for different sorts of amoebas... some red ones, some blue ones, etc.
The obvious (and easy) challenge is to extend the program so that the amoebas move in the Y dimension too.
Can you make different amoebas move at different speeds? Move in straight lines which are not parallel to the edges of the image, or at 45 degrees to an edge?
Give each amoeba a "strength" property. Phase 1: The strength values are fixed, a variety being assigned when the world is created. Extend that to something under which strengths wax and wane. Maybe coming near the upper edge makes an amoeba stronger, coming near the bottom edge makes it weaker>
And have the strength of an amoeba somehow displayed in what it looks like on the screen. Oh, and a graph at the side of the screen showing the current distribution of strengths across the population?
Got all that done? Now give all the amoebas (and other organisms... you do have more than just amoebas present by now, don't you?) genes. And have the simulation demonstrate evolution by natural selection. You'll probably have to add feeding, and a mechanism to "rain" "food" from the sky...
That's not too much to attempt. I had most of it running in a program for an Archimedes in about 1988. The idea wasn't mine, but all of the code was.
Search across all my sites with the Google search...
Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes. There were two "unknown attributes" in Google+ button code. Sigh.
....... P a g e . . . E n d s .....