Task 11  Task 11: Variable Arrays  Task 11


Games typically have many objects on the screen all moving independant of each other. Up to this point the example programs you have encountered have controlled one object on the screen. If, for instance, you want to control 5 circles on the screen you would need to create separate variables for each x,y coordinate pair of each circle. That means 10 individually named variables simply to locate 5 circles on the screen. Then, you would need another 10 variables to control the x,y movement, another 5 variables for the size of the circles and yet another 5 variables for the color of each circle! Imagine if you want to control 100 circles at a time ... yes, 350 separate variables to keep track of! Enter the following example program that illustrates just how much work it is to control 5 simple circles on the screen at once using separate variables.

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

DIM x1!, y1!, size1%, col1% ' circle 1 x,y coordinates, radius and color
DIM x2!, y2!, size2%, col2% ' circle 2 x,y coordinates, radius and color
DIM x3!, y3!, size3%, col3% ' circle 3 x,y coordinates, radius and color
DIM x4!, y4!, size4%, col4% ' circle 4 x,y coordinates, radius and color
DIM x5!, y5!, size5%, col5% ' circle 5 x,y coordinates, radius and color
DIM xdir1!, ydir1! '          x,y direction of circle 1
DIM xdir2!, ydir2! '          x,y direction of circle 2
DIM xdir3!, ydir3! '          x,y direction of circle 3
DIM xdir4!, ydir4! '          x,y direction of circle 4
DIM xdir5!, ydir5! '          x,y direction of circle 5

'----------------------------
'- Main Program Begins Here -
'----------------------------

SCREEN 12 '                                       enter graphics screen
RANDOMIZE TIMER '                                 seed number generator
size1% = INT(RND(1) * 20) + 20 '                  random circle 1 size
size2% = INT(RND(1) * 20) + 20 '                  random circle 2 size
size3% = INT(RND(1) * 20) + 20 '                  random circle 3 size
size4% = INT(RND(1) * 20) + 20 '                  random circle 4 size
size5% = INT(RND(1) * 20) + 20 '                  random circle 5 size
col1% = 1 '                                       circle 1 color
col2% = 2 '                                       circle 2 color
col3% = 3 '                                       circle 3 color
col4% = 4 '                                       circle 4 color
col5% = 5 '                                       circle 5 color
x1! = INT(RND(1) * (639 - size1% * 2)) + size1% ' random circle 1 x coordinate
x2! = INT(RND(1) * (639 - size2% * 2)) + size2% ' random circle 2 x coordinate
x3! = INT(RND(1) * (639 - size3% * 2)) + size3% ' random circle 3 x coordinate
x4! = INT(RND(1) * (639 - size4% * 2)) + size4% ' random circle 4 x coordinate
x5! = INT(RND(1) * (639 - size5% * 2)) + size5% ' random circle 5 x coordinate
y1! = INT(RND(1) * (479 - size1% * 2)) + size1% ' random circle 1 y coordinate
y2! = INT(RND(1) * (479 - size2% * 2)) + size2% ' random circle 2 y coordinate
y3! = INT(RND(1) * (479 - size3% * 2)) + size3% ' random circle 3 y coordinate
y4! = INT(RND(1) * (479 - size4% * 2)) + size4% ' random circle 4 y coordinate
y5! = INT(RND(1) * (479 - size5% * 2)) + size5% ' random circle 5 y coordinate
DO
    xdir1! = RND(1) - RND(1) '                    random circle 1 x direction
LOOP UNTIL xdir1! <> 0 '                          loop back if it's 0
DO
    xdir2! = RND(1) - RND(1) '                    random circle 2 x direction
LOOP UNTIL xdir2! <> 0 '                          loop back if it's 0
DO
    xdir3! = RND(1) - RND(1) '                    random circle 3 x direction
LOOP UNTIL xdir3! <> 0 '                          loop back if it's 0
DO
    xdir4! = RND(1) - RND(1) '                    random circle 4 x direction
LOOP UNTIL xdir4! <> 0 '                          loop back if it's 0
DO
    xdir5! = RND(1) - RND(1) '                    random circle 5 x direction
LOOP UNTIL xdir5! <> 0 '                          loop back if it's 0
DO
    ydir1! = RND(1) - RND(1) '                    random circle 1 y direction
