Explination of Function stuff

Started by Wonkyth, Wed 06/05/2009 11:47:37

Previous topic - Next topic

Wonkyth

Since I've started making my own Script Modules I have found that my current knowledge of scripting commands and functions isn't really satisfactory.
Is it possible for people to explain the following to me?:

Importing/Exporting Functions;

Extender Functions;

Enumeration;

Pointers;

The term "Static"(cant find anything in Help);

Structs.

I shouldn't need it spelled out to me too simply, as I think i should be able to understand most concepts rather quickly.
Again, Any Help Appreciated.

"But with a ninja on your face, you live longer!"

Khris

1+2:
Functions don't need to be exported, just imported.
Say you add an extender function to the global script:

Code: ags
function FadeOut(this Object*) {
  int i = this.Transparency;
  while (i<100) {
    i++;
    this.Transparency = i;
  }
}


You can call this now in the global script:
Code: ags
  object[1].FadeOut();    // fade out object 1 in the current room


If you add an import line to the header, you can call the function in room scripts, too.
Code: ags
import function FadeOut(this Object*);


Now, in a room script, you can do:
Code: ags
  oChair.FadeOut();


3:
Enums add readability to code. Instead of arbitrary numbers, you can use words as function parameters.
Code: ags
// header
enum Weather {
  eRain,
  eStorm,
  eSunny
};

From the technical side, this adds three constants: eRain and the others are integer constants with the values of 1, 2 and 3.
You can also specify a value inside the enum definition if you need.
The great thing is that you can now declare a function like this:
Code: ags
function ChangeWeather(Weather w) {
  if (w == eRain) {
    ...
  }
  else if (w == eStorm) {
    ...
  }
  ...
}

