Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: Calin Leafshade on Wed 03/02/2010 16:16:35

Title: Useful Functions
Post by: Calin Leafshade on Wed 03/02/2010 16:16:35
I'm compiling a module of useful little miscellaneous functions for scripting newbies and I wondered if anyone had any suggestions?

Just little things which make life a little easier.

for example:

- FadeIn and FadeOut for Guis,
- ClampInt, ClampFloat to catch those pesky "must be between" values
- ToggleBool

and so on.
Title: Re: Useful Functions
Post by: barefoot on Wed 03/02/2010 17:31:03
Hi Calin..

That would be a really great resource ... as  im sure many of us would agree with..
I'll keep my eyes open for when you do finish the compiling.

awaiting.

cheers
barefoot
Title: Re: Useful Functions
Post by: GarageGothic on Wed 03/02/2010 18:01:36
I'm sure they're covered in other modules, but some functions I often use and it would make sense to have in a utility module are:

- AbsInt(int val)
- AbsFloat(float val)
- MaxInt(int val1, int val2, optional int val3, ... optional int val9)
- MinInt(int val1, int val2, optional int val3, ... optional int val9)
- MaxFloat(float val1, float val2, optional float val3, ... optional float val9)
- MinFloat(float val1, float val2, optional float val3, ... optional float val9)