LOOP UNTIL ydir1! <> 0 '                          loop back if it's 0
DO
    ydir2! = RND(1) - RND(1) '                    random circle 2 y direction
LOOP UNTIL ydir2! <> 0 '                          loop back if it's 0
DO
    ydir3! = RND(1) - RND(1) '                    random circle 3 y direction
LOOP UNTIL ydir3! <> 0 '                          loop back if it's 0
DO
    ydir4! = RND(1) - RND(1) '                    random circle 4 y direction
LOOP UNTIL ydir4! <> 0 '                          loop back if it's 0
DO
    ydir5! = RND(1) - RND(1) '                    random circle 5 y direction
LOOP UNTIL ydir5! <> 0 '                          loop back if it's 0

DO '                                              begin main program loop
    CLS '                                         clear the screen
    x1! = x1! + xdir1! '                          change circle 1 x location
    IF x1! < size1% OR x1! > 639 - size1% THEN '  did circle 1 hit side of screen?
        xdir1! = -xdir1! '                        yes, reverse circle 1 x direction
    END IF
    x2! = x2! + xdir2! '                          change circle 2 x location
    IF x2! < size2% OR x2! > 639 - size2% THEN '  did circle 2 hit side of screen?
        xdir2! = -xdir2! '                        yes, reverse circle 2 x direction
    END IF
    x3! = x3! + xdir3! '                          change circle 3 x location
    IF x3! < size3% OR x3! > 639 - size3% THEN '  did circle 3 hit side of screen?
        xdir3! = -xdir3! '                        yes, reverse circle 3 x direction
    END IF
    x4! = x4! + xdir4! '                          change circle 4 x location
    IF x4! < size4% OR x4! > 639 - size4% THEN '  did circle 4 hit side of screen?
        xdir4! = -xdir4! '                        yes, reverse circle 4 x direction
    END IF
    x5! = x5! + xdir5! '                          change circle 5 x location
    IF x5! < size5% OR x5! > 639 - size5% THEN '  did circle hit side of screen?
        xdir5! = -xdir5! '                        yes, reverse circle 5 x direction
    END IF
    y1! = y1! + ydir1! '                          change circle 1 y location
    IF y1! < size1% OR y1! > 479 - size1% THEN '  did circle 1 hit side of screen?
        ydir1! = -ydir1! '                        yes, reverse circle 1 y direction
    END IF
    y2! = y2! + ydir2! '                          change circle 2 y location
    IF y2! < size2% OR y2! > 479 - size2% THEN '  did circle 2 hit side of screen?
        ydir2! = -ydir2! '                        yes, reverse circle 2 y direction
    END IF
    y3! = y3! + ydir3! '                          change circle 3 y location
    IF y13 < size3% OR y3! > 479 - size3% THEN '  did circle 3 hit side of screen?
        ydir3! = -ydir3! '                        yes, reverse circle 3 y direction
    END IF
    y4! = y4! + ydir4! '                          change circle 4 y location
    IF y4! < size4% OR y4! > 479 - size4% THEN '  did circle 4 hit side of screen?
        ydir4! = -ydir4! '                        yes, reverse circle 4 y direction
    END IF
    y5! = y5! + ydir5! '                          change circle 5 y location
    IF y5! < size5% OR y5! > 479 - size5% THEN '  did circle 5 hit side of screen?
        ydir5! = -ydir5! '                        yes, reverse circle 5 y direction
    END IF
    CIRCLE (x1!, y1!), size1%, col1% '            draw circle 1
    PAINT (x1!, y1!), col1%, col1% '              paint circle 1
    CIRCLE (x2!, y2!), size2%, col2% '            draw circle 2
    PAINT (x2!, y2!), col2%, col2% '              paint circle 2
    CIRCLE (x3!, y3!), size3%, col3% '            draw circle 3
    PAINT (x3!, y3!), col3%, col3% '              paint circle 3
    CIRCLE (x4!, y4!), size4%, col4% '            draw circle 4
    PAINT (x4!, y4!), col4%, col4% '              paint circle 4
    CIRCLE (x5!, y5!), size5%, col5% '            draw circle 5
    PAINT (x5!, y5!), col5%, col5% '              paint circle 5
    _DISPLAY '                                    update screen with changes
