Creating a custom function

Started by Amayirot Akago, Wed 26/10/2016 15:11:50

Previous topic - Next topic

Amayirot Akago

I'm trying to create a custom function for my game which I can call whenever the player points at a certain hotspot, which will change the cursor into a pointer finger. However, I want the function to include a variable which determines the direction the pointer points towards; left, right, up, or down, so I don't have to make four separate functions.

So far, from looking at the manaual, I've worked out how the function should more or less look:

Code: ags
function point(string left string right string up string down)


And for each direction the code would go like:

Code: ags
{
  Mouse.SaveCursorUntilItLeaves();
  Mouse.UseModeGraphic(eModePointLeft);
}


Now how do I go about actually telling the script what to do for each variable?

I have already read about having to export functions at the end of the global script and importing it into the header so that shouldn't be a problem.
Quote from: CaptainDMy suspicion is that an accident, probably caused by a lightning storm and a mad professor, resulted in Amayirot's brain becoming inextricably linked to the databases behind MobyGames and LemonAmiga.

Snarky

This isn't quite right. First, the point() function isn't syntactically correct and doesn't really make sense.

The basic function is pretty easy. Instead of a string, let's use an enum:

Code: ags
// Put this in the script header
enum PointerDirection {
ePointNone = 0,
ePointLeft = 1,
ePointRight = 2,
ePointUp = 3,
ePointDown = 4
};

// Put this in the script body and export the function
void setCursorDirection(PointerDirection dir)
{
  // Mouse.SaveCursorUntilItLeaves(); // We may not need this line, depending on the rest of the code
  if(dir == ePointLeft)
    Mouse.UseModeGraphic(eModePointLeft);
  else if(dir == ePointRight)
    Mouse.UseModeGraphic(eModePointRight); 
  else if(dir == ePointUp)
    Mouse.UseModeGraphic(eModePointUp); 
  else if(dir == ePointDown)
    Mouse.UseModeGraphic(eModePointDown); 
  else
    Mouse.UseModeGraphic(eModeDefault); // Name of your regular cursor here
}


Now there are two ways to call this code. The first is to add a "Mouse moves over hotspot" event for every hotspot in the game, for example:

Code: ags
function hSomeHotspot_MouseMove()
{
  setCursorDirection(ePointUp); // Or whatever is appropriate for this hotspot
}


In this case you should uncomment the first line of the setCursorDirection() function, since we do need the SaveCursorUntilItLeaves() call.

However, this is not the best solution. One issue is that it only works with hotspots, and sometimes you may want to use an object or even a character as the "hotspot". Another drawback is that you need to fill your code with a ton of these "Mouse moves over hotspot" event handlers.

A better way to approach this is to check each game cycle whether the mouse is over a hotspot, by adding some code to repeatedly_execute(). There are modules that already do a lot of this logic, and you can try to modify them or roll your own code. It depends on the rest of the UI you're using. Here's the general idea:

Code: ags
function repeatedly_execute()
{
  LocationType ltype = GetLocationType(mouse.x, mouse.y);
  if (ltype == eLocationNothing)
  {
    setCursorDirection(ePointNone);    // Or set some other cursor
  }
  else if(ltype == eLocationHotspot)
  {
    Hotspot* hs = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
    // TODO: set the cursor
  }
  // Rest of repeatedly_execute() ...
}


(In this version of the code we DON'T need the SaveCursorUntilItLeaves() call, so leave that line commented out.)

So far the function only figures out which hotspot (if any) the cursor is over. Now the question becomes how to determine which pointer to use, depending on the hotspot. The best way to approach this is to have a custom property for hotspots that defines which direction the pointer should point, and then in the function look up this value and set the pointer accordingly.

Start by creating a custom Hotspot property called "PointerDirection", of type Number and with default value 0. (Look up custom properties in the manual.)

Now in place of the "TODO" in the function above, add these lines:

Code: ags
  PointerDirection dir = hs.GetProperty("PointerDirection");
  setCursorDirection(dir);


Now you don't need any event handler functions; you can just set the value of the "PointerDirection" property for each hotspot in the editor (you'll have to use the numbers, 0-4, corresponding to ePointNone/Left/Right/Up/Down). By adding similar code and custom properties for objects and characters, you can also have the same effect for them.

(Code is untested and may contain bugs.)

Amayirot Akago

#2
Well, I've done as you said and added the relevant parts to the header and global script, and tried to use the new function for one hotspot, but now when I try to start the game I get the error "Undefined token 'setCursorDirection' ".

Code: ags
export setCursorDirection;


Is this how I was meant to export the function?

Also I can't find anything on this "void" thing you used :confused: Care to explain?
Quote from: CaptainDMy suspicion is that an accident, probably caused by a lightning storm and a mad professor, resulted in Amayirot's brain becoming inextricably linked to the databases behind MobyGames and LemonAmiga.

dayowlron

#3
void just says the function does not return a value.

The correct export line would be:

export setCursorDirection(PointerDirection dir);

However I was looking at the code. the function setCursorDirection should be in your global script then in the header it should be:

void setCursorDirection(PointerDirection dir);

The function is not "exported".
Pro is the opposite of Con                       Kids of today are so much different
This fact can clearly be seen,                  Don't you know?
If progress means to move forward         Just ask them where they are from
Then what does congress mean?             And they tell you where you can go.  --Nipsey Russell

Snarky

#4
No, to "export" a function (that's actually not the right technical term, my mistake), you declare a "prototype" of it in the header. This is essentially saying "I've made a function, here's what it's called and what it looks like, you can find it in the script file". So:

Code: ags
//In the header, after the PointerDirection struct
import void setCursorDirection(PointerDirection dir);


You know how functions can return strings, ints, floats, and all kinds of other things (including pointers to Characters, GUIs, etc.)? When you write a function like that, instead of putting "function" you just put the type of value it returns. So you can do something like:

Code: ags
int max(int a, int b)
{
  if(a>b) return a;
  else return b;
}


Well, "void" is simply a type of function that doesn't return a value at all. (To simplify slightly, "function" is a function that can return either an int or nothing. The fact that it exists at all is a bit of a hack for legacy reasons.)

Amayirot Akago

#5
After I add the void line in the header I get an error "Expected '{'" on that line.

All of this coding stuff is going over my head as it is :confused: Anyone got any good online tutorials?
Quote from: CaptainDMy suspicion is that an accident, probably caused by a lightning storm and a mad professor, resulted in Amayirot's brain becoming inextricably linked to the databases behind MobyGames and LemonAmiga.

Crimson Wizard

Quote from: Amayirot Akago on Thu 27/10/2016 13:59:27
After I add the void line in the header I get an error "Expected '{'" on that line.
How does the line look exactly?
Also, you do not have to use void, you can use "function" if void confuses you. "Function" basically means that function returns integer, by the way, but since AGS does not require "return" statement, it works without returning anything too.

Quote from: Amayirot Akago on Thu 27/10/2016 13:59:27
All of this coding stuff is going over my head as it is :confused: Anyone got any good online tutorials?

Get some simple script module / open source game and use them as an example :).

Amayirot Akago

#7
I entered the line exactly as Snarky said:

Code: ags
import void setCursorDirection(PointerDirection dir);


EDIT: Except no I didn't because I completely missed to add the import bit at the start. It works now :)
Quote from: CaptainDMy suspicion is that an accident, probably caused by a lightning storm and a mad professor, resulted in Amayirot's brain becoming inextricably linked to the databases behind MobyGames and LemonAmiga.

SMF spam blocked by CleanTalk