Much more readable, and in addition, if you type ChangeWeather(, the auto-complete window will show the three enums you declared.

4.
Explaining Pointers is sort of hard; one really needs to grasp the concept once, and everything will fall into place.
An ubiquitous example of a Pointer is player. It "points" to the current player character, e.g. cEgo.
So in this case, if you have "player.Walk(x, y);" written in a script, you really call cEgo.Walk(x, y);.
But if the player changed and player now pointed to cLarry, the same line would call cLarry.Walk(x, y);

Declaring your own pointers is very handy.
Consider this:
Code: ags
function iCellphone_Useinv() {
  InventoryItem*i = player.ActiveInventory;   // i is now a pointer of type InventoryItem, pointing to the 
                                              //  item the player has just used on the cell phone.

  if (i == iBattery) {
    Display("You put the battery into the cell phone and power it on.");
    player.LoseInventory(i);
  }
  else Display(String.Format("You're not sure how to combine the %s with the cell phone.", i.Name));
}


Instead of having to constantly type "player.ActiveInventory", a simple "i" does the exact same job.
Plus, I can change i to whatever other InventoryItem I want.

It an elegant substitute for storing the ID number of something in an integer variable.

5+6:
You'll only really need "static" if you want to write a set of module functions that begin with "MyModule."
A struct is used to combine several variables into a dataset.
Code: ags
// header

struct strContact {
  String Name = "",      // initial value of "" instead of null to avoid errors
  int Age,
  String Occupation = "";
  import function DisplayAge();
};

// main script

strContact Roger;
strContact Larry;

function strContact::DisplayAge() {
  Display(String.Format("%s's age is %d.", this.Name, this.Age));
}


You have just declared two instances of the struct, Roger and Larry. Now you can do this:
Code: ags
  Larry.Name = "Larry Laffer";
Larry.Age = 35;
  Larry.DisplayAge();


This will result in "Larry Laffer's age is 35." being displayed.

Note that you can't access the struct members directly: Calling
Code: ags
  strContact.DisplayAge();

will result in an error.

So if you want to write a module, you'd do something like this:
Code: ags
// header

struct RainModule {
  import static void SetDropsAmount(int da);
  import static int GetDropsAmount();
  import static void StartRain();
  import static void StopRain();
}

// main script

int DropsAmount = 100;

static void SetDropsAmount(int da) {
  DropsAmount = da;
}

static int GetDropsAmount() {
  return DropsAmount;
}

static void StartRain() {
  ...
}

static void StopRain() {
  ...
}


Now you are allowed to call "RainModule.StartRain();" directly, since the static keyword is used; you are just using a struct to group the functions together, not to create a template to generate several instances from.


Phew. Long post. I hope you'll find it useful.

Wonkyth

Thanks!
Up until now I've just Retro-Fitted code from existing modules to suit my needs. It didn't really work.
"But with a ninja on your face, you live longer!"

Trent R

I'd also suggest reading the articles on the wiki on enums, pointers, and AGS Pointers for Dummies.


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

Wonkyth

I got an error that I cant figure out how to resolve, and as I still have an active thread I felt it should go there:

I was trying my hand at module-making, working on a script that handles movement by only allowing forward and backward movement, clockwise and anti-clockwise rotation.
I get this:
RotoMove.asc(67): Error (line 67): PE04: parse error at 'RM_CurrentDirection'

The code:
Code: ags

if (keycode == RM_Clockwise) {
    if (RM_CurrentDirection == eDirections_SouthEast) {
      RM_CurrentDirection == eDirections_South; //line 67
      player.Loop = 0;


I cant figure out why it doesn't like this code!
Just above that section is code(the Anti-Clockwise "if") that uses the same variable, but it had no problems with that.
Thanks for any help.



"But with a ninja on your face, you live longer!"

monkey0506

The == operator is the boolean operator, used for comparing two values. The = operator is the assignment operator, used to assign values to variables.

Wonkyth

DAMMIT!
why didn't I see that?

Thanks.
"But with a ninja on your face, you live longer!"

Wonkyth

New problem:
I've got the current code:
Code: ags

function Repeatedly_execute() {
  
    if (IsKeyPressed(RM_Forward)) {
            
      int newx;
      int newy;
      
      
      if (RM_CurrentDirection == eDirections_SouthEast) {
				newx = 10000;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_NorthEast) {
				newx = 10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_SouthWest) {
				newx = -10000;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_NorthWest) {
				newx = -10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_South) {
				newx = 0;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_West) {
				newx = -10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_East) {
				newx = 10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_North) {
				newx = 0;
				newy = -10000;
			}
      player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
      }


}

What it's supposed to do is, quite simply, walk in the direction indicated.
I copied most of it from the keyboard movement module, but changed a few things.
It's not working.
The player doesn't move.
What am I doing wrong?
"But with a ninja on your face, you live longer!"

Khris

I'm not sure, but I believe that calling a .Walk command every game loop will keep a character at their current position, since they never get the opportunity to actually begin to walk.

You'd have to do:

Code: ags
bool forward_key_down;

function Repeatedly_execute() {
  
  if (IsKeyPressed(RM_Forward)) {
    if (!forward_key_down) {
      forward_key_down = true;

      ....  // direction stuff

      player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
    }
  }
  else {
    forward_key_down = false;
    player.StopMoving();
  }
}

Wonkyth

#9
I'll give that a try...

[Edit]

code is now:
Code: ags

function Repeatedly_execute() {
  
    if (IsKeyPressed(RM_Forward)) {
      if (!Forward_Key_Down) {
        Forward_Key_Down = true;
      int newx;
      int newy;
      
      
      if (RM_CurrentDirection == eDirections_SouthEast) {
				newx = 10000;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_NorthEast) {
				newx = 10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_SouthWest) {
				newx = -10000;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_NorthWest) {
				newx = -10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_South) {
				newx = 0;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_West) {
				newx = -10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_East) {
				newx = 10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_North) {
				newx = 0;
				newy = -10000;
			}
      player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
  }
  else {
    Forward_Key_Down = false;
    player.StopMoving();
    }
    }


}

and still no results.
"But with a ninja on your face, you live longer!"

Hudders

Might be a bit of a cheeky question; but are you sure that:

1. A walkable area exists.
2. The character starts within the walkable area.

?

Khris

Debugging 101:
Add a display line before player.WalkStraight():

Code: ags
    Display("Calling WalkStraight.");


Does it get called?

Wonkyth

#12
Quote from: Hudders on Fri 08/05/2009 08:57:03
Might be a bit of a cheeky question; but are you sure that:

1. A walkable area exists.
2. The character starts within the walkable area.

?
Yes and Yes.
First thing I do when I'm testing an idea for a game is import a blank white background and bucket on a walkable area.

Quote from: KhrisMUC on Fri 08/05/2009 08:59:43
Does it get called?

No, that's what I cant figure out.

I also put a 'Display("south");' in 'else if (RM_CurrentDirection == eDirections_South)', and that isn't being called either.


Maybe I'll have to look at the Keyboard_Movement module again, to make sure there aren't any differences that would cause no effect.
"But with a ninja on your face, you live longer!"

Wonkyth

I've decided to post the entire module code, maybe that will help.

Code: ags

// Main script for module "RotoMove"
//*******************************************************************************************************************
enum RM_Directions {
  eDirections_South, 
  eDirections_SouthEast, 
  eDirections_East, 
  eDirections_NorthEast, 
  eDirections_North, 
  eDirections_NorthWest, 
  eDirections_West, 
  eDirections_SouthWest
};
int walkbackdir;
//*******************************************************************************************************************
//DEFUALT SETTINGS
//     \/
bool RM_On = true; //must be turned on for module effect

RM_Directions RM_CurrentDirection = eDirections_South;//Defualt Direction
//     /\
//*******************************************************************************************************************
//keycodes
//    \/
int RM_Forward = 372;//Up
int RM_Backward = 380;//Down
int RM_Clockwise = 377;//Right
int RM_AntiClockwise = 375;//Left
//    /\
//*******************************************************************************************************************
//loop numbers
//    \/
int South = 0;
int West = 1;
int East = 2;
int North = 3;
int SouthEast = 4;
int NorthEast = 5;
int SouthWest = 6;
int NorthWest = 7;
//    /\
//*******************************************************************************************************************
//    \/
bool Forward_Key_Down = false;
//    /\
//*******************************************************************************************************************

function Repeatedly_execute() {
  
    if (IsKeyPressed(RM_Forward)) {
      if (!Forward_Key_Down) {
        Forward_Key_Down = true;
      int newx;
      int newy;
      
      
      if (RM_CurrentDirection == eDirections_SouthEast) {
				newx = 10000;
				newy = 10000;       
			}
			else if (RM_CurrentDirection == eDirections_NorthEast) {
				newx = 10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_SouthWest) {
				newx = -10000;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_NorthWest) {
				newx = -10000;
				newy = -10000;
			}
			else if (RM_CurrentDirection == eDirections_South) {
				newx = 0;
				newy = 10000;
			}
			else if (RM_CurrentDirection == eDirections_West) {
				newx = -10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_East) {
				newx = 10000;
				newy = 0;
			}
			else if (RM_CurrentDirection == eDirections_North) {
				newx = 0;
				newy = -10000;
    }
    Display("walking");
      player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
  }
  else {
    Forward_Key_Down = false;
    player.StopMoving();
    }
    }


}


function on_key_press(int keycode) {
  if (RM_On == true) {
  if (keycode == RM_AntiClockwise){
     if (RM_CurrentDirection == eDirections_South) {
      RM_CurrentDirection = eDirections_SouthEast;
      player.Loop = SouthEast;
    }
    else if (RM_CurrentDirection == eDirections_SouthEast) {
      RM_CurrentDirection = eDirections_East;
      player.Loop = East;
    }
    else if (RM_CurrentDirection == eDirections_East) {
      RM_CurrentDirection = eDirections_NorthEast;
      player.Loop = NorthEast;
    }
    else if (RM_CurrentDirection == eDirections_NorthEast) {
      RM_CurrentDirection = eDirections_North;
      player.Loop = North;
    }
    else if (RM_CurrentDirection == eDirections_North) {
      RM_CurrentDirection = eDirections_NorthWest;
      player.Loop = NorthWest;
    }
    else if (RM_CurrentDirection == eDirections_NorthWest) {
      RM_CurrentDirection = eDirections_West;
      player.Loop = West;
    }
    else if (RM_CurrentDirection == eDirections_West) {
      RM_CurrentDirection = eDirections_SouthWest;
      player.Loop = SouthWest;
    }
    else if (RM_CurrentDirection == eDirections_SouthWest) {
      RM_CurrentDirection = eDirections_South;
      player.Loop = South;
      }
  }
  
  if (keycode == RM_Clockwise) {
    if (RM_CurrentDirection == eDirections_SouthEast) {
      RM_CurrentDirection = eDirections_South;
      player.Loop = South;
  }
    else if (RM_CurrentDirection == eDirections_SouthWest) {
      RM_CurrentDirection = eDirections_West;
      player.Loop = West;
  }
  else if (RM_CurrentDirection == eDirections_NorthEast) {
      RM_CurrentDirection = eDirections_East;
      player.Loop = East;
  }
  else if (RM_CurrentDirection == eDirections_NorthWest) {
      RM_CurrentDirection = eDirections_North;
      player.Loop = North;
  }
  else if (RM_CurrentDirection == eDirections_East) {
      RM_CurrentDirection = eDirections_SouthEast;
      player.Loop = SouthEast;
  }
 else if (RM_CurrentDirection == eDirections_North) {
      RM_CurrentDirection = eDirections_NorthEast;
      player.Loop = NorthEast;
  }
  else if (RM_CurrentDirection == eDirections_South) {
      RM_CurrentDirection = eDirections_SouthWest;
      player.Loop = SouthWest;
  }
  else if (RM_CurrentDirection == eDirections_West) {
      RM_CurrentDirection = eDirections_NorthWest;
      player.Loop = NorthWest;
    }
}
}
  
  }

can anyone see what I'm doing wrong?
"But with a ninja on your face, you live longer!"

Hudders

You haven't declared Forward_Key_Down

I'm not sure if that's important but it's what sticks out.

Wonkyth

I have, just above Repeatedly_Execute().
"But with a ninja on your face, you live longer!"

Wonkyth

PLEASE HELP?! :-\
I know it sounds pathetic, but that's sort of the state that my non-working code has reduced me to.
"But with a ninja on your face, you live longer!"

Trent R

#17
I'd start throwing breakpoints and/or Display checks everywhere and see what is being called and what isn't.


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

Wonkyth

#18
Ok, I'll give that a try, but I'm pretty sure what's being called, as at the moment one bit does everything it's supposed to, and the bit does nothing.

If I cant track down the problem soon, then I'll do a complete makeover of the code, starting from the walk_forward part


[Edit] I just went through and put a 'display("");' between every set of curly braces in the Repeatedly_Execute function, and found that nothing in that function was going - Not even the Function itself!
Unless there is some special rule about using 'Display("");' in Repeatedly Execute, then something really weird is going on.
I know the script is being used, as the on_key_press function is being called.
Any ideas?
"But with a ninja on your face, you live longer!"

Trent R

I just threw a Display(""); call into gamestart, and nothing happened. Apparently you have to display at least a space, but the best way is display the script lines and variables. Until we can view runtime variables while debugging (a feature I want very much, but CJ has said will require rewriting the compiler), String.Format and Display calls will be your best debugging friends. Also, if you just need to know if the lines are firing, (and not care what variables are and such) you can use breakpoints instead. Check out the manual entry 'Debugging features'


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

SMF spam blocked by CleanTalk