LOOP UNTIL _KEYDOWN(27) '                         leave loop when ESC key pressed
SYSTEM '                                          return to Windows

Work!
Figure 1 - That's a lot of coding for 5 moving circles!!

Now, imagine a game like Asteroids. You need to keep track of the player's ship, a UFO, bullets from the UFO and the player's ship and upwards of 50 asteroids on the screen at any given time. The individual variables to handle all of this motion would be mind boggling. There has to be a better way, right? Well, luckily there is through the use of something called arrays. Here is the same example code from above, but this time using arrays to control everything. Enter the program and execute it and then we'll discuss how this code can be so much smaller yet achieve the same outcome.

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

CONST TOTAL = 5

DIM x!(TOTAL), y!(TOTAL) '       circle x,y coordinates
DIM Xdir!(TOTAL), Ydir!(TOTAL) ' circle x,y directions
DIM Size%(TOTAL) '               circle sizes
DIM Col%(TOTAL) '                circle colors
DIM Count% '                     generic FOR...NEXT counter

'----------------------------
'- Main Program Begins Here -
'----------------------------

SCREEN 12 '                                                                      enter graphics screen
RANDOMIZE TIMER '                                                                seed number generator
FOR Count% = 1 TO TOTAL '                                                        cycle through circles
    Size%(Count%) = INT(RND(1) * 20) + 20 '                                      random circle size
    DO
        Col%(Count%) = INT(RND(1) * 15) + 1 '                                    random circle color
    LOOP UNTIL Col%(Count%) <> 8 '                                               loop back if color 8
    x!(Count%) = INT(RND(1) * (639 - Size%(Count%) * 2)) + Size%(Count%) '       random x location
    y!(Count%) = INT(RND(1) * (479 - Size%(Count%) * 2)) + Size%(Count%) '       random y location
    DO
        Xdir!(Count%) = RND(1) - RND(1) '                                        random x direction
        Ydir!(Count%) = RND(1) - RND(1) '                                        random y direction
    LOOP UNTIL Ydir!(Count%) <> 0 AND Xdir!(Count%) <> 0 '                       loop if either direction 0
NEXT Count%
DO '                                                                             begin main program loop
    CLS '                                                                        clear the screen
    FOR Count% = 1 TO TOTAL '                                                    cycle through circles
        x!(Count%) = x!(Count%) + Xdir!(Count%) '                                change circle x location
        IF x!(Count%) < Size%(Count%) OR x!(Count%) > 639 - Size%(Count%) THEN ' circle hit screen edge?
            Xdir!(Count%) = -Xdir!(Count%) '                                     yes, reverse x direction
        END IF
        y!(Count%) = y!(Count%) + Ydir!(Count%) '                                change circle y location
        IF y!(Count%) < Size%(Count%) OR y!(Count%) > 479 - Size%(Count%) THEN ' circle hit screen edge?
            Ydir!(Count%) = -Ydir!(Count%) '                                     yes, reverse y direction
        END IF
        CIRCLE (x!(Count%), y!(Count%)), Size%(Count%), 8 '                      draw temp circle
        PAINT (x!(Count%), y!(Count%)), Col%(Count%), 8 '                        paint inside temp circle
        CIRCLE (x!(Count%), y!(Count%)), Size%(Count%), Col%(Count%) '           draw circle with color
    NEXT Count%
    _DISPLAY '                                                                   update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                                        leave loop when ESC pressed
SYSTEM '                                                                         return to Windows

Pretty cool huh? Much less code but the same result. Before we continue, change this line of code:

CONST TOTAL = 5

to read

CONST TOTAL = 50

and then run the code again. By changing this number you can create as many circles at once on the screen as you like! We'll come back to this code a bit later in this task after the different types of arrays have been discussed.


Holy cow!
Figure 2 - Holy circles Batman!

-- Arrays --

Of all the concepts in programming it seems that arrays are one of the most troubling to understand for new programmers. An array can be defined as "a systematic arrangement of objetcs, usually in rows and columns." It's the "rows and columns" portion of the definition that makes arrays so powerful in the hands of a programmer. Arrays allow a programmer to keep track of hundreds, thousands, even millions of variables with a predefined table of values that are easily accessible by name, number, or both. In this task we'll attempt to equate arrays to the operation of simple spreadsheets with cells that contain information that can be called upon or changed as desired.

