DOUBLE-CLICK IN ADVENTURE GAME STUDIO

How to script a double-click in AGS

  • Shinan
  • 06/08/2010 10:12 PM
  • 5158 views
I'll share a little AGS tidbit. One thing that is not (currently) supported by AGS is double-clicking but there's a fairly simple workaround if you want to have doubleclicking in your game.
The idea is that in the code when a left click is processed you run a function that checks if the mouse button is pressed a second time within a given timeframe.

This might need a bit of basic AGS knowledge but if you read through this you should also be able to copy-paste stuff to make it work. Hopefully this tutorial will also help you understand exactly how it works so you can mess around with it and make my otherwise hopelessly bad code better.



In the basic globalscript of AGS you should find a line that is something along the lines of
function on_mouse_click(MouseButton button) {
  // called when a mouse button is clicked. button is either LEFT or RIGHT
  if (IsGamePaused() == 1) {
    // Game is paused, so do nothing (ie. don't allow mouse click)
  }
  else if (button == eMouseLeft) {
    ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }
  else if (button == eMouseRight || button == eMouseWheelSouth){
    // right-click our mouse-wheel down, so cycle cursor
    mouse.SelectNextMode();
  }
}

That's if you open the game in the default template. There's some more stuff after that but that's the basic left and right click commands (There's middle mouse button and mousewheel commands implemented in the default template).

Now you'll need a couple of variables set. You need four integers. In my script I called them mx, my, lastclick and clickdelay
mx and my stores the coordinates of a click when it happens. The script also has a check that they stay the same over two clicks so you can't click once on one place and then have the second click somewhere else.
lastclick is a variable that tells you when the last mouse click happened
clickdelay is the number of game cycles you have until the second click in a doubleclick has to happen. (in AGS one second is 40 game cycles. I set this number as 7 but you can fiddle around with it depending on how fast you want to force people to doubleclick.)

Immediately after creating the variables you can set clickdelay to a number. In this tutorial I set it as 7.
So this code basically looks something like:
int mx, my, lastclick;
int clickdelay = 7;

You should put this as high up as possible in the GlobalScript.

Another thing you'll need is a left clicking function that you call each time the left mouse button is pressed. You can have a boolean variable in this since it'll either be single click or double-click.

My function looks like this:
function left_click(bool single) {
  if (single) {
    // single-click code
    ProcessClick(mouse.x, mouse.y, eModeWalkto);
  }
  else {    
    // double-click code
    ProcessClick(mouse.x, mouse.y, eModeInteract);
  }
}

My boolean is called single so when it's set to true it's a single click. That might not be logical in some minds (since double-clicking might be when you "succeed" but either way works I suppose) What the rest of the code does is that it processes the click depending on which mode it's set to. You can check the manual as to how exactly the ProcessClick function works.

Since this is a global function you're best off putting it somewhere high up in the globalscript.

So next we need to call this function when you press the left mouse button.
else if (button == eMouseLeft) {
    ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }

This is the snippet of code from before. We need to change what is called here. So instead of processing a click it needs to run the function. Now on default AGS doesn't recognize doubleclicks so there's not much we can do here at a glance. If we write
else if (button == eMouseLeft) {
    left_click(true);
  }

then the code will run the single click code. Which I guess it should since that was only a single click.

So we need to go mess somewhere else to check exactly how to do the timer thing. In AGS there's an area called "repeatedly execute" on the default template it should look something like this:
function repeatedly_execute() {
  
  // put anything you want to happen every game cycle, even when
  // the game is paused, here
  
  if (IsGamePaused() == 1) return;

  // put anything you want to happen every game cycle, but not
  // when the game is paused, here
}

here we want to do a timer thing. Since this runs every cycle (one second is 40 cycles) we can do the whole loop adding thing here. What I put in was.
if (lastclick>0 && lastclick<=clickdelay) lastclick++;
  else if (lastclick>clickdelay) {
    lastclick=0;
    left_click(true);
  }

what this does is that if the integer lastclick is more than 0 but not more than the clickdelay variable (that we set earlier to 7) it increases the lastclick variable by one each cycle. If lastclick reaches a number that is more than the clickdelay then the click will register as a single click in the left_click function. And the lastclick variable will return to zero.

With me at all?

In the
else if (button == eMouseLeft) {
    left_click(true);
  }

we now change the code completely to instead mess around with the lastclick variable. Since the repeatedly execute code doesn't start up until the lastclick variable is more than zero we need to change the variable from zero to something (in this case 1).
else if (button == eMouseLeft) {
    lastclick=1;
  }

This will create a delay (one of the setbacks of this method of doubleclicking, see the afterword) before the action is finished because it will wait until the lastclick variable is over 7 until it executes. What we want is that while the lastclick variable is counting up we want to check if there's been another leftclick. To do that we use another one of those ifs.
else if (button == eMouseLeft) {
  {
    if (lastclick>0) {
      lastclick=0;
      left_click(false);  
    }
    else {
      lastclick=1;
    }
  }

What this code now will do is to check if lastclick is more than 0 it will set it to zero and run the doubleclick code in the left_click function (by setting the single boolean to false. If you were more logical than I was this might be the part where you went "wtf was he thinking?" I don't know what I was thinking I'm copy-pasting an old project here. You can switch around the booleans no problem.
If lastclick already is zero (or actually if it isn't more than zero) it will be set to one just like it was earlier and start the timer.


Now we have working doubleclick code in AGS. There's one slight tidbit left though. In the beginning I suggested using mx and my variables for the mouse coordinates. The way this works now is that if you click once then move the cursor to the other side of the screen for the second click it'll register as a double click on that area. This might not be a good idea. So by storing the mouse coordinates and checking them against the current coordinates you can make sure your double-click happens on the right spot.

By changing the eMouseLeft code into this:
else if (button == eMouseLeft) 
  {
    if (lastclick>0 && mouse.x==mx && mouse.y==my) {
      lastclick=0;
      left_click(false);  
    }
    else {
      lastclick=1;
      mx=mouse.x;
      my=mouse.y;
    }
  }

you now save the mouse coordinates on your regular click and while the timer is running and you left click you check to see if the coordinates have stayed the same. If they have it's a goahead for clicking. You can also change the single-click code in the left_click function from
function left_click(bool single) {
  if (single) {
    // single-click code
    ProcessClick(mouse.x, mouse.y, eModeWalkto);
  }
  else {    
    // double-click code
    ProcessClick(mouse.x, mouse.y, eModeInteract);
  }
}

to
function left_click(bool single) {
  if (single) {
    // single-click code
    ProcessClick(mx, my, eModeWalkto);
  }
  else {    
    // double-click code
    ProcessClick(mx, my, eModeInteract);
  }
}

if you want. Though it's really only useful in the single-click mode since otherwise it will process where the mouse is when the timer runs out. For the double-click you already checked where it was in clicking code.



So there it was. A fairly detailed "how to do double-clicking" in AGS. I hope it was helpful (and that it worked). There's probably other ways to do double-clicking but this is the simplest I've found. The downside to this is that it waits until the single-click happens so there can be some lag. Especially if you set the clickdelay to a very high value. You should test and see what value works so that the lag isn't too noticeable and it's still possible to doubleclick. 7 was a good number for me but you might have others. And if you're nice you might even make a menu so that players can change the number during the game if they feel that they can't doubleclick or if they feel the lag is distracting. That's probably a whole different tutorial though.


I also hope this tutorial works because I might have put a comma or semicolon at the wrong place somewhere. Please mention in the comments any error messages you may get and I can try to help you get through this.
Pages: 1