Useful Functions

Started by Calin Leafshade, Wed 03/02/2010 16:16:35

Previous topic - Next topic

Calin Leafshade

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.

barefoot

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
I May Not Be Perfect but I Have A Big Heart ..

GarageGothic

#2
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)

Dualnames

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!
Code: ags

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


Code: ags

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);
}
}

Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

monkey0506

#4
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.

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:

Code: ags
bool ToggleBool(bool val) {
  return !val;
}

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


Versus:

Code: ags
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:

Code: ags
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)

Calin Leafshade


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:
Code: ags

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

Code: ags

if(Bool) Bool = false;
else Bool = true;

monkey0506

#6
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:

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


Like that? Or just:

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


It might actually even be worth providing an enum like:

Code: ags
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

Calin Leafshade

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

Code: ags

int i = 0
while (i < 10){

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

}


would return 0, 1, 2, 3, 4, 5, 4, 3, 2, 1

Crimson Wizard

Nice to see 'face direction' there, something I actually suggested to be included to built-in AGS functions; oh well...

Here's another one:

Code: ags
function RandomRange(int min, int max)
{
   return min + Random(max - min + 1);
}

monkey0506

I actually had a few thoughts on some things:

Code: ags
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.

Khris

Quote from: Crimson Wizard on Thu 04/02/2010 14:24:46
Code: ags
function 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
Code: ags
  return min + Random(max - min);

monkey0506

Random does indeed return 0-MAX inclusive so you're right on that Khris.

RickJ

#12
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.

SMF spam blocked by CleanTalk