- One Dimensional Arrays -

The simplest array that can be created is the one dimensional array or an array that contains a single column of information with a predefined number of rows. Type in the following snippet of code to see a one dimensional array in use.

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

DIM User$(5) ' array to hold up to 6 strings (0 to 5)
DIM Count% '   generic counter used in FOR...NEXT loop

'----------------------------
'- Main Program Begins Here -
'----------------------------

User$(0) = "Terry" '      assign an element to each array index
User$(1) = "Mark"
User$(2) = "John"
User$(3) = "Mary"
User$(4) = "Luke"
User$(5) = "Melissa"

FOR Count% = 0 TO 5 '     loop through all 6 array indexes
    PRINT User$(Count%) ' display element of each array index
NEXT Count%

The DIM statement is used to dimension, or set up, the array to accept elements of information. An element is a string or numeric value that can be stored within the array. User$ is the variable name of the array and each element value can be accessed by providing an array index, or key, in the form of a numeric value. This array was provided the index value of 5 when it was created allowing for six (0 through 5) string elements to be stored within it rows. An array given only one index value is known as a one dimensional array because it only sets up one column of information to be stored. An easy way to visualize this is to view it as a spreadsheet as seen in Chart 1 below.

User$()
Index #Element
0
1
2
3
4
5
Chart 1 - User$(5) visualized as a spreadsheet

To begin placing elements, or information, into the array you simply address the array variable name with an index number pointing to the row where the element should be stored. This portion of the example code:

User$(0) = "Terry" '      assign an element to each array index
User$(1) = "Mark"
User$(2) = "John"
User$(3) = "Mary"
User$(4) = "Luke"
User$(5) = "Melissa"


placed the elements into their corresponding rows by addressing each row as an index number. The end result is shown in Chart 2 below:

User$()
Index #Element
0Terry
1Mark
2John
3Mary
4Luke
5Melissa
Chart 2 - User$(5) populated array

By using an index number with the array variable name, User$, you can obtain the value of the element at that index location, like so:

PRINT User$(2)

To which the result printed to the screen would be John. Likewise, if you wish to change the value of any element simply use the index number and assign a new value as such:

User$(2) = "Thomas"

This will overwrite the element's value at array index 2 with the new information as seen in Chart 3 below:


User$()
Index #Element
0Terry
1Mark
2Thomas
3Mary
4Luke
5Melissa
Chart 3 - Element at index 2 altered

- Two Dimensional Arrays -

Two dimensional arrays allow you to create a table that can be accessed in two dimensions, that is they have an X and Y component that can address multiple columns and rows of data. Consider the following example code:

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

DIM Contacts$(3, 5) ' two dimensional array used as contact database
DIM Match% '          contains index number of match if found
DIM Count% '          index counter
DIM SearchName$ '     name user wishes to search for

'----------------------------
'- Main Program Begins Here -
'----------------------------

Contacts$(1, 1) = "Mike Smith" '     populate database with information
Contacts$(1, 2) = "123 Any Street"
Contacts$(1, 3) = "Anytown"
Contacts$(1, 4) = "OH"
Contacts$(1, 5) = "12345"

Contacts$(2, 1) = "Laura Flowers"
Contacts$(2, 2) = "456 This Street"
Contacts$(2, 3) = "Toledo"
Contacts$(2, 4) = "MA"
Contacts$(2, 5) = "23432"

Contacts$(3, 1) = "Tom Thumb"
Contacts$(3, 2) = "765 My Street"
Contacts$(3, 3) = "Mayberry"
Contacts$(3, 4) = "NC"
Contacts$(3, 5) = "24241"

