Functions are integral to any program. Even in the programs you have been writing so far, you have used functions such as Print and Delay, and you have even written your own implicit main function. This section teaches you how to write your own functions that will make understanding and writing your program much easier and simpler.
Functions are small snippets of code that usually perform a single task. All programs consist of at least one function: main. Although main isn’t actually defined, it still exists within the program.
Every line of code written so far (with the exception of the ones in Chapter 1) has been written in the function main. This function is the starting point and ending point of every Blitz3D program. Figure 3.7 shows an example of the main function in action. Because the main function is never formally declared, I always write a comment telling myself where it begins. I suggest you do the same.
Main calls two types of programs to do its work: user-defined and program-defined functions. User-defined functions are those that are written by the programmer. All of these functions must be defined before they are used. Program-defined functions are defined within the compiler, like the function Print. All of these have already been written; all you have to do is call them with the proper parameters.
A parameter is a piece of information sent to the function to tell it what to do. For example, the string$ variable is a parameter to the Print function. This variable tells Print what you want printed to the screen.
You can send parameters to your own functions as well, but make sure that you declare the parameters in advance. If your function is called with an extra parameter, your code will not compile.
To use any function, you first must declare it. The function declaration is usually written directly before the function code.
Function functionname([parameter variable,])
Looks kind of complex, huh? Let’s make this easy. First type Function. This is required for every function declaration. Now, pick a function name (make sure it describes what the function does; for example, if it counts, call it Count). Now, add an open parenthesis. Add as many parameter variables as you need, each separated by a comma. Finally, add an ending parenthesis.
Here is an example
Function ConvertFtoC (fvalue)
This function most likely converts a Fahrenheit value to a Celsius value. You can see that by looking at the function’s name. Make sure yours are easy to understand too.
Next, you write the actual function code.
Return (5.0/9.0 * (fvalue - 32))
Remember that the * sign means multiplication and the / sign means division. This code returns the Celsius value of the variable sent. A return value is any number or string returned by a called function. For example, on the KeyHit() function, either a one or a zero is returned. Here, the returned value is the Celsius equivalent to the Fahrenheit number.
Finally, we end the function.
End Function
We now need a main function call to actually use this function.
Print "Welcome to our FtoC converter" fvalue = Input$("What Fahrenheit value do you wish to convert?") cvalue = ConvertFtoC(fvalue) Print fvalue + " Fahrenheit = " + cvalue + " Celsius."
This section of code is the actual main program. It starts off by introducing the program and receiving the Fahrenheit value to convert. Next it calls ConvertFtoC() and stores its value in the variable cvalue. Finally it prints the results.
Let’s put all these parts together now.
;demo03-06.bb - Converts Fahrenheit to Celsius ;MAIN PROGRAM Print "Welcome to our FtoC converter" ;get Fahrenheit and put it in fvalue fvalue = Input$("What Fahrenheit value do you wish to convert? ") ;Convert fvalue to Celsius cvalue = ConvertFtoC(fvalue) ;print results Print fvalue + " Fahrenheit = " + cvalue + " Celsius." ;Delay for five seconds Delay 5000 ;END OF MAIN PROGRAM Function ConvertFtoC(fvalue) ;convert value and return it Return 5.0/9.0 * (fvalue - 32) End Function
Figure 3.8 shows the output of this program.
And that’s all there is to functions. Well, almost ...
There are two possible scopes in Blitz3D: global and local. Global variables are visible throughout the program, in every function and every line of code. Local variables are valid only in the function in which they are defined. This means that a variable defined within one function is not valid in another.
What Is Scope?
Scope is kind of hard to understand, so to help, I went to http://www.dictionary.com and looked up scope. Here is what it said:
“The scope of an identifier is the region of a program source within which it represents a certain thing. This usually extends from the place where it is declared to the end of the smallest enclosing block (begin/end or procedure/function body). An inner block may contain a redeclaration of the same identifier, in which case the scope of the outer declaration does not include (is “shadowed” or “occluded” by) the scope of the inner.”
What? If you finished reading that (20 bucks says you gave up after “program source within which it represents a certain thing”), you are probably as lost as you were before.
Scope is a range of operation from where variables can be referenced. The fact that there are two kinds of scopes allows programmers to create programs that have two or more variables with the same name. You can have one variable with the name variablex in the global scope (otherwise known as the main program) and another variable named variablex in the function HiIAmAFunction(). Even though every other part of the program, including other functions, will use the global scope’s version of variablex, HiIAmAFunction() will use its separate, more specialized, version of variablex.
By the way, Scope is also a mouthwash.
Let me show you an example of scoping. Note that this code will not work. It is only used to demonstrate scope problems.
;CallMe() - Broken CallMe() Print x Function CallMe() x = 314 End Function
The example output is shown in Figure 3.9.
As you can see, this program calls CallMe() and x is assigned to 314. Then it tries to print x, but it ends up printing 0! What gives?
You guessed it—scope. This function calls CallMe() and has x assigned to 314. But when it returns back to main, the 314 has been flushed from memory. Although x is equal to 314 in CallMe(), it is equal to 0 in main.
There are a few ways to fix this. One way is to have CallMe() return a value like this:
CallMe() Print "x is equal to " + CallMe() Function CallMe() x = 314 Return x End Function
In this example, CallMe() returns the x value, which is printed by main.
The other way to solve this problem is to use global variables. Global variables have global scope and are visible throughout the program. This means that the scope of x in CallMe() will be the same as the scope of x in main.
To create a global variable, simply precede the variable with the Global command.
;demo03-07.bb - Fixed CallMe() Global x CallMe() Print "x is equal to " + x ;Delay five seconds Delay 5000 Function CallMe() x = 314 End Function
The example output is shown in Figure 3.10.
Note
Notice that I wrote Global x in the main program rather than the function CallMe(). This is because you can only create global variables in the main program. If you want to use global scope, you must create the variable in the main program. By the way, the act of creating a variable without actually setting the variable is called declaring. Making the variable equal to something is called defining it.
This time, we make x global. Then, when we assign 314 to x, x is equal to 314 in every function, and not just in CallMe()
What Is Portable Code?
Porting is an important concept, because in the long run, it can save you a lot of time. In English, for something to be portable, it must be able to easily move around. Think of that Game Boy Advance you saw at Walmart a few days ago. Portable code is easy to move around. Portable code is independent code that doesn’t rely upon global variables for information. This allows you to cut and paste functions from one program to another. Take the demo03-06.bb, the Fahrenheit-to-Celsius calculator. That is a very portable function because you can rip that program right out and use it in another program, if the need ever arises. Because the function does not rely on any global variables, you have nothing more to set up. When the function does rely on global variables, it is extremely hard to cut and paste code from one program to another, simply because global variables usually do not exist in two different programs.
Global variables are common in games, but you should try to use them as little as possible for a few reasons. First, because every function has access to them, it is very easy to change the variable by accident. Second, using global variables makes functions less portable. If a function only uses parameters and local variables, it can be ported to other programs by just copying and pasting. If it uses global variables, you have to go through the code and change any references to global variables that don’t exist in the new program. Although it doesn’t seem like a big deal now, it can be a big pain to have to search through functions when you decide to add them to a new program.
By the way, another way to create a local variable is to add the keyword Local before a variable, such as:
Local x
If you add the Local keyword to x in the previous program
x = 314
the x variable in main will once again equal zero. This is because the local scope takes precedence over the global scope. Therefore, the local version of x is initialized to 314, while the global version is left unaffected.
There is no difference between
Local variable
and
variable
if there is no declared global variable. In other words, when you declare a local variable, you can omit the Local keyword (although you might want to keep it just for clarity and style).
Functions are necessary to programming. You know that you have to use them, but when should you do so?
Use functions whenever you have to perform a task. I know that this is a vague statement to make, but you should have at least a few functions for anything but the most trivial of programs.
Usually, the main function should do little, if any, work. The tasks should be handed to functions. If the task can be subdivided into two or more tasks, be sure to create the extra functions. You can always call functions from within another function.
Here is an example: say you are creating a spaceship game and you have a function to draw everything onscreen. You should probably make separate functions for drawing each part of the game: a separate function for drawing the ships and the bullets. It is possible to subdivide those even more. If you wanted to, you could create separate functions for drawing the bullets from the player and bullets from the enemy. Two more functions would draw the player and the enemy ships.
Basically, if you see a place where a function could be useful, write it. It takes hardly any more code than just putting the task in the main function and it makes your code much more portable, not to mention readable.
18.226.214.128