User Tools

Site Tools


hpl2:tutorials:script:funcdef

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
hpl2:tutorials:script:funcdef [2011/08/14 09:49]
thegreatcthulhu [Solving a basic problem with function pointers]
hpl2:tutorials:script:funcdef [2011/08/15 01:09] (current)
apjjm [Solving a basic problem with function pointers]
Line 8: Line 8:
  
  
-The [[http://​www.angelcode.com/​angelscript/​sdk/​docs/​manual/​doc_datatypes_funcptr.html|Angelscript documentation]] states that //"A function pointer is a data type that can be dynamically set to point to a global function that has a matching function signature as that defined by the variable declaration."​ // In other words, you're making a "type"  ​- something like //int // or //string // - but instead of this type's variables containing //text// or //​numbers//,​ it contains functions - or more specifically, ​ pointers to functions . \\  To understand better what a function pointer is: Consider a box, and this box contains a note telling you to look in another box somewhere else - this is your function pointer, it just contains information on where to look. The other box, the one //​referenced,​ // contains the actual functional information. We can use these "extra boxes" to create variables that can be called just like functions.+The [[http://​www.angelcode.com/​angelscript/​sdk/​docs/​manual/​doc_datatypes_funcptr.html|Angelscript documentation]] states that //"A function pointer is a data type that can be dynamically set to point to a global function that has a matching function signature as that defined by the variable declaration."​ // In other words, you're making a **type** - something like //int // or //string // - but instead of this type's variables containing //text// or //​numbers//,​ it contains functions - or more specifically, ​ pointers to functions . \\  To understand better what a function pointer is: Consider a box, and this box contains a note telling you to look in another box somewhere else - this is your function pointer, it just contains information on where to look. The other box, the one //​referenced,​ // contains the actual functional information. We can use these "extra boxes" to create variables that can be called just like functions.
  
  
Line 17: Line 17:
 funcdef void fdSimpleFunction();​ // Used for pointers to functions which take no arguments and return no vales  funcdef void fdSimpleFunction();​ // Used for pointers to functions which take no arguments and return no vales 
 funcdef int  fdReturningFunction();​ // Used for pointers to functions which return an int and take no arguments. funcdef int  fdReturningFunction();​ // Used for pointers to functions which return an int and take no arguments.
-funcdef int  fdComplexFunction(int,​int); ​ // Used for pointers to functions which of return type int and take two ints as arguments ​ +funcdef int  fdComplexFunction(int,​ int);  // Used for pointers to functions which of return type int and take two ints as arguments
 </​code>​ </​code>​
  
Line 25: Line 25:
  
 <code cpp>void sfHelloWorld() {    <code cpp>void sfHelloWorld() {   
-    AddDebugMessage("​Hello World!",​false); ​ // Outputs: Hello World! +    AddDebugMessage("​Hello World!",​ false); ​ // Outputs: Hello World! 
-+}
 </​code>​ </​code>​
  
Line 34: Line 34:
  
 <code cpp> <code cpp>
-fdSimpleFunction@ functionVar; ​+fdSimpleFunction@ functionVar;​
 </​code>​ </​code>​
  
Line 41: Line 41:
 <code cpp>// We know this line declares our functionVar <code cpp>// We know this line declares our functionVar
 fdSimpleFunction@ functionVar;​ fdSimpleFunction@ functionVar;​
-  ​+ 
 // We now will make this point to sfHelloWorld()! // We now will make this point to sfHelloWorld()!
-@functionVar = @sfHelloWorld; ​+@functionVar = @sfHelloWorld;​
 </​code>​ </​code>​
  
  
-This new line is making //​functionVar//​point to the address of //​sfHelloWorld//​ (in other words, we just put a note in our box saying look into the specific other box for //​sfHelloWorld//​). You are actually saying **"set the handle of function var to the handle of sfHelloWorld"​** - this is why //​functionVar // can be called just like the function, even though it is actually a variable:+This new line is making //​functionVar // point to the address of //​sfHelloWorld//​ (in other words, we just put a note in our box saying look into the specific other box for //​sfHelloWorld//​). You are actually saying **"set the handle of function var to the handle of sfHelloWorld"​** - this is why //​functionVar // can be called just like the function, even though it is actually a variable:
 <code cpp>// If all has gone well: <code cpp>// If all has gone well:
 functionVar();​ functionVar();​
    
 // Does exactly the same as: // Does exactly the same as:
-sfHelloWorld(); ​+sfHelloWorld();​
 </​code>​ </​code>​
  
Line 61: Line 61:
 <code cpp>// Make the type "​fdSimpleFunction"​ <code cpp>// Make the type "​fdSimpleFunction"​
 funcdef void fdSimpleFunction();  ​ funcdef void fdSimpleFunction();  ​
-  ​+ 
 // Output hello world // Output hello world
 void sfHelloWorld() { void sfHelloWorld() {
-    AddDebugMessage("​Hello World!",​false);​+    AddDebugMessage("​Hello World!",​ false);
 } }
-  ​+ 
 void OnStart() {  void OnStart() { 
     // Call the function normally!     // Call the function normally!
-    AddDebugMessage("​Calling the function normally!",​false);​+    AddDebugMessage("​Calling the function normally!",​ false);
     sfHelloWorld(); ​     sfHelloWorld(); ​
-  ​+ 
     // Call the function using our variable!     // Call the function using our variable!
-    AddDebugMessage("​Calling the function using the pointer!",​false);​+    AddDebugMessage("​Calling the function using the pointer!",​ false);
     fdSimpleFunction@ functionVar;​     fdSimpleFunction@ functionVar;​
     @functionVar = @sfHelloWorld;​     @functionVar = @sfHelloWorld;​
     functionVar();​     functionVar();​
-+}
 </​code>​ </​code>​
  
  
 So far, all we have managed to achieve is something we could have done already! Why go through all this hassle, to just call a function we could have called anyway? The next section shows how the variable aspect of the function can be exploited to solve a basic problem. So far, all we have managed to achieve is something we could have done already! Why go through all this hassle, to just call a function we could have called anyway? The next section shows how the variable aspect of the function can be exploited to solve a basic problem.
 +
  
 ==== Solving a basic problem with function pointers ==== ==== Solving a basic problem with function pointers ====
Line 93: Line 94:
 }    }   
 void subFunction() { void subFunction() {
-    // do something... +    //Implementing later... 
-+}
 </​code>​ </​code>​
  
Line 100: Line 101:
 The specification is as follows: At the end of //​bigFunction//​ we want to call a function called //​output1//​. However, //​subFunction//​ should have a random (1/4) chance of making //​bigFunction//​ call //output2// instead. Both the output functions are defined below: The specification is as follows: At the end of //​bigFunction//​ we want to call a function called //​output1//​. However, //​subFunction//​ should have a random (1/4) chance of making //​bigFunction//​ call //output2// instead. Both the output functions are defined below:
 <code cpp>void output1() { <code cpp>void output1() {
-    AddDebugMessage("​Yo!",​false);​+    AddDebugMessage("​Yo!",​ false);
 }    }   
 void output2() { void output2() {
-    AddDebugMessage("​Dawg!",​false);​ +    AddDebugMessage("​Dawg!",​ false); 
-+}
 </​code>​ </​code>​
  
Line 113: Line 114:
 <code cpp>// Create a function definition (which is actually the same as fdSimpleFunction) <code cpp>// Create a function definition (which is actually the same as fdSimpleFunction)
 // Which will matches the signature of both our output functions // Which will matches the signature of both our output functions
-funcdef void fdOutput(); ​+funcdef void fdOutput();
 </​code>​ </​code>​
  
  
-With the second step creating the variable which shall initially point to //output1 // at the start of //​bigFunction. // Next we call//​subFunction // as before, which will change the function pointer. Finally, we will call the function pointed to by the pointer:+With the second step creating the variable which shall initially point to //output1 // at the start of //​bigFunction. // Next we call //​subFunction // as before, which will change the function pointer. Finally, we will call the function pointed to by the pointer:
 <code cpp> <code cpp>
 fdOutput @outputChoice;​ fdOutput @outputChoice;​
Line 124: Line 125:
     subFunction();​     subFunction();​
     outputChoice();​     outputChoice();​
-+}
 </​code>​ </​code>​
  
  
-The subFunction implementation is as follows: +The //subFunction// implementation is as follows:
- +
 <code cpp>void subFunction() { <code cpp>void subFunction() {
     if(RandInt(0,​ 3) == 1)      if(RandInt(0,​ 3) == 1) 
     {     {
-      ​// A 1 in 4 chance of this code being reached +        @outputChoice = @output2;  ​// A 1 in 4 chance of this code being reached
-      @outputChoice = @output2;+
     }     }
-+}
 </​code>​ </​code>​
  
Line 147: Line 145:
 // Which will matches the signature of both our output functions // Which will matches the signature of both our output functions
 funcdef void fdOutput(); funcdef void fdOutput();
- +  
- +// Our output functions ​
-// Our output functions ​/////////// ​+
 void output1() { void output1() {
-    AddDebugMessage("​Yo!",​false);​+    AddDebugMessage("​Yo!",​ false);
 }    }   
 void output2() { void output2() {
-    AddDebugMessage("​Dawg!",​false);​+    AddDebugMessage("​Dawg!",​ false);
  
-///////////////////////////////////​ 
    
 // The actual stuff that does the descision making // The actual stuff that does the descision making
 fdOutput @outputChoice;​ fdOutput @outputChoice;​
 void bigFunction() { void bigFunction() {
-    // Initially point to output 1 +    ​@outputChoice = @output1; ​// Initially point to output 1 
-    ​@outputChoice = @output1       // 1 in 4 of output 2... +    ​subFunction()   // Call with 1/chance ​of changing outputChoice ​ 
-    ​subFunction();​ +    outputChoice(); ​  // Call whichever output has been chosen
-  +
-   outputChoice(); ​  // Call whichever output has been chosen+
  
    
 void subFunction() { void subFunction() {
-    if(RandInt(0,​3)==1) ​+    if(RandInt(0,​ 3) == 1) 
     {     {
-        @outputChoice = @output2; ​   // A 1 in 4 chance of this code being reached+        @outputChoice = @output2; ​   // A 1 in 4 chance of changing the function pointer
     }     }
 } }
    
-void OnStart() { +void OnStart() {      
-    for(int i=0; i<20; i++) bigFunction();  ​// Call bigFunction 20 times - 1/4 chance of output2? +    // Call bigFunction 20 times - notice roughly a 1/4 chance of output2? 
-+    for(int i=0; i<20; i++) bigFunction(); ​  
 +}
 </​code>​ </​code>​
  
Line 189: Line 184:
  
  
-<code cpp>//​This creates a signature called "​SimpleFunction"​ +<code cpp>// This creates a signature called "​SimpleFunction"​ 
-//Which matches functions which take no arguments, and return nothing. +// Which matches functions which take no arguments, and return nothing..
-funcdef void fdSimpleFunction(); ​  +funcdef void fdSimpleFunction(); ​    
-//Such as these example ​functions+// ...such ​as the following sample ​functions
 +// This function will output "hello world"
 void sfHelloWorld() { void sfHelloWorld() {
-//Output hello world +    ​AddDebugMessage("​Hello World!",​ false); 
-AddDebugMessage("​Hello World!",​false);​ + 
-}+// This function will output how many times it has been called ​
 void sfDisplayTimesCalled() { void sfDisplayTimesCalled() {
-    ​//This function will output how many times it has been called +    AddLocalVarInt("​DTC_TimesCalled",​ 1); 
-    ​AddLocalVarInt("​DTC_TimesCalled",​1);​ +    AddDebugMessage("​DisplayTimesCalled,​ called: " + GetLocalVarInt("​DTC_TimesCalled"​) + " times",​ false);
-    AddDebugMessage("​DisplayTimesCalled,​ called: " +  +
-                    ​GetLocalVarInt("​DTC_TimesCalled"​) + " times",​ false); +
-+
-void sfPlayScarySound() { +
-    //Play the sound of an angry brute! +
-    PlayGuiSound("​enemy\\brute\\notice.snt",​1.0f);+
  
 +//This function will play the sound of an angry brute! ​
 +void sfPlayScarySound() {
 +    PlayGuiSound("​enemy\\brute\\notice.snt",​ 1.0f);
 +}
 </​code>​ </​code>​
  
Line 225: Line 219:
  
 <code cpp>void callRandomSimpleFunction() { <code cpp>void callRandomSimpleFunction() {
-    ​//Pick a random index from the array +    uint index = RandInt(0, simpleFunctions.length()-1); ​          ​// Pick a random index from the array 
-    ​uint index = RandInt(0,​simpleFunctions.length()-1);​ +    fdSimpleFunction @functionToCall = simpleFunctions[index]; ​   // Select ​that function 
-    ​//Select that function +    functionToCall(); ​                                            // Call that function 
-    fdSimpleFunction @functionToCall = simpleFunctions[index];​ +  
-    //Call that function +    // Note this can be simplified down to one line: 
-    functionToCall();​ +    // simpleFunctions[RandInt(0,​ simpleFunctions.length()-1)]();​ 
-    //Note this can be simplified down to one line: +}
-    //​simpleFunctions[RandInt(0,​simpleFunctions.length()-1)]();​ +
-+
 </​code>​ </​code>​
  
Line 241: Line 233:
  
 <code cpp>void callEachFunction(string &in asTimerName) { <code cpp>void callEachFunction(string &in asTimerName) {
-//Get the index +    ​uint index = GetLocalVarInt("​simpleFunctionIndex"​); ​   // Get the index 
-uint index = GetLocalVarInt("​simpleFunctionIndex"​);​ +    if(index>​= simpleFunctions.length()) return; ​          // Don't go any further if we have called all the functions 
-//Don't go any further if we have called all the functions +  
-if(index>​= simpleFunctions.length()) return; +    // Access, and call like before: 
-//Access, and call like before: +    fdSimpleFunction @functionToCall = simpleFunctions[index];​ 
-fdSimpleFunction @functionToCall = simpleFunctions[index];​ +    functionToCall(); ​  
-functionToCall();​ +  
-//Increment the index +    AddLocalVarInt("​simpleFunctionIndex",​ 1);        // Increment the index, so the next function ​is called shortly... 
-AddLocalVarInt("​simpleFunctionIndex",​1);​ +    AddTimer(asTimerName,​ 1.0f, "​callEachFunction"​); ​ // Call this function again in 1 second, so the next function is called 
-//Call this function ​again in 1 second +}
-AddTimer(asTimerName,​1.0f,"​callEachFunction"​);​ +
-+
 </​code>​ </​code>​
  
  
-One potential extension for use with sequences is making each function return a float, which can then be used as the delay time before calling the next function. ​Below is a sample script file for this section, don't forget to visit the OnStart routine and uncomment one of the two lines - or you won't see anything+One potential extension for use with sequences is making each function return a float, which can then be used as the delay time before calling the next function. ​The  ​sample script file for this section ​is below, don't forget to visit the OnStart routine and uncomment one of the two lines - or you won't see anything, and additional function is added to loop the //​callRandomSimpleFunction//​ with a timer so it's effects can be seen easier: 
- +<code cpp>// This creates a signature called "​SimpleFunction"​ 
- +// Which matches functions which take no arguments, and return nothing. 
-<code cpp>//​This creates a signature called "​SimpleFunction"​ +funcdef void fdSimpleFunction(); ​ 
-//Which matches functions which take no arguments, and return nothing. + // Such as these sample ​functions:
-funcdef void fdSimpleFunction();​ //Such as these example ​functions+
 void sfHelloWorld() { void sfHelloWorld() {
-//Output hello world +    ​AddDebugMessage("​Hello World!",​ false); ​   // Output hello world 
-AddDebugMessage("​Hello World!",​false);​ +  ​
-}+
 void sfDisplayTimesCalled() { void sfDisplayTimesCalled() {
-    ​//This function will output how many times it has been called +    AddLocalVarInt("​DTC_TimesCalled",​ 1); //Display how many times function was called: 
-    ​AddLocalVarInt("​DTC_TimesCalled",​1);​ +    AddDebugMessage("​DisplayTimesCalled,​ called: " + GetLocalVarInt("​DTC_TimesCalled"​) + " times",​ false);
-    AddDebugMessage("​DisplayTimesCalled,​ called: " +  +
-                    ​GetLocalVarInt("​DTC_TimesCalled"​) + " times",​ false);+
 } }
 void sfPlayScarySound() { void sfPlayScarySound() {
-    ​//Play the sound of an angry brute! +    PlayGuiSound("​enemy\\brute\\notice.snt",​ 1.0f); ​   // Play the sound of an angry brute! 
-    ​PlayGuiSound("​enemy\\brute\\notice.snt",​1.0f);​ +} 
-}  +  
-//We now can create an array of these simple functions for further use. +// We now can create an array of these simple functions for further use.
-//Note that fdSimpleFunction@ is like a type now - like string, or int!+
 fdSimpleFunction@[] simpleFunctions = { @sfHelloWorld,​ @sfDisplayTimesCalled,​ @sfPlayScarySound };  fdSimpleFunction@[] simpleFunctions = { @sfHelloWorld,​ @sfDisplayTimesCalled,​ @sfPlayScarySound }; 
-//Some example uses of this:  +  
-//Calling a random function+// Some example uses of this:  
 +// Calling a random function
 void callRandomSimpleFunction() { void callRandomSimpleFunction() {
-    ​//Pick a random index from the array +    uint index = RandInt(0, simpleFunctions.length()-1); ​          ​// Pick a random index from the array 
-    ​uint index = RandInt(0,​simpleFunctions.length()-1);​ +    fdSimpleFunction @functionToCall = simpleFunctions[index]; ​   // Select ​that function 
-    ​//Select that function +    functionToCall(); ​                                            // Call that function 
-    fdSimpleFunction @functionToCall = simpleFunctions[index];​ +  
-    //Call that function +    // Note this can be simplified down to one line: 
-    functionToCall();​ +    // simpleFunctions[RandInt(0,​ simpleFunctions.length()-1)]();​ 
-    //Note this can be simplified down to one line: +
-    //​simpleFunctions[RandInt(0,​simpleFunctions.length()-1)]();​ +// Using a timer to call one function per second in sequence.
-  +
-//Using a timer to call one function per second in sequence.+
 void callEachFunction(string &in asTimerName) { void callEachFunction(string &in asTimerName) {
-//Get the index +    ​uint index = GetLocalVarInt("​simpleFunctionIndex"​); ​   // Get the index 
-uint index = GetLocalVarInt("​simpleFunctionIndex"​);​ +    if(index>​= simpleFunctions.length()) return; ​          // Don't go any further if we have called all the functions 
-//Don't go any further if we have called all the functions +  
-if(index>​= simpleFunctions.length()) return; +    // Access, and call like before: 
-//Access, and call like before: +    fdSimpleFunction @functionToCall = simpleFunctions[index];​  
-fdSimpleFunction @functionToCall = simpleFunctions[index];​ +    functionToCall();​ 
-functionToCall();​ +  
-//Increment the index +    AddLocalVarInt("​simpleFunctionIndex",​ 1);        // Increment the index 
-AddLocalVarInt("​simpleFunctionIndex",​1);​ +    AddTimer(asTimerName,​ 1.0f, "​callEachFunction"​); ​ // Call this function again in 1 second 
-//Call this function again in 1 second +
-AddTimer(asTimerName,​1.0f,"​callEachFunction"​);​ +// Using a timer to repeatedly call a random function
-}  +
-//Using a timer to repeatedly call a random function+
 void callRandTimer(string &in asTimerName) { void callRandTimer(string &in asTimerName) {
-callRandomSimpleFunction();​ +    ​callRandomSimpleFunction();​ 
-AddTimer(asTimerName,​1.0f,"​callRandTimer"​);​+    AddTimer(asTimerName,​ 1.0f, "​callRandTimer"​);​
  
 void OnStart() { void OnStart() {
-//Uncomment one of the following to test it out! +    ​// Uncomment one of the following to test it out! 
-//​callEachFunction("​testTimer1"​);​ +    //​callEachFunction("​testTimer1"​);​ 
-//​callRandTimer("​testTimer2"​);​+    //​callRandTimer("​testTimer2"​);​
 } }
 </​code>​ </​code>​
Line 321: Line 303:
  
  
-A quick note on an earlier point - when the function pointer is defined initially, it can point nowhere. This can be tested for with the following code:+A quick note on an earlier point - when the function pointer is defined initially, it points ​nowhere ​(as it does if an assignment fails due to mismatching signatures). This can be tested for with the following code:
  
  
-<code cpp>if( functionPointer is null ) +<code cpp>if( functionPointer is null )
 </​code>​ </​code>​
  
  
-Finally, that state of a function pointer **is not saved when the map is - ** there is no way to save the state of a function pointer - so keep them the same (which is fine in the case of an array - like the last example), or assume they haven'​t changed within the**scope** of one function (as in the second example).+Finally, that state of a function pointer **is not saved when the map is - ** there is no way to save the state of a function pointer - so keep them the same (which is fine in the case of an array - like the last example), or assume they haven'​t changed within the **scope** of the first function (E.g. the second example).
  
  
hpl2/tutorials/script/funcdef.1313315357.txt.gz · Last modified: 2011/08/14 09:49 by thegreatcthulhu