DO '                                                                       main loop begins
    PRINT '                                                                blank line
    PRINT "Enter a name, or partial name, to search for." '                display instructions
    INPUT "Enter nothing to end the program > ", SearchName$ '             get name to search for
    IF SearchName$ = "" THEN END '                                         end program if nothing
    Count% = 1 '                                                           reset index counter
    Match% = 0 '                                                           reset match indicator
    DO '                                                                   begin search loop
        IF INSTR(UCASE$(Contacts$(Count%, 1)), UCASE$(SearchName$)) THEN ' is name contained within?
            Match% = Count% '                                              yes, remember this index
            EXIT DO '                                                      leave the DO...LOOP
        END IF
        Count% = Count% + 1 '                                              increment index counter
    LOOP UNTIL Count% = 4 '                                                leave loop when value 4
    IF Match% THEN '                                                       was there a match? (<> 0)
        PRINT '                                                            yes, blank line
        PRINT "Match found!" '                                             inform user
        PRINT '                                                            blank line
        PRINT "Name   : "; Contacts$(Match%, 1) '                          display element values
        PRINT "Address: "; Contacts$(Match%, 2)
        PRINT "City   : "; Contacts$(Match%, 3)
        PRINT "State  : "; Contacts$(Match%, 4)
        PRINT "Zip    : "; Contacts$(Match%, 5)
    ELSE '                                                                 no, nothing matched
        PRINT '                                                            blank line
        PRINT "Match not found." '                                         inform user
    END IF
LOOP '                                                                     loop back to beginning

Database
Figure 3 - A simple contact database program

With this program we have created a two dimensional array called Contacts$ that contains four rows (0 to 3) and six columns (0 to 5) by issuing the command:

DIM Contacts$(3, 5)

It's important not to forget that array indexes start at zero but that does not mean you need to fill the elements with data starting at index zero. Many times it just feels correct to start using an array at index one, such as with the example program above. This is purely up to the programmer whether index zero is used or not. Again, by visualizing the array as a spreadsheet it may make more sense as to how the data is stored as seen in Chart 4 below:


Contacts$()
Elements
Index #012345
0<null><null><null><null><null><null>
1<null>Mike SMith123 Any StreetAnytownOH12345
2<null>Laura Flowers456 This StreetToledoMA23432
3<null>Tom Thumb765 My StreetMayberryNC24241
Chart 4 - Contacts$(3, 5) populated array

Each column in the above spreadsheet could be assigned a name that the programmer could use to easily remember the element information it contains. For example, column 1 would be "name", column 2 "address", column 3 "city", column 4 "state" and column 5 "zip". However, the method of creating arrays using DIM alone does not lend to naming the columns. The programmer would need to simply remember what each column is used for. However, there is a way to create arrays that allows the columns to be named making it easier for the programmer to remember the type of data held in each column.

- Arrays Created with TYPE -

TYPEs allow you to define a data structure of grouped and often related information. Let's look at the following code example to see how TYPEs can be utilized.

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

TYPE DOT
    x AS INTEGER ' x location of pixel
    y AS INTEGER ' y location of pixel
    c AS INTEGER ' color of pixel
END TYPE

DIM Pixel AS DOT ' a variable created with custom TYPE

'----------------------------
'- Main Program Begins Here -
'----------------------------

SCREEN 12 '                        enter graphics screen
Pixel.x = 319 '                    set pixel x coordinate
Pixel.y = 239 '                    set pixel y coordinate
Pixel.c = 15 '                     set pixel color
PSET (Pixel.x, Pixel.y), Pixel.c ' draw pixel on screen

In this program a data structure called DOT was created using the TYPE statement. Inside this data structure are defined three variables x, y and c. The END TYPE statement denotes where the data structure ends. However, type identifier symbols such as the percent sign (%) for integers and dollar sign ($) for strings are not allowed. Variable data types must be defined using the AS clause with the name of the data type spelled out after it. (Data type names can be found here in the QB64 wiki describing the TYPE statement)

Once a data structure has been defined it must be associated with a variable name in order to use it. In the example program above this was accomplished by the following line of code:

DIM Pixel AS DOT ' a variable created with custom TYPE

The variable name of Pixel can now be used to access the data structure DOT embedded within it. In order to access a data structure sub-variable the use of period (.) must follow the main variable name and then the name of the sub-variable as seen in the example program above:


Pixel.x = 319 '                    set pixel x coordinate
Pixel.y = 239 '                    set pixel y coordinate
Pixel.c = 15 '                     set pixel color


To get an idea of what this structure looks like, let's again view the variable in spreadsheet form.

Pixel.xyc
31923915
Chart 5 - The variable Pixel's structure