(setting default values for optional floats is a bit weird since you have to use ints, but I haven't experienced any problems with it so far)
Title: Re: Useful Functions
Post by: Dualnames on Wed 03/02/2010 18:55:17
Great idea, I don't have anything generic to really give out. But it's a cool idea.

Add the face thingy.

Declare a struct eh!

enum FaceOption {
  D,
  L,
  R,
  U
};



function Face (Character *Charpointer, FaceOption param) {
if (param == D) {
Charpointer.FaceLocation(Charpointer.x,Charpointer.y+10, eBlock);
}
else if (param == L) {
Charpointer.FaceLocation(Charpointer.x-10,Charpointer.y, eBlock);
}
else if (param == R) {
Charpointer.FaceLocation(Charpointer.x+10,Charpointer.y, eBlock);
}
else if (param == U) {
Charpointer.FaceLocation(Charpointer.x,Charpointer.y-10, eBlock);
}
}

Title: Re: Useful Functions
Post by: monkey0506 on Wed 03/02/2010 18:58:12
I don't have any specific ideas for functions (beyond what GG already suggested of the abs, min, and max functions) but this module sounds like a good candidate for a Library module (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=39999.0).

Sure, it's a shameless plug, but it was Rick's idea. :P

Anyway good idea to actually put this module together.

Just a couple of questions though...

What is ClampInt supposed to do? Is that to bind a value into a specific range (like how 256 stored in a char gets converted to 0)?

Also, is there a purpose of ToggleBool? I understand you said your target audience here is scripting newbies but since we can't pass parameters by reference there would be no advantage to using the function. In fact it would be disadvantageous due to the overhead of having to call the function just to do:

bool ToggleBool(bool val) {
 return !val;
}

bool b = false;
b = ToggleBool(b);


Versus:

bool b = false;
b = !b;


Edit: No offense here Dual, but I actually highly recommend that people do not declare enumerations (note it's an enum not a struct :P) with such non-descript and meaningless values. Perhaps a better definition would be something like:

import void FaceDirection(this Character*, BlockingStyle=eBlock);
// forward-declaring this lets us give the enum and the function the same name, YAY

enum FaceDirection {
  eFaceDown = 'D',
  eFaceLeft = 'L',
  eFaceRight = 'R',
  eFaceUp = 'U'
};

void Character::FaceDirection(FaceDirection dir, BlockingStyle blocking) {
  // note although this is an extender method since we forward-declared it
  // we can use the normal scope-resolution
  // (which is required since I am being silly and gave the enum the same name as the function :P)
  if (dir == eFaceDown) this.FaceLocation(this.x, this.y + 1000, blocking);
  else if (dir == eFaceLeft) this.FaceLocation(this.x - 1000, this.y, blocking);
  else if (dir == eFaceRight) this.FaceLocation(this.x + 1000, this.y, blocking);
  else if (dir == eFaceUp) this.FaceLocation(this.x, this.y - 1000, blocking);
}


(I also used an extender method to prevent the possibility of null pointer references and mainstream the function. :P)
Title: Re: Useful Functions
Post by: Calin Leafshade on Wed 03/02/2010 19:09:12

GG: MaxInt etc is a good idea. Already thought of Abs

Dual: Already added the 'face direction' one.. i use that alot.

Monkey: ClampInt essentially limits a value to a certain range.

I use it extensively when dealing with things like transparency which have predefined bounds.

i.e


Pseudo:

while (Transparency < 100){

Transparency = ClampInt(0, 100, Transparency + 3); // Usage ClampInt(Minimum, Maximum, Value);
wait(1);

}



Also good point with the Bool thing.. i forgot about the ! operator on account of a small brain haemorrhage or something.

i was doing it  something like


if(Bool) Bool = false;
else Bool = true;
Title: Re: Useful Functions
Post by: monkey0506 on Wed 03/02/2010 19:20:54
How does your ClampInt function work though. Does it just truncate the value within the limits or does it actually provide recursive bounding? What I mean by this is:

char c = 255;
char d = c + 1; // d = 0
char e = c + 2; // d = 1


Like that? Or just:

int i = 100;
int j = ClampInt(0, 100, i + 15); // i = 100


It might actually even be worth providing an enum like:

enum ClampStyle {
 eClampTruncate,
 eClampRecursive
};


Or something...I don't really know you'd want to call it that. Those names seem a bit silly to me. :P
Title: Re: Useful Functions
Post by: Calin Leafshade on Wed 03/02/2010 20:04:34
It just truncates(Clamps) the value.

I do kinda see the advantage of recursive or even reciprocal clamping though.

Reciprocal clamping could be used  for things like pendulum movement.

for example


int i = 0
while (i < 10){

ClampReciprocal(0, 5, i);
i ++;

}


would return 0, 1, 2, 3, 4, 5, 4, 3, 2, 1
Title: Re: Useful Functions
Post by: Crimson Wizard on Thu 04/02/2010 14:24:46
Nice to see 'face direction' there, something I actually suggested to be included to built-in AGS functions; oh well...

Here's another one:

function RandomRange(int min, int max)
{
   return min + Random(max - min + 1);
}
Title: Re: Useful Functions
Post by: monkey0506 on Mon 08/02/2010 18:29:08
I actually had a few thoughts on some things:

ViewFrame* GetViewFrame(this Character*)
{
  return Game.GetViewFrame(this.View, this.Loop, this.Frame);
}

ViewFrame* GetViewFrame(this Object*)
{
  if (this.View == 0) return null;
  return Game.GetViewFrame(this.View, this.Loop, this.Frame);
}

int GetGraphic(this Character*)
{
  ViewFrame *frame = this.GetViewFrame();
  return frame.Graphic;
}

int GetWidth(this Character*)
{
  return Game.SpriteWidth[this.GetGraphic()];
}

int GetHeight(this Character*)
{
  return Game.SpriteHeight[this.GetGraphic()];
}


Simple functions but I've had cause to rewrite them a few times for various purposes.
Title: Re: Useful Functions
Post by: Khris on Mon 08/02/2010 18:33:47
Quote from: Crimson Wizard on Thu 04/02/2010 14:24:46function RandomRange(int min, int max)
{
   return min + Random(max - min + 1);
}


I believe Random(3) will return 0-3, so it's supposed to be
  return min + Random(max - min);
Title: Re: Useful Functions
Post by: monkey0506 on Mon 08/02/2010 19:16:02
Random does indeed return 0-MAX inclusive so you're right on that Khris.
Title: Re: Useful Functions
Post by: RickJ on Mon 08/02/2010 22:53:35
First of all I like the term "clamp"; it's used extensively in control systems.

Anyway I'd like to suggest the use of some conventions that would promote consistency and simplicity.  Much of this is obviously my own personal preference so if your's are different..; well it's your module.

Proposed rules for arithmetic functions such as clamp, max, min, random, etc.:
1) Always make the input value the first parameter rather than the last.   By doing this it makes possible the use of optional paremeters.

2) Begin function names with lowercase letter indicating data type.   For example ClamInt() would become iClamp(). So there would be room for a future fClamp(), cClamp(), sClamp(), and of course the totally useless bClamp()  :=.

Other proposed rules:
3) Consider using extender function where appropriate.   FaceDirection() is a good candiatel.

4) Consider making object methods where appropriate, at least set a pattern for doing so in the future if required.