;------------------------------------------------------------------------------- ; ; ;-------------------------------; ; ; Variable Collections ; ; ;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,; ; ; This part is quite large, to say the least. ; So copy and paste as you see fit. ; ;------------------------------------------------------------------------------- ; ; In a lot of games you can carry multiple weapons. ; Each of these weapons would require ammunition of some sort. ; What if you wanted to create such a system? ; You could do it like this: ; Weapon1_Ammo = 50 Weapon2_Ammo = 0 Weapon3_Ammo = 0 Weapon4_Ammo = 5 ; ; There is another solution however; an array. ; Dim Weapon_Ammo( 4 ) ; Weapon_Ammo( 1 ) = 50 Weapon_Ammo( 2 ) = 0 Weapon_Ammo( 3 ) = 0 Weapon_Ammo( 4 ) = 5 ; ; You're probably wondering why anyone wouldn't want to use ; the topmost solution - it does look a lot easier! :) ; Ofcourse it's all up to the programmer. ; But imagine having a huge amount of weapons. ; And you wanted to display the amount of ammo ; for each weapon on the screen. ; For the topmost approach: ; Print "Weapon 1 ammo: " + Weapon1_Ammo Print "Weapon 2 ammo: " + Weapon2_Ammo Print "Weapon 3 ammo: " + Weapon3_Ammo Print "Weapon 4 ammo: " + Weapon4_Ammo Print WaitKey ; ; And for the array: ; For Weapon_Number = 1 To 4 Print "Weapon " + Weapon_Number + " ammo: " + Weapon_Ammo( Weapon_Number ) Next Print WaitKey ; ; E.g. you can easily walk through each element in the array ; instead of copying, pasting and editing every line :) ; ; The For..Next loop you see up there repeats the Print statement 4 times. ; The variable Weapon_Number - which did not exist before that point - ; will be created as integer variable and a value of 1 is added to it ; with each repetition, inside the For..Next. ; ; Here's a couple of alternatives: ; ; Repeat..Until ; Weapon_Number = 0 Repeat Weapon_Number = Weapon_Number + 1 Print "Weapon " + Weapon_Number + " ammo: " + Weapon_Ammo( Weapon_Number ) Until Weapon_Number = 4 Print WaitKey ; Weapon_Number = 1 Repeat Print "Weapon " + Weapon_Number + " ammo: " + Weapon_Ammo( Weapon_Number ) Weapon_Number = Weapon_Number + 1 Until Weapon_Number = 5 Print WaitKey ; ; While..Wend ; Weapon_Number = 0 While Weapon_Number < 4 ; Keep repeating until Weapon_Number >= 4 Weapon_Number = Weapon_Number + 1 Write "Weapon " ; Use Write if you don't want Write Weapon_Number ; the cursor to go to Write " ammo: " ; the next line. Print Weapon_Ammo( Weapon_Number ) Wend Print WaitKey ; ; And there are lots more! ; ;------------------------------------------------------------------------------- ; ; Remember what happens when a variable is used ; or called upon for the first time? ; A_New_Variable = 0 ; ; It is created, declared, initialized; its type is set. ; Local An_Integer_Variable% = 0 ; ; By default, all variables will be set to 0 when created. ; This also applies to arrays. ; So when you write ; Dim Weapon_Ammo( 4 ) ; ; for the first time, ; a number of elements will be created and set to 0. ; ; Did you notice that each element in the array is also of a specific type? ; That's right, the Weapon_Ammo array is an array of integers! ; Dim Weapon_Ammo%( 4 ) ; ; Another thing you see above is that you can redefine an array. ; When you do this, everything inside the array will be set to 0 again. ; And, not only can you erase an entire array, you can even change its size! ; Dim Weapon_Ammo( 1 ) ; ; But wait - there is more :P ; When an array is created it doesn't start counting from 1. ; Weapon_Ammo( 0 ) = 50 Weapon_Ammo( 1 ) = 5 ; ; There are actually 2 elements in it, when you define it with ( 1 ). ; So there's an extra element ( 0 ). ; This is the difference between 0-based and 1-based orientation. ; E.g. start counting from 0 instead of 1. ; It's usually just another case of personal preference :) ; ; Let's take a look at what our Weapon_Ammo array looks like, ; schematically: ; ; | 0 | 1 | - Element (weapon number) ; +-------+-------+ ; | | | ; | 50 | 5 | - Contents (ammo amount) ; | | | ; +-------+-------+ ; | Array | ; +---------------+ ; ; Resizing the array to its original size. ; All contents is lost. ; Dim Weapon_Ammo( 4 ) ; ; | 0 | 1 | 2 | 3 | 4 | - Element ; +-------+-------+-------+-------+-------+ ; | | | | | | ; | 0 | 0 | 0 | 0 | 0 | - Contents ; | | | | | | ; +-------+-------+-------+-------+-------+ ; | Array | ; +---------------------------------------+ ; ; As with normal variables, ; you can't change the type of the elements ; once an array has been declared for the first time. ; So let's take a new array, an array of strings. ; For example, if we want to store the name of each weapon. ; Dim Weapon_Name$( 4 ) ; Weapon_Name( 1 ) = "Pistol" Weapon_Name( 2 ) = "Shotgun" Weapon_Name( 3 ) = "Flame thrower" Weapon_Name( 4 ) = "Rocket launcher" ; ; Again, as with variables, once arrays are defined, ; you can omit the type identifier ($, #, etc), ; as you can see above. ; ; You can declare arrays of any type. ; Just to recap, here are the available types: ; ; % Integer variable ; # Floating point variable ; $ String variable ; .[Type name] Pointer variable (more about this soon) ; ; If you can remember, variables are used like this: ; ; [Variable name][Variable type] ; ; Arrays are used like this: ; ; [Array name][Type of elements]([Number of elements]) ; ; Number of elements is actually the number of elements + 1, as shown before. ; ;------------------------------------------------------------------------------- ; ; Unlike normal variables, normal arrays ; - declared using the Dim keyword - ; are always global. ; So you can use them anywhere in your program. ; ; There is another trick you can do with arrays. ; When you declare an array you use the Dim keyword, ; which is short for dimension. ; Which would indicate that arrays can be multidimensional. ; Is this true? ; Dim Grid( 6 , 4 ) ; ; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; +--+-------+-------+-------+-------+-------+-------+-------+ ; | Array | ; +----------------------------------------------------------+ ; ; Apparently :P ; In the above example, a 2-dimensional array, like a grid. ; Imagine a maze where you can walk through. ; So you'd want some walls. ; - How? ; Let's say that a value of 0 (all elements currently) ; means that you can walk there. ; And a value of 1 means there's a wall there. ; You can choose any values you want ofcourse, ; it's all up to the programmer :) ; ; Let's place a wall in the center of the map (3,2). ; Grid( 3 , 2 ) = 1 ; ; This code doesn't really convey much ; as you'll read back sometime and wonder what the 1 stands for, ; but we can do something about that :) ; Const Free = 0 Const Wall = 1 ; Grid( 3 , 2 ) = Wall ; ; You'll probably remember the 'state-of-life'. ; This is a perfect example of those state identifiers. ; ; Now let's place a larger wall section. ; So we'd have to fill a number of places on the grid with the value 1. ; You could do it like this: ; Grid( 0 , 0 ) = Wall Grid( 0 , 1 ) = Wall Grid( 0 , 2 ) = Wall Grid( 0 , 3 ) = Wall Grid( 0 , 4 ) = Wall ; ; So you'd get a vertical wall section on the left side of the grid. ; But you could also use a For..Next loop for that. ; For Y = 0 To 4 Grid( 0 , Y ) = Wall Next ; ; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 2 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 4 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ; | | | | | | | | ; +--+-------+-------+-------+-------+-------+-------+-------+ ; | Array | ; +----------------------------------------------------------+ ; ; Let's try the opposite side. ; For Y = 0 To 4 Grid( 6 , Y ) = Wall Next ; ; And if you wanted to complete the box with a couple of ; horizontal wall sections, well.. ; I think you'll understand the code below. ; For X = 0 To 6 Grid( X , 0 ) = Wall Grid( X , 4 ) = Wall Next ; ; Yes, we're actually putting a wall in each corner for the second time. ; It doesn't really need to be fixed, ; as it won't cause bugs or slowdowns, ; but here's what we could have done: ; For X = 1 To 5 Grid( X , 0 ) = Wall Grid( X , 4 ) = Wall Next ; ; Now, it may seem pretty obvious what the grid looks like. ; ; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 2 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 3 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | ; | | | | | | | | ; ---+-------+-------+-------+-------+-------+-------+-------+ ; | | | | | | | | ; 4 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ; | | | | | | | | ; +--+-------+-------+-------+-------+-------+-------+-------+ ; | Array | ; +----------------------------------------------------------+ ; ; But it might not be as obvious ; how to display the grid on the screen. ; (Yes, I know, it doesn't really look like a maze :P) ; ; If we were to walk through each element in our grid, ; how would we do that in code? ; It is very similar to the first For..Next loop in this program. ; ; If you remember, ; we did a couple of combined loops. ; Even an example of a checkerboard. ; For Y = 0 To 4 For X = 0 To 6 ; Grid( X , Y ) Next Next ; ; And that's all there is to it! :) ; Well, okay, not all, I mean, ; we still have to put it on the screen :P ; For Y = 0 To 4 For X = 0 To 6 Write Grid( X , Y ) ; Same line. Next Print ; Next line. Next WaitKey ; ; Note that the X and Y dimensions can be easily mixed-up. ; This can be dangerous to your code's health :) ; So be careful how you order your dimensions. ; ; Here's an example of what might happen: ; Print For Y = 0 To 4 For X = 0 To 4 ; Made smaller to stay ; within grid range. Write Grid( Y , X ) ; Swapped X with Y. Next Print Next WaitKey ; ; The grid gets rotated 90 degrees! ; Hmm, not exactly what we had in mind :) ; ; I've made the X range smaller ; otherwise Blitz will complain ; that we're trying to access ; an element that lies beyond ; the range of our array. ; ;------------------------------------------------------------------------------- ; ; By the way, the Write and Print commands ; are not exactly graphical commands. ; These, as well as their friends Locate and Input ; are not totally satisfiable. (eh?) ; I'll explain this later. ; ; So let's try some more 'gamey' commands. ; There's some more maths required though. ; ; First, let's CLear the Screen. ; Cls ; ; And place some Text at a pixel location of our desire. ; Text 100 , 100 , "<- (100,100)" WaitKey ; ; Text, hmm? ; Here's the syntax: ; ; Text (Pixel X location) , (Pixel Y location) , (Text) ; ; There are more optional parameters, (say what?) ; but I'll leave those up to you to find out :P ; Parameters, you know? ; Those thingies you put behind a command, ; separated by commas. ; ; If you're inside BlitzBasic, ; you can press F1 when the cursor is on or near a command/keyword, ; and at the bottom of the window you will see the quick help (syntax). ; Pressing F1 again will bring up the full help page. ; ; Let's try a loop with the Text command. ; A vertical display of numbers below (100,100) on screen. ; For Y = 1 To 5 Text 100 , 100 + Y * 10 , Y Next ; ; What happens in the loop is ; ; Y = 1 Pixel X Location = 100 ; Pixel Y Location = 100 + 1 * 10 ; 100 + 10 = 110 ; Text = 1 ; ; Y = 2 Pixel X Location = 100 ; Pixel Y Location = 100 + 2 * 10 ; 100 + 20 = 120 ; Text = 2 ; ; Y = 3 Pixel X Location = 100 ; Pixel Y Location = 100 + 3 * 10 ; 100 + 30 = 130 ; Text = 3 ; ; Y = 4 Pixel X Location = 100 ; Pixel Y Location = 100 + 4 * 10 ; 100 + 40 = 140 ; Text = 4 ; ; Y = 5 Pixel X Location = 100 ; Pixel Y Location = 100 + 5 * 10 ; 100 + 50 = 150 ; Text = 5 ; ; So we leave exactly 10 pixels space for each piece of text, vertically. ; ; Let's try something more interesting. ; For GridY = 0 To 4 For GridX = 0 To 6 ScreenX = GridX * 10 ; Pixel X Location. ScreenY = GridY * 10 ; Pixel Y Location. Display = Grid( GridX , GridY ) ; Number to put on screen. Text ScreenX , ScreenY , Display Next Next WaitKey ; ; - Isn't the result of that (almost) the same as with Write and Print? ; Indeed it is. The point is that Text has advantages over Write and Print. ; - Which advantages? ; I guess you want to know everything, huh? :) ; First, Text is faster. ; And second, Text is more flexible. ; - More flexible? How? ; You can center the text you want to display on a certain coordinate, ; without having to do the maths for it. ; - How? ; Enough questions! :P ; Please read the Blitz help for more.. ; Right now we need colors! ; Color 255 , 0 , 0 ; (eh?) ; ; That is how we can set the current drawing color. ; Syntax: ; ; Color (Red) , (Green) , (Blue) ; ; The combined color components give you a color of your desire. ; You can specify values in the range of 0 and 255, ; where 0 means darkest and 255 means brightest. ; ; So the current drawing color is now; Red. ; ; Some more examples: ; Color 0 , 255 , 0 ; Green Color 0 , 0 , 255 ; Blue Color 255 , 255 , 255 ; White Color 0 , 0 , 0 ; Black Color 255 , 255 , 0 ; Yellow Color 255 , 0 , 255 ; Purple Color 128 , 128 , 128 ; Gray Color 255 , 128 , 0 ; Orange Color 128 , 64 , 0 ; Brown Color 16 , 96 , 160 ; Creme Blue ; ; So if we start putting something on the screen now, ; it will be... Creme Blue :) ; Text 0 , 100 , "Creme Blue" ; ; Let's take our old loop and throw in some colors. ; For GridY = 0 To 4 For GridX = 0 To 6 ScreenX = GridX * 10 ScreenY = GridY * 10 Display = Grid( GridX , GridY ) If Display Color 0 , 128 , 255 Else Color 128 , 64 , 0 End If Text ScreenX , ScreenY , Display Next Next WaitKey ; ; If an element in our grid contains a non-zero value, ; it will be placed on the screen in Light Blue, ; otherwise Brown. ; ; We are actually overwriting our old grid display on the screen. ; That is, if you're running these couple of sections in one go. ; ; Btw, you can also apply some 'glue' ; to get rid of the extra variables. ; Like this: ; ; Text GridX * 10 , GridY * 10 , Grid( GridX , GridY ) ; ; It can be harder to read though. ; ; The screen is cleared with the color black by default. ; But you can change that. ; ClsColor 128 , 64 , 0 ; ; The ClsColor command works the same as the Color command. ; But it applies only to the Cls command. ; Cls ; ; This would clear your screen with the color.. Brown :) ; ;------------------------------------------------------------------------------- ; ; We've been using a 2-dimensional array. ; So it's time for a 3-dimensional array. ; Dim Grid3D$( 10 , 10 , 1 ) ; ; That would be.. 11 * 11 * 2 = 242 elements. ; Kinda like this: ; ; ---+---+---+---+---+---+---+---+---+---+---+---+ ; 1 / / / / / / / / / / / /| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + ; 0 / / / / / / / / / / / /|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 0 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 1 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 2 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 3 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 4 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 5 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 6 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 7 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 8 | | | | | | | | | | | |/|/| ; ---+---+---+---+---+---+---+---+---+---+---+---+ + + ; 9 | | | | | | | | | | | |/|/ \ ; ---+---+---+---+---+---+---+---+---+---+---+---+ + 1 ; 10 | | | | | | | | | | | |/ \ ; ---+---+---+---+---+---+---+---+---+---+---+---+ 0 ; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 \ ; ; Or like this: ; ; | 0 | 1 | 2 | 3 | 4 | 5 ; ---+---+---+---+---+---+---+---+---+---+---+-- - - ; | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | ; 0 |---+---|---+---|---+---|---+---|---+---|-- - - ; | : | : | : | : | : | ; ---+-------+-------+-------+-------+-------+-- - - ; | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | ; 1 |---+---|---+---|---+---|---+---|---+---|-- - - ; | : | : | : | : | : | ; ---+-------+-------+-------+-------+-------+-- - - ; | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | ; 2 |---+---|---+---|---+---|---+---|---+---|-- - - ; | : | : | : | : | : | ; ---+-------+-------+-------+-------+-------+-- - - ; | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | ; 3 |---+---|---+---|---+---|---+---|---+---|-- - - ; | : | : | : | : | : | ; ---+-------+-------+-------+-------+-------+-- - - ; | | | | | | ; 4 : : : : : : etc ; ; So if you would say ; ; Grid3D( 0 , 0 , 1 ) = 6 ; ; here's what would happen: ; ; | 0 | 1 ; ---+---+---+-- - - ; | 0 | 1 | ; 0 |---+---|-- - - ; | : 6 | ; ---+-------+-- - - ; | | ; 1 : : etc ; ; So now we can store a unique color for each element, ; as well as a unique character (A, z, 0, !, etc). ; ; We'd have to agree on how to store the things again. ; For example, for each element on the grid ; field 0 would contain the color and ; field 1 would contain the character. ; ; You saw I picked an array of strings so it makes ; storing both types (values and text) easier. ; ; Let's use some sort of index selector to ; distinguish color from character. (a what?) ; Just to make the code more clear. ; Const Grid3D_Color = 0 Const Grid3D_Char = 1 ; ; Here's an example: ; Grid3D( 10 , 10 , Grid3D_Char ) = "A" ; ; Hopefully this would mean that we put a capital A ; in the lower right corner of the grid. ; But we're not there yet. ; ; Let's remove it before anyone notices it :P ; Grid3D( 10 , 10 , Grid3D_Char ) = "" ; ; We need to know which colors we're gonna use. ; I mean, we only have 1 field to store a color. ; We could increase the number of fields in the array, ; to be able to use 2 new fields, ; so we would have one field for Red, ; one for Green and one for Blue. ; E.g. having an array that looks like this: ; ; Dim Grid3D$( 10 , 10 , 3 ) ; ; But let's do it the hard way :P ; ; As before, we can agree on some ; constants for colors we want to use. ; ; Suppose we want simply red, green and blue. ; Const Color_Red = 0 Const Color_Green = 1 Const Color_Blue = 2 ; ; Again, which values they contain doesn't really matter, ; so long as the values are unique. ; You could even use strings if you wanted to, ; as we're using a grid of strings. ; ; Example: ; ; Grid3D( 5 , 5 , Grid3D_Color ) = Color_Red ; ; So this would be a 'state-of-life' again. ; Like in the previous parts. ; ; You're right, this has nothing to do with ; displaying it on the screen, yet :P ; ; By default, the grid is empty, because it's a grid of strings. ; When you store a number, it will be converted to text. ; And if want to get the number back, ; and store it in an integer variable, ; the text will be translated back into a number. ; ; You can imagine a problem when you try to convert ; text that's not a number, into a number. ; Value = "ABC" ; ; As said before, you cannot store text in an integer variable. ; So the text will be converted to a number. ; If the text is not a number, it will be converted to 0. (eek) ; ; So when the whole grid contains empty strings, ; you will get a grid of zeroes ; when converting each field to a number. ; ; So each color field contains Color_Red (zero) ; after converting it to a number. ; Also there's no need to convert the character field ; so now each character field contains just "" (empty). ; ; But what if we tried to compare a string with a number? ; Like we want to know what color we have stored. ; And currently all color fields contain "" (empty). ; Value = 0 If Value = "" Then Print "Zero is equal to Empty" ; ; Apparently Blitz doesn't think ; zero is equal to empty. ; ; However, if you really want to, ; you can force a conversion, ; like this: ; ConvertedValue = "" If Value = ConvertedValue Then Print "Zero is equal to (converted) Empty" ; ; or like this: ; If Value = Int ( "" ) Then Print "Zero is equal to (converted) Empty" ; ; These are the available conversion tools: ; ; Integer Int () ; String Str () ; Float Float () ; ; The brackets are optional. ; If Value = Int "" Then Print "Brackets are optional" ; ; So remember this when you're ; converting, glueing or comparing. ; ; Let's put a blue exclamation mark in the upperleft corner. ; Can you think of how to do that? ; Grid3D( 0 , 0 , Grid3D_Color ) = Color_Blue Grid3D( 0 , 0 , Grid3D_Char ) = "!" ; ; Now let's try build a routine to display the grid. ; First, the loops. ; For Y = 0 To 10 For X = 0 To 10 Next Next ; ; At the end of these loops, X and Y will both equal 11. ; So I'll just reset X and Y to 0 ; to prevent going off the grid ; in the code coming up. ; X = 0 Y = 0 ; ; We have to set the color first, ; and then draw the character. ; ; If we find Color_Red on a spot, ; we have to set.. a red color. ; If Grid3D( X , Y , Grid3D_Color ) = Color_Red Color 255 , 0 , 0 End If ; ; If we find Color_Green in a field, ; the current drawing color must be green. ; If Grid3D( X , Y , Grid3D_Color ) = Color_Green Color 0 , 255 , 0 End If ; ; And finally for Color_Blue, blue. ; If Grid3D( X , Y , Grid3D_Color ) = Color_Blue Color 0 , 0 , 255 End If ; ; Ofcourse we won't find any of these ; since each color field contains "" (empty). ; As comparing a "" with any number ; won't be result in a color change. ; ; Okay, now stack them. ; If Grid3D( X , Y , Grid3D_Color ) = Color_Red Color 255 , 0 , 0 End If If Grid3D( X , Y , Grid3D_Color ) = Color_Green Color 0 , 255 , 0 End If If Grid3D( X , Y , Grid3D_Color ) = Color_Blue Color 0 , 0 , 255 End If ; ; No, not like that. ; If Grid3D( X , Y , Grid3D_Color ) = Color_Red Color 255 , 0 , 0 Else If Grid3D( X , Y , Grid3D_Color ) = Color_Green Color 0 , 255 , 0 Else If Grid3D( X , Y , Grid3D_Color ) = Color_Blue Color 0 , 0 , 255 End If ; ; Yeah, that's it. ; ; And maybe you recall a Select Case ; technique for doing that as well. ; Select Grid3D( X , Y , Grid3D_Color ) Case Color_Red Color 255 , 0 , 0 Case Color_Green Color 0 , 255 , 0 Case Color_Blue Color 0 , 0 , 255 End Select ; ; So which character should we display? ; Char$ = Grid3D( X , Y , Grid3D_Char ) ; ; Oooohh.. storing it in a string variable. ; Because if we store it in an integer variable, ; it will be converted to zero if not a number! ; ; Okay, and where should we place the character? ; Hmm.. maths :) ; ; Let's use a distance of 10 pixels for each character. ; Just like before. ; WhereX = X * 10 WhereY = Y * 10 ; ; Maybe not in the upperleft corner of the screen, ; but somewhere more in the middle. ; WhereX = X * 10 + 100 WhereY = Y * 10 + 100 ; ; Text on the screen? ; Text WhereX , WhereY , Char ; ; Good girl. ; ; Now merge'm. ; For Y = 0 To 10 For X = 0 To 10 If Grid3D( X , Y , Grid3D_Color ) = Color_Red Color 255 , 0 , 0 Else If Grid3D( X , Y , Grid3D_Color ) = Color_Green Color 0 , 255 , 0 Else If Grid3D( X , Y , Grid3D_Color ) = Color_Blue Color 0 , 0 , 255 End If Char = Grid3D( X , Y , Grid3D_Char ) WhereX = X * 10 + 100 WhereY = Y * 10 + 100 Text WhereX , WhereY , grid3d(x,y,grid3d_color) Next Next WaitKey ; ; You should see a red liney thingy somewhere, ; which would be the red exclamation mark. ; If not, you probably didn't copy and paste enough code :) ; ; As before, you can get rid of the Char, ; WhereX and WhereY variables. ; It's all up to you :) ; ; Try playing around some more ; with the grid, colors and text. ; Practice makes perfect ;) ; ;----------------------------------------------------------------------------------------------------------------------- ; ; There's a way to easily store a tilemap in your code. ; .Tilemap Data 10 , 10 ; Dimensions Data Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Free , Free , Free , Free , Free , Free , Free , Free , Wall Data Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall , Wall ; ; Ofcourse you could also use ones and zeroes. ; ; Blitz will store each data element in sequential order; ; from left to right, and from top to bottom: ; ; .Tilemap: 10 -> 10 -> Wall -> Wall -> Wall -> etc.. ; ; It's a lot like the Blitz program cursor ; which reads your program from top to bottom. ; ; You can use the Restore command ; to position the data reading cursor ; at the first Data statement ; under the specified Label. ; Restore Tilemap ; ; By default the data reading cursor ; starts from the top of your program. ; ; You can read data elements using the Read command. ; ; Read Value ; Reads the next value from data. ; ; So you can first read the dimensions of the tilemap. ; Read Tilemap_SizeX Read Tilemap_SizeY ; ; Then erase and resize the tilemap ; using these new dimensions. ; Dim Tilemap( Tilemap_SizeX , Tilemap_SizeY ) ; ; Now, if you would use a double loop ; you could read in the entire tilemap. ; For Y = 1 To Tilemap_SizeY For X = 1 To Tilemap_SizeX ; Read the next data element ; and put its value in a variable of your choice. Read Tilemap( X , Y ) Next Next ; ; I guess you know how to display it on screen :) ; ;----------------------------------------------------------------------------------------------------------------------- ; ; Let's clear the screen and reset the colors ; so we can use some simple commands again ; to go easy on the brain :P ; ClsColor 0 , 0 , 0 Cls Color 255 , 255 , 255 ; ; To go to the next level, pointanoids, ; we need to go back to the basics. ; And replay all that has passed. ; ; An integer variable. ; Integer_Variable% = 1000 ; ; +---------------+ ; | | ; | 1000 <---- ; | | ; +---------------+ ; | Integer var. | ; +---------------+ ; ; A floating point variable. ; FloatingPoint_Variable# = 1.000 ; ; +---------------+ ; | | ; | 1.0 <---- ; | | ; +---------------+ ; | Float var. | ; +---------------+ ; ; A string variable. ; String_Variable$ = "1.000,00" ; ; | | | | | | | | ; v v v v v v v v ; | | | | | | | | | ; | 1 | . | 0 | 0 | 0 | , | 0 | 0 | ; +---+---+---+---+---+---+---+---+-- - ; | String variable ; +------------------------------ -- - ; ; An array of integers. ; Const NumberOfElements% = 3 ; Dim ArrayOfIntegers%( NumberOfElements ) ; ; | | | | ; +----- v -----+----- v -----+----- v -----+----- v -----+ ; | | | | | ; | 0 | 0 | 0 | 0 | ; | | | | | ; +---------------+---------------+---------------+---------------+ ; | Integer | Integer | Integer | Integer | ; +---------------+---------------+---------------+---------------+ ; | Array of integer variables | ; +---------------------------------------------------------------+ ; ; An array of floats. ; Dim ArrayOfFloats#( NumberOfElements ) ; ; | | | | ; +----- v -----+----- v -----+----- v -----+----- v -----+ ; | | | | | ; | 0.0 | 0.0 | 0.0 | 0.0 | ; | | | | | ; +---------------+---------------+---------------+---------------+ ; | Float | Float | Float | Float | ; +---------------+---------------+---------------+---------------+ ; | Array of floating point variables | ; +---------------------------------------------------------------+ ; ; And finally, an array of strings. ; Dim ArrayOfStrings$( NumberOfElements ) ; ; | | | | ; v v v v ; | | | | ; | | | | ; +---+-- - +---+-- - +---+-- - +---+-- - ; | String | String | String | String ; +-----------+-----------+-----------+-----------+ ; | Array of string variables | ; +-----------------------------------------------+ ; ; or ; ; +---------------+ ; | | ; | String 0 <---- ; | | ; +---------------+ ; | | ; | String 1 <---- ; | | ; +---------------+ ; | | ; | String 2 <---- ; | | ; +---------------+ ; | | ; | String 3 <---- ; | | ; +---------------+-----------+ ; | Array of string variables | ; +---------------------------+ ; ; Remember our array of colors and characters? ; ; Dim Grid3D( X , Y , Index ) ; ; You can also look at it like ; each element on the 2D grid (!) ; having multiple fields so to speak: ; ; Color (string) ; Character (string) ; ; So far we were using constants as: ; ; State identifier ; ; Const State = .. ; ; What_Are_We_Doing = State ; Select What_Are_We_Doing ; Case State ; .. ; ; Count identifier ; ; Const Count = .. ; ; NumberOfApples = Count ; Dim Array( Count ) ; ; Index identifier ; ; Const Index = .. ; ; Array( Index ) = Value ; ; Each element in an array ; has to be of the same type. ; ; So what if you wanted more ; different types of fields? (err) ; ; Or what if you wanted just ; a player with various attributes? ; Local PlayerName$ Local PlayerSpeed# Local PlayerHealth% ; ; And what if you wanted to have more than one player? ; Local Player1_Name$ Local Player1_Speed# Local Player1_Health% Local Player2_Name$ Local Player2_Speed# Local Player2_Health% ; ; And what if you wanted to walk through ; over 100 players with a For..Next loop? ; Dim Player_Name$( 100 ) Dim Player_Speed#( 100 ) Dim Player_Health%( 100 ) ; ; And what if there could be ; any number of players? ; - You can resize an array. ; Yes, but the contents will be lost ; when you resize it. ; - Use a second array to copy the contents. ; Okay and what if you had 5 players ; and player 3 had to go? ; How would you do that? ; - Manually re-arrange the contents ; of the array by using a sorting algorithm. ; Smart ass :P ; ; There's a far more easier approach ; than all of the above. ; ; Imagine a list containing any number of objects ; where each object contains anything you want. ; ; For each object you can use a mould, a template, ; a structure or a blueprint if you will. ; ; So in the case of our player: ; Type Player Field Name$ Field Speed# Field Health% End Type ; ; This is like our design plan for one player. ; ; You can create an existing copy of this Type, ; by using the New command. ; ; New Player ; New (Type) ; ; The only problem is, ; we need to stick it in a variable. ; Otherwise we can't do anything with it. ; In fact, Blitz will give you an error ; if you don't to assign it to a variable. ; ; The variable we stick it in has to be ; of the same type as the thing we're creating. ; Blitz is very strict in this, ; unlike strings, integers etc. ; ; To confuse you even further, ; the variable doesn't really contain the thing, ; it just points to the thing, ; so you can modify the thing, ; as well as change its contents. ; Local PointerToPlayer.Player ; ; Yes, a pointer variable. ; Or to be more precise, ; a pointer to Player variable. ; ; When a pointer variable is first created, ; it actually doesn't point to anything, ; which is called Null. ; If PointerToPlayer = Null Print "Yup, nothing there" End If ; ; If you would create a player object, ; imagine that this is what it would look like: ; ; +---------------+---------------+-------------------+ ; | Name (string) | Speed (float) | Health (integer) | ; +---------------+---------------+-------------------+ ; | Player object | ; +---------------------------------------------------+ ; ; If you compare it with the other schematics ; of the single variables and arrays above, ; you'll see that the arrow is missing. ; It indicates there's no way we can use it, yet. ; ; Here's what our pointer PointerToPlayer currently looks like: ; ; | ; | v | ; +---------------------------------------------------+ ; | Player object (Null) | ; +---------------------------------------------------+ ; ; The arrow is there, ; but the object is not :P ; E.g. the type is set, ; but it ain't pointing to any object. ; ; So let's make it point to something that exists. ; PointerToPlayer = New Player ; (Pointer).(Type) = New (Type) ; ; Yes, you don't have to include the type of a variable ; once it has been defined, remember? ; Just like with strings, floats and integers. ; If PointerToPlayer <> Null Print "Something's there!" End If ; ; Now that the pointer is actually pointing to something, ; we can change the contents of what it's pointing to. ; E.g. the contents of the Player object. ; PointerToPlayer\Name = "Dr. I.M. D'humb" PointerToPlayer\Speed = 5.1 ; (Pointer).(Type)\(Field) = (Value) PointerToPlayer\Health = 100 ; ; The backslash (\) allows you to access a field. ; And you can use these fields just like ; any other variable (string, float, etc). ; ; | | | ; v v v ; +----- -----+----- -----+------- -------+ ; | Name (string) | Speed (float) | Health (integer) | ; +---------------+---------------+-------------------+ ; | Player object | ; +---------------------------------------------------+ ; ; Well.. for the rest all you can do is.. ; Delete it! :P ; Delete PointerToPlayer ; Delete (Pointer).(Type) ; ; Okay, not very useful at this point, ; but you get the idea. ; ; Note that the player object was deleted, not the pointer. ; E.g. you can't delete variables :) ; ; Also, the pointer variable PointerToPlayer ; is now pointing to.. Null.. again. ; ; | ; | v | ; +---------------------------------------------------+ ; | Player object (Null) | ; +---------------------------------------------------+ ; ; Blitz keeps track of all objects you created. ; So you don't have to worry (too much) ; when you're not keeping track of every single object yourself. ; ; | | | ; v v v ; +----- -----+ +----- -----+ +----- -----+ ; | Player object | | Player object | | Player object | ; +---------------+ +---------------+ +---------------+ ; ; Considering that, ; can you tell me what happens ; in the code below? ; PointerToPlayer = New Player PointerToPlayer = Null ; ; In the first line ; a new Player object is created, ; and PointerToPlayer is pointing to it. ; ; In the second line ; we manually make the pointer point to ; a non-existing object (Null). ; ; But the object is still floating somewhere. ; And because Blitz keeps track of all objects ; there is a way we can find out exactly where it is. ; ; In fact, you can walk through ; an entire collection of objects, ; using a single pointer variable. ; It's a bit like walking through an array ; using a single integer variable. ; ; | ; v ; +----- -----+ ; | Player object | ; +---------------+--+ ; | Player object | ; +---------------+--+ ; | Player object | ; +---------------+ ; ; Also, like with arrays, ; Blitz keeps track of the order of objects. ; For example; the first time we created a player object, ; it would be the first object. ; ; +-+-----+ ; | | | ; | | 1 | ; | | | ; +-+-----+ ; ; All objects created after it would stack up behind it. ; ; +-+-----+ +-+-----+ +-+-----+ ; | | | | | | | | | ; | | 1 | ----> | | 2 | ----> | | 3 | ; | | | | | | | | | ; +-+-----+ +-+-----+ +-+-----+ ; ; Now, let's go fishing for our lost player object. ; We can use the First keyword to retrieve ; the first object in the list. ; PointerToPlayer = First Player ; (Pointer).(Type) = First (Type) ; ; +-+-----+ ; | | | ; ---->| 1 | ; | | | ; +-+-----+ ; ; Yes, there is also the keyword Last ; to retrieve the last object from the list. ; It works in exactly the same way. ; ; Ofcourse if there is no first or ; last object in the list, ; all you get is Null. ; E.g. the pointer will point to ; a non-existing object. ; ; Let's put this player object to (some) use. ; PointerToPlayer\Name = "First Player" PointerToPlayer\Speed = 0 PointerToPlayer\Health = Rand ( 1 , 100 ) ; ; Rand () creates random numbers ; in the range of your choice. ; So the player above will have a random amount of health ; ranging somewhere between 0 and 101. (From 1 to 100) ; ; Unfortunately the random numbers generated are not really random. ; In fact, you could say they're completely fake. ; Everytime you ask for a random number ; you get the next number in a certain pattern. ; You can control what this pattern looks like ; with a so called seed value. ; SeedRnd 0 ; ; Here, a seed value of 0, would give you the same ; pattern every time from this point. ; So if you'd put this at the top of your program, ; you would get the same random number order every time. ; What if we wanted different random numbers every time? ; SeedRnd MilliSecs () ; ; MilliSecs () will give you ; the number of milliseconds ; since Windows started. ; ; Because you won't be running the program ; on exactly the same millisecond every day, ; it will seem that the random numbers are indeed.. random :) ; E.g. the pattern will be based on the current millisecond. ; ; So now you'll get a (supposedly) fresh random pattern ; every time you run the program. ; ; Okay, allow me to create a bunch of other players ; with some added random values. ; For PlayerNumber = 2 To 10 PointerToPlayer = New Player PointerToPlayer\Name = "Player " + PlayerNumber ; (text-glue) PointerToPlayer\Speed = Rnd ( 1 , 5 ) PointerToPlayer\Health = Rand ( 1 , 100 ) Next ; ; Is that a typo? ; No, Rnd () works similar to Rand (). ; Rand () returns integer values (1, 2, 3, etc). ; And Rnd () returns floating point values (0.73, 1.8651, etc). ; ; You do not *have* to specify a minimum and maximum value. ; You can also do this: ; Random_Int = Rand ( 10 ) ; In range of 1 and 10. Random_Float = Rnd ( 10 ) ; Between 0 and 10. ; ; Note that in the above cases ; Rnd () starts at 0 while Rand () starts at 1. ; ; Through all the distractions, ; do you know how many Player objects we have now? ; We still have a player called First Player. ; And we created 9 more players with unique names. ; So we have 10 Player objects. ; ; You can walk through the entire collection of objects ; using a single pointer to Player type variable. ; ; | ; v ; +----- -----+ +---------------+ +---------------+ ; - --| Player object |---| Player object |---| Player object |-- - ; +---------------+ +---------------+ +---------------+ ; ; Like mentioned before, it is actually very similar to ; looping through an array with one integer variable. ; ; | ; v ; +--- ---+ +-----------+ +-----------+ ; - --| Element |---| Element |---| Element |-- - ; +-----------+ +-----------+ +-----------+ ; ; And it's also similar to the above loop ; where we used 1 pointer variable to create 9 objects. ; For PointerToPlayer = Each Player ; For (Pointer).(Type) = Each (Type) Number = Number + 1 Write Number + ": " Print PointerToPlayer\Name Next WaitKey ; ; You can use the Each keyword to ; walk through all objects of the same type. ; ; E.g. the PointerToPlayer variable will point ; to every object in the list. ; ; So inside the For..Next you can access ; each object, one at a time. ; ; Each next object in the list ; will be fetched for you, ; and PointerToPlayer ; will point to it. ; ; It also possible to do this manually. ; Imagine a simple For..Next loop. ; ; For Element = 1 to 10 : Next ; ; You can also increment by hand. ; ; Element = 1 ; Repeat ; Element = Element + 1 ; Until Element = 11 ; ; Same goes for objects. ; Automatically: ; ; For Pointer = Each Type : Next ; ; Manually: ; ; Pointer = First Type ; Repeat ; Pointer = After Pointer ; (Pointer).(Type) = After (Pointer).(Type) ; Until Pointer = Null ; ; The After keyword can be used to ; go to the next object in the list. ; E.g. the object behind the ; object it's currently pointing to. ; PointerToPlayer = First Player Repeat PointerToPlayer = After PointerToPlayer Until PointerToPlayer = Null ; ; If there's After, there's also Before. ; So you can do the same thing backwards. ; Let's try that with a While..Wend loop. ; PointerToPlayer = Last Player While PointerToPlayer <> Null PointerToPlayer = Before PointerToPlayer Wend ; ; Okay, what if you want to move ; objects in the list around? ; ; There is the Insert keyword to assist you. ; There are 10 players currently, right? ; So how do you place the first player (1) ; behind the last player (10)? ; ; Initialize variables. Local FirstPlayer.Player Local LastPlayer.Player ; Locate first and last objects in list. FirstPlayer = First Player LastPlayer = Last Player ; Place first object behind last object. Insert FirstPlayer After LastPlayer ; ; It's almost real english :) ; Let's test what our first object is, ; just to be sure. ; FirstPlayer = First Player Print Print "First object name: " + FirstPlayer\Name ; ; Which should give you the name of Player 2 :) ; ; However, you don't always have to assign ; a variable to use an object. ; Sometimes you can combine keywords ; like there's no tomorrow. ; Insert Last Player Before First Player ; ; Do you know what we just did? ; That's right, we moved player named First Player ; back to its original spot. ; ; You can use Insert also, for example, ; to arrange objects in a certain order. ; ; But you don't always have to rely on ; the keywords First, Last, Before, After etc. ; Pointers will be pointers. ; You can use them in any way you want. ; ;----------------------------------------------------------------------------------------------------------------------- ; ; There are some common cases ; where you'll want to administer ; all your objects by hand. ; ; Imagine a game with players shooting at enemies. ; And enemies shooting at players. ; ; So you'd need players (just like before). ; ; Type Player ; Field Located_Where ; Field Doing_What ; End Type ; ; As well as enemies. ; ; Type Enemy ; Field Located_Where ; Field Doing_What ; End Type ; ; Now, they can shoot, ; so we'd need to store bullets. ; ; Type Bullet ; Field Located_Where ; End Type ; ; All looking good ; but what if players' shots ; would hurt only enemies ; and vise versa? ; ; So you'd have to know ; who's the owner of a bullet. ; A player, or an enemy. ; ; One way is forgetting ; the old Bullet type structure ; and just using 2 separate ones. ; One for each group (players and enemies). ; ; Type Player_Bullet ; Field Located_Where ; End Type ; ; Type Enemy_Bullet ; Field Located_Where ; End Type ; ; Still looking good ; but it's not so funny ; when there's different types of ; players, enemies and bullets. ; ; So we add a field ; to our original Bullet type ; to know who the owner is ; e.g. which group the bullet belongs to. ; ; Const Bullet_Of_Player = 1 ; Const Bullet_Of_Enemy = 2 ; ; Type Bullet ; Field Of_Whom ; <--- ; Field Located_Where ; End Type ; ; Now what if there are thousands of bullets ; and you don't want to loop through all bullets every time ; and still use just one type of bullet. ; ; You can't do this if you rely on Blitz' keywords. ; This may not be something that happens in your game. ; And most (simple) games will only need Blitz' keywords. ; Remember that pointers will be pointers. ; You can use them in any way you want. ; ; So, here's another solution: ; ; Type Bullet ; Field Located_Where ; End Type ; ; Type Player ; Field Located_Where ; Field Doing_What ; Field FirstBullet.Bullet ; <--- ; End Type ; ; Type Enemy ; Field Located_Where ; Field Doing_What ; Field FirstBullet.Bullet ; <--- ; End Type ; ;----------------------------------------------------------------------------------------------------------------------- ; ; So far we've seen simple variable types as a field ; but you can also place a pointer variable in there. ; Type Link Field PointerToNextLink.Link End Type ; ; Now we can make our own chain of links. ; FirstLink.Link = New Link ; ; FirstLink ; | ; v ; ,---. ; / \ ; ( ; \ / ; `---' ; AnotherLink.Link = New Link ; ; FirstLink ; | AnotherLink ; v | ; ,---. v ; / \ _.---._ ; ( ( ; \ / `^---^^ ; `---' ; FirstLink\PointerToNextLink = AnotherLink ; ; FirstLink ; | AnotherLink ; v | ; ,---. v ; / _>---._ ; ( ( ) ; \ ^>---^^ ; `---' ; AnotherLink = Null ; ; FirstLink ; | ; v ; ,---. ; / _>---._ ; ( ( ) ; \ ^>---^^ ; `---' ; ; So long as you keep track of the root ; or your own first link of the chain, ; you will be able to find any link in the chain ; without having to use any of the keywords. ; ; How? ; AnotherLink = FirstLink\PointerToNextLink ; ; Actually the reversed of what we did before. ; And you can make it really hairy if you wanted to. ; ; FirstLink\PointerToNextLink\PointerToNextLink\PointerToNextLink\ etc.. ; ; Let's add another link to the chain, ; using the same pointer variable. ; AnotherLink = New Link ; ; FirstLink AnotherLink ; | | ; v v ; ,---. ,---. ; / _>---._ / \ ; ( ( ) ( ; \ ^>---^^ \ / ; `---' `---' ; FirstLink\PointerToNextLink\PointerToNextLink = AnotherLink ; ; FirstLink AnotherLink ; | | ; v v ; ,---. ,---. ; / _>---<_ \ ; ( ( ) ( ) ; \ ^>---<^ / ; `---' `---' ; AnotherLink = Null ; ; FirstLink ; | ; v ; ,---. ,---. ; / _>---<_ \ ; ( ( ) ( ) ; \ ^>---<^ / ; `---' `---' ; ; You'll probably want to iterate ; through the manual list easily. ; E.g. walk through each object in ; our home made list, one at a time. ; ; So here's an example While..Wend loop to ; demonstrate how you can walk through ; all links in the chain. ; ; This will be our iterator. Local PointerToLink.Link ; Find our first link. PointerToLink = FirstLink While PointerToLink = Null ; Point to next link in chain. PointerToLink = PointerToLink\PointerToNextLink Wend ; ; You could add another pointer variable ; to point to the object before the current object ; to make searching through the list faster. ; ; Ofcourse this chain of links contains only a pointer variable ; so there's no real use for this chain of links ; as we can't really put some useful information in each link. ; ;----------------------------------------------------------------------------------------------------------------------- ; ; So let's put a manual linked list to good use ; and add at least one useful field. ; Type Element Field pNext.Element Field iValue% End Type ; ; Another idea is to use one (or more) letter ; of the variable name to know what type it is. ; Some examples: ; ; iValue ; Integer ; sName ; String ; fSpeed ; Float ; pNext ; Pointer ; ; Now create a random bunch of objects, ; put some random stuff in them ; and rack'em up (link the chain). ; ; Initialize variables. Local iElementCount% Local iElement% Local pRoot.Element Local pNext.Element ; Create a root element. pRoot = New Element pRoot\iValue = Rand ( 100 ) ; Place elements behind it. pNext = pRoot iElementCount = Rand ( 10 , 20 ) For iElement = 1 To iElementCount pNext\pNext = New Element pNext\pNext\iValue = Rand ( 100 ) pNext = pNext\pNext Next ; ; Let's see what we generated. ; iElement = 0 pNext = pRoot While pNext <> Null iElement = iElement + 1 Print iElement + ": " + pNext\iValue pNext = pNext\pNext Wend Print WaitKey ; ;----------------------------------------------------------------------------------------------------------------------- ; ; There's one more type of field you can use. ; Type Inventory Field Slots[ 10 ] End Type ; ; It's called a BlitzArray[tm]. ; And it works similar to regular arrays. ; Inv.Inventory = New Inventory Inv\Slots[ 0 ] = 293 ; (Pointer).(Type)\Array[ Element ] = Value ; ; The major difference is that ; you cannot redimension it ; e.g. you can't change its size ; or instantly free its contents ; so its size has to be constant. ; Const Amount = 100 ; Type Ship Field Weapons[ Amount ] Field Engine Field Generator Field Hull Field Shield End Type ; ; If you remember normal arrays ; you'll know that we actually created ; an array of integers. ; ; And if I told you that you can use ; any type of field as a regular variable, ; would that also mean you can create ; a BlitzArray[tm] as a regular variable? ; Local Weapons[ Amount ] ; ; Yes! :) ; Global Inventory$[ 10 ] ; ; A (global) BlitzArray[tm] of strings. ; Inventory[ 1 ] = "Gold coin" ; ; Ofcourse BlitzArrays[tm] are most useful ; in scenarios where the size of the array ; remains constant throughout the game. ; ; Otherwise regular arrays will be an excellent choice. ; Even though regular arrays are always Global. ; ;----------------------------------------------------------------------------------------------------------------------- ; ; So you can have arrays of certain types; ; string, float and integer. ; But what about pointers? ; Type Thing Field Contents End Type ; Dim PointerArray.Thing( 0 ) ; Dim Array.Type( Elements ) ; ; Look! ; An array of pointers! ; Do you see that it looks just like ; an array of a different type? ; Dim StringArray$( 0 ) ; ; Let's do something with the first element. ; PointerArray( 0 ) = New Thing PointerArray( 0 )\Contents = 2004 ; Array.Type( Element )\Field = Value ; ; Remember what happens when we redimension the array? ; Its contents gets erased. ; Dim PointerArray( 1 ) ; Contains 2 elements. ; ; But what we have here is an array of pointers. ; So the actual objects were not erased. ; ; If you remember the First keyword ; you'll know how to retrieve the first object. ; PointerArray( 0 ) = First Thing ; ; So when we display the contents ; it should be 2004, right? ; Print PointerArray( 0 )\Contents WaitKey ; ; What about BlitzArrays[tm]? ; Const Alot = 10000 ; Local BlitzArray_WithPointers.Thing[ Alot ] ; BlitzArray_WithPointers[ 9999 ] = PointerArray( 0 ) ; ; See how you can combine everything with everything? ; Mix and blend as you see fit :) ; ;----------------------------------------------------------------------------------------------------------------------- ; ; Sometimes that can become difficult though. ; Even though Blitz is a very intelligent language, ; it won't always know what you're talking about :P ; ; You'll remember text glue, ; Print "Where " + "Am " + "I ?" ; ; and how to convert text to a value. ; TextValue$ = "5000" ; Auto Value = TextValue ; Manual Value = Int ( TextValue ) ; ; Sometimes you can't rely on automatic ; conversion because Blitz won't understand ; your mysterious ways. ; Print "-Glue-" ; Print Value1 + Value2 ; /|\ ; | ; Number glue ; Print Value1 + "" + Value2 ; /|\ /|\ ; | | ; Text glue ; Print Str ( Value1 ) + Str ( Value2 ) ; /|\ ; | ; Text glue ; ; And floats with integers. ; Print "-Conversion-" ; ; Just integers, not accurate. Value = 10 / 3 * 10 Print Value ; ; Converted to float, accurate. Value = Float 10 / 3 * 10 Print Value ; ; Using a float instead of integer, accurate. Value = 10.0 / 3 * 10 Print Value ; ; Changed priority, accurate. Value = 10 * 10 / 3 Print Value ; ; Actually, you can do the same with pointers. ; Type Any Field Thing# End Type ; pAny.Any = New Any pAny\Thing = -3.14 ; ; There's the Handle keyword to convert to a number. ; Value = Handle pAny ; hType = Handle ( Pointer.Type ) Print Value ; ; Technically what you'll get ; is a unique memory address ; for the pointer. ; ; This way you can keep track ; of pointers by storing their address ; instead of just pointers. ; ; The Object keyword converts ; the address back to a pointer. ; pAny = Object.Any Value ; Pointer.Type = Object.Type ( hType ) ; ; I've used hType to indicate ; it's a handle (address, number, value) ; of a pointer of this type. ; ; And pAny would mean ; a pointer to an object of type Any. ; But you probably already knew that :) ; ; You can also use this approach ; to test any number against any type. ; ; So you could for example store ; *different* types of objects ; in a regular array of integers. ; ; Write "It's a" ; If Object.Engine Array( Element ) <> Null ; Print "n engine." ; Else If Object.Generator Array( Element ) <> Null ; Print " generator." ; Else If Object.Weapon Array( Element ) <> Null ; Print " weapon." ; Else If Object.Shield Array( Element ) <> Null ; Print " shield." ; End If ; ; Handle and Object work exactly ; the same as Int, Str and Float. ; ;-----------------------------------------------------------------------------------------------------------------------