As you can see in Chart 5 above, the use of a data structure creates self-documenting column names within the variable itself. This makes retrieving information from a variable with a data structure much more intuitive as this line in the example proves:

PSET (Pixel.x, Pixel.y), Pixel.c ' draw pixel on screen

The PSET statement needs at minimum an x and y value to turn a pixel on, supplied by Pixel.x and Pixel.y, and an optional color value of the pixel supplied by Pixel.c. The line above is practically self explanatory at this point thanks to the use of a data structure. Now, what's really cool is we can use these structured data types to create arrays that become very intutive to use.

A one dimensional array created with a variable containing a data structure takes on two dimensional array properties. Let's take the last example program and modify it to use a one dimensional array.

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

CONST MAXPIXELS% = 10 '        number of pixels +1 on screen

TYPE DOT
    x AS INTEGER '             x location of pixel
    y AS INTEGER '             y location of pixel
    c AS INTEGER '             color of pixel
END TYPE

DIM Pixel(MAXPIXELS%) AS DOT ' create one dimension array with data structure
DIM Count% '                   index counter

'----------------------------
'- Main Program Begins Here -
'----------------------------

SCREEN 12 '                                                    enter graphics screen
RANDOMIZE TIMER '                                              seed random number generator
FOR Count% = 0 TO MAXPIXELS% '                                 cycle through all indexes
    Pixel(Count%).x = INT(RND(1) * 640) '                      random x between 0 and 639
    Pixel(Count%).y = INT(RND(1) * 480) '                      random y between 0 and 479
    Pixel(Count%).c = 15 '                                     set pixel color
    PSET (Pixel(Count%).x, Pixel(Count%).y), Pixel(Count%).c ' turn pixel on
NEXT Count%

Using the value stored in the constant MAXPIXELS% we can now create as many pixels on the screen as we wish. Using the current value of 10 let's again visualize the array that was created by using a spreadsheet.


Pixel().
Index #xyc
03419815
145213415
222840115
31671415
4982115
556337515
613317915
738222215
81146515
931229015
1055734115
Chart 6 - One dimensional array with two dimensional properties

The index number serves as the row value and the data structure variable names represent the columns. Therefore, if you need to pull the y value of the fourth pixel you could simply issue the command:

PRINT Pixel(3).y ' the value of 14 printed to the screen

Before we get into three dimensional arrays let's take the second code example in this task and rewrite it again but this time with a structured array to see how much nicer and easier the code is to read.


'--------------------------------
'- Variable Declaration Section -
'--------------------------------

CONST FALSE = 0, TRUE = NOT FALSE '   truth testers (discussed in a later task)
CONST MAXCIRCLES% = 100 '             number of circles on screen
CONST MAXRADIUS% = 30 '               maximum radius of circles
CONST SWIDTH% = 640 '                 screen width (don't exceed your monitor)
CONST SHEIGHT% = 480 '                screen height (don't exceed your monitor)

TYPE CIRCLES '                        data structure to hold circle info
    x AS SINGLE '                     x location of circle
    y AS SINGLE '                     y location of circle
    r AS INTEGER '                    radius of circle
    c AS _UNSIGNED LONG '             32bit color of circle (16 million possible colors)
    xVel AS SINGLE '                  x velocity of cricle
    yVel AS SINGLE '                  y velocity of circle
END TYPE

DIM Circles(MAXCIRCLES%) AS CIRCLES ' structured array to hold circle info
DIM Count% '                          index counter
DIM First% '                          first loop run indicator

'----------------------------
'- Main Program Begins Here -
'----------------------------

SCREEN _NEWIMAGE(SWIDTH%, SHEIGHT%, 32) '                                                         make 32bit graphics screen
RANDOMIZE TIMER '                                                                                 seed number generator
First% = TRUE '                                                                                   this is first time loop run
DO '                                                                                              begin main program loop
    CLS '                                                                                         clear the screen
    FOR Count% = 0 TO MAXCIRCLES% '                                                               cycle through indexes
        IF First% THEN '                                                                          first loop run?
            Circles(Count%).r = INT(RND(1) * (MAXRADIUS% - 10) + 10) '                                   yes, random circle radius
            Circles(Count%).x = INT(RND(1) * (SWIDTH% - (Circles(Count%).r * 2))) + Circles(Count%).r '  random x coordinate
            Circles(Count%).y = INT(RND(1) * (SHEIGHT% - (Circles(Count%).r * 2))) + Circles(Count%).r ' random y coordinate
            Circles(Count%).c = _RGB32(INT(RND(1) * 256), INT(RND(1) * 256), INT(RND(1) * 256)) '        random 32bit color
            Circles(Count%).xVel = (RND(1) - RND(1)) * 2 '                                        random x velocity
            Circles(Count%).yVel = (RND(1) - RND(1)) * 2 '                                        random y velocity
        END IF
        IF Circles(Count%).x + Circles(Count%).xVel < Circles(Count%).r THEN '                    will circle hit left edge?
            Circles(Count%).x = Circles(Count%).r '                                               yes, put circle at left edge
            Circles(Count%).xVel = -Circles(Count%).xVel '                                        reverse x velocity
        ELSEIF Circles(Count%).x + Circles(Count%).xVel > SWIDTH% - Circles(Count%).r - 1 THEN '  no, will circle hit right edge?
            Circles(Count%).x = SWIDTH% - Circles(Count%).r - 1 '                                 yes, put circle at right edge
            Circles(Count%).xVel = -Circles(Count%).xVel '                                        reverse x velocity
        ELSE '                                                                                    no, circle can move freely
            Circles(Count%).x = Circles(Count%).x + Circles(Count%).xVel '                        update circle x position
        END IF
        IF Circles(Count%).y + Circles(Count%).yVel < Circles(Count%).r THEN '                    will circle hit top edge?
            Circles(Count%).y = Circles(Count%).r '                                               yes, put circle at top edge
            Circles(Count%).yVel = -Circles(Count%).yVel '                                        reverse y velocity
        ELSEIF Circles(Count%).y + Circles(Count%).yVel > SHEIGHT% - Circles(Count%).r - 1 THEN ' no, will circle hit bottom edge?
            Circles(Count%).y = SHEIGHT% - Circles(Count%).r - 1 '                                yes, put circle at bottom edge
            Circles(Count%).yVel = -Circles(Count%).yVel '                                        reverse y velocity
        ELSE '                                                                                    no, circle can move freely
            Circles(Count%).y = Circles(Count%).y + Circles(Count%).yVel '                        update circle y position
        END IF
        CIRCLE (Circles(Count%).x, Circles(Count%).y), Circles(Count%).r, Circles(Count%).c '     draw circle
        PAINT (Circles(Count%).x, Circles(Count%).y), Circles(Count%).c, Circles(Count%).c '      paint circle
    NEXT Count%
    First% = FALSE '                                                                              reset first loop run indicator
    _DISPLAY '                                                                                    update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                                                         leave loop when ESC pressed
SYSTEM '                                                                                          return to Windows

The code above sets up a one dimensional array with two dimensional qualities. Once again here is a spreadsheet representation of the data structure created (only a few lines shown for interest of size).

Circles().
Index #xyrcxVelyVel
03415622<color>0.33-0.11
113441312<color>-0.87-0.78
26931721<color>-0.130.97
357622514<color>0.630.39
44898917<color>0.32-0.61
.....................
10052136227<color>-0.480.67
Chart 7 - The Circles(). array in spreadhseet from

The code above is updating values in the spreadsheet based on what is happening on the screen. The array is cycled through with the use of a FOR...NEXT loop one index at a time. The x velocity and y velocity are added to the current x position and y position and the new x and y values are saved back to the spreadsheet. If the current x or y location of the circle happens to fall beyond the limits of the screen the x velocity or y velocity is reversed and saved back to the spreadsheet. Once the calculations for the current circle have been made and saved the circle is drawn to the screen using the newly saved values. When all indexes have been cycled through the screen is cleared and the process starts again. The values from the last cycle are saved in the spreadsheet for use in the next cycle, and so on. This is the main basis of most video games that require many objects on the screen to be manipulated during each screen update. Playing with the values of the constants at the top of the code allows for easy manipulation of the array.

Just imagine if you want to control this many objects at one time without the use of an array structure. You would need to create 606 unique variables to handle all of this interaction and manually check each variable within the code! This would result in a program that could easily be thousands of lines, or perhaps even tens of thousands of lines long. <yikes!>


- Three Dimensional Arrays -

For many new programmers a three dimensional array is particularly difficult to envision, but once again using the analogy of spreadsheets even this concept should become clear. A three dimensional array is a collection of spreadsheets stacked on top of one another with each spreadsheet containing its own rows and columns. For example, take the collowing line of code:

DIM Calendar$(11, 6, 5)

This line of code sets up 12 individual spreadsheets (0 to 11), each containing seven columns (0 to 6) and six rows (0 to 5). Do you see what we have created here? ... a one year calendar. Again, this will be easier to envision as spreadsheets.


Month 2Calendar$(2, #, #)
Month 1Calendar$(1, #, #)6
Month 0Calendar$(0, #, #)6Sat 6th
Index#0123456Sat 2ndSat 13th
0Tue 1stWed 2ndThu 3rdFri 4thSat 5thSat 9thSat 20th
1Sun 6thMon 7thTue 8thWed 9thThu 10thFri 11thSat 12thSat 16thSat 27th
2Sun 13thMon 14thTue 15thWed 16thThu 17thFri 18thSat 19thSat 23rd
3Sun 20thMon 21stTue 22ndWed 23rdThur 24thFri 25thSat 26thSat 30th
4Sun 27thMon 28thTue 29thWed 30thThur 31st
5
Chart 8 - Three dimensional array creating a one year calendar

Did you notice that we addressed the rows and columns differently in this array than any previous array? In this case the first index (11) contains the 12 months, the second index (6) is addressing each column in the array and the third index (5) is addressing each row in the array. In all of the previous examples we address the row first and then the column, but this is completely up to the programmer how the elements are arranged. With a situation such as a calendar it makes sense to address the column first (the week day) and then the row (the week).

- Four Dimensional Arrays and Beyond -

Ok, this is getting out of hand right? You can add any number of indexes you wish when creating an array just realize the more you add, the more complex your array gets and the more RAM it will use. To get an idea of where a four dimensional array would come in handy consider the following:

DIM Calendar$(999, 11, 6, 5)

Here we have an array that could be interpreted as a calendar that spans 1000 years. In other words, we've created 1000 (0 to 999) of the yearly calendar arrays in the previous three dimensional example. Once again keep in mind that the larger the array the more RAM it will consume. With this example alone we have created 504,000 element indexes or 1000 x 12 x 7 x 6.


-- Your Turn --











-- COMMAND REFERENCE --


Commands learned in previous tasks:

PRINT
INPUT
DIM
REM or '
CONST
TIME$
VAL()
IF...THEN
AND
END
GOTO
SELECT CASE...END SELECT
CASE
TO
IS
CASE ELSE
colon ( : )
FOR...NEXT
STEP
CLS
SLEEP
_DELAY
SYSTEM
DO...LOOP UNTIL (and variations)
WHILE...WEND
SCREEN
LINE
CIRCLE
PAINT
PSET
SUB
END SUB
FUNCTION
END FUNCTION
SHARED
SQR()
^ (exponent)
INPUT$
LINE INPUT
INKEY$
CHR$()
_KEYDOWN
_KEYHIT
_MOUSEX
_MOUSEY
_MOUSEINPUT
_MOUSEHIDE
_MOUSESHOW
_MOUSEMOVE
_MOUSEBUTTON

New commands introduced in this task:

DIM
TYPE
END TYPE
AS

Concepts learned in previous tasks:

execute
statement
expression
literal string
syntax error
variables
type declarations
literal strings
concatenation
integers
long integers
single precision
double precision
strings
null strings
reserved words
operators ( +, -, *, / )
declare
constant
relational operators
functions
nesting
order of operations
Boolean
conditions
indenting
loops
labels
frame rate
controlled loops
conditional loops
Monochrome
Grayscale
pixels
bits per pixel
radian
counter-clockwise
aspect ratio
algorithm
subroutine
function
local variables
RAM
global variables
Pythagorean Theorem
BIOS
ASCII
buffer
CMOS
ROM
ASCII chart

New concepts introduced in this task:

array
one dimensional array
element
index
two dimensional array
three dimensional array