Hijacking the Mouse Cursor

Started by Baron, Mon 07/01/2013 16:12:47

Previous topic - Next topic

Baron

Hi.  I'm trying to program an intreactive tutorial for my game.  So far I've been using an object that looks like a cursor to float over various parts of the screen as a colourful secondary character describes how to point and click, among other things, but now that it has come time to describe the GUI that won't work because GUIs are always drawn on top of objects.  So I've been thinking....

1) If there were a way to control the real game cursor, I could use that.  I'm aware that I can use mouse.SetPosition, but it would be tedious that way to script the movement commands necessary to make it look like it was moving back and forth.  A mouse.Move command would be helpful, but then there's also the problem of disabling the player's control while the tutorial is running.  So this is probably not going to work (unless someone knows something I don't know about hijacking a mouse cursor?)

2) Alternatively I could create another GUI that looks like a mouse cursor.  I don't have to worry about hijacking the actual mouse cursor, but there's still the problem of programming realistic movement.  There is no GUI.Move command, only GUI.X and GUI.Y properties (again doable but tedious).

3) I thought about reconstituting the GUI as a series of objects and hotspots with an invisible GUI to handle labels.  Again tedious, but probably the path of least resistance unless a more elegant solution can be found.

So, I'm looking for input.  My question is: What would be the easiest way to create a tutorial cursor that can be scripted to behave like the normal game cursor (at least in terms of movement)?

Thanks for any help or advice,

Baron

cat

You could do (2) and use the TweenModule. This can tween the movement of GUIs (afair).

Edit: Unless you want stuff on screen to react to the cursor i.e. highlight buttons, show a overhotspot text...

monkey0506

I don't think that scripting movement should be that tedious...

Code: ags
// GUIMove.ash
/// Moves the selected GUI to (X, Y) in screen coordinates. Also used to set X/Y movement speed.
import void Move(this GUI*, int x, int y, int xSpeed=SCR_NO_VALUE, int ySpeed=SCR_NO_VALUE);
/// Returns whether a GUI is currently moving.
import bool IsMoving(this GUI*);
/// Stops the current GUI movement.
import void StopMoving(this GUI*);
/// Returns the X coordinate of the GUI's current movement, as set by GUI.Move.
import int GetXMovePoint(this GUI*);
/// Returns the X speed of the GUI's current movement, as set by GUI.Move.
import int GetXMoveSpeed(this GUI*);
/// Returns the Y coordinate of the GUI's current movement, as set by GUI.Move.
import int GetYMovePoint(this GUI*);
/// Returns the Y speed of the GUI's current movement, as set by GUI.Move.
import int GetYMoveSpeed(this GUI*);

// GUIMove.asc
int GUI_XDest[];
int GUI_XSpeed[];
int GUI_YDest[];
int GUI_YSpeed[];

function game_start()
{
  if (Game.GUICount == 0) return; // if there's no GUIs then what the hell man, what the hell...
  GUI_XDest = new int[Game.GUICount];
  GUI_XSpeed = new int[Game.GUICount];
  GUI_YDest = new int[Game.GUICount];
  GUI_YSpeed = new int[Game.GUICount];
  int i = 0;
  while (i < Game.GUICount)
  {
    GUI_XDest[i] = -1; // use -1 for no movement
    GUI_YDest[i] = -1;
    GUI_XSpeed[i] = 5; // arbitrary, untested default - adjust as needed
    GUI_YSpeed[i] = 5;
    i++;
  }
}

void Move(this GUI*, int x, int y, int xSpeed, int ySpeed)
{
  if ((x < 0) || (x >= System.ViewportWidth)) x = -1;
  if ((y < 0) || (y >= System.ViewportHeight)) y = -1;
  GUI_XDest[this.ID] = x;
  GUI_YDest[this.ID] = y;
  if ((xSpeed != SCR_NO_VALUE) && (xSpeed > 0)) GUI_XSpeed[this.ID] = xSpeed;
  if ((ySpeed != SCR_NO_VALUE) && (ySpeed > 0)) GUI_YSpeed[this.ID] = ySpeed;
}

bool IsMoving(this GUI*)
{
  return ((GUI_XDest[this.ID] != -1) || (GUI_YDest[this.ID] != -1)); // GUI is moving when either destination is not -1
}

void StopMoving(this GUI*)
{
  GUI_XDest[this.ID] = -1;
  GUI_YDest[this.ID] = -1;
}

int GetXMovePoint(this GUI*)
{
  return GUI_XDest[this.ID];
}

int GetXMoveSpeed(this GUI*)
{
  return GUI_XSpeed[this.ID];
}

int GetYMovePoint(this GUI*)
{
  return GUI_YDest[this.ID];
}

int GetYMoveSpeed(this GUI*)
{
  return GUI_YSpeed[this.ID];
}

function repeatedly_execute()
{
  int i = 0;
  while (i < Game.GUICount)
  {
    if (GUI_XDest[i] != -1)
    {
      if (gui[i].X > GUI_XDest[i])
      {
        if ((gui[i].X - GUI_XSpeed[i]) < GUI_XDest[i]) gui[i].X = GUI_XDest[i];
        else gui[i].X -= GUI_XSpeed[i];
      }
      else if (gui[i].X < GUI_XDest[i])
      {
        if ((gui[i].X + GUI_XSpeed[i]) > GUI_XDest[i]) gui[i].X = GUI_XDest[i];
        else gui[i].X += GUI_XSpeed[i];
      }
      if (gui[i].X == GUI_XDest[i]) GUI_XDest[i] = -1;
    }
    if (GUI_YDest[i] != -1)
    {
      if (gui[i].Y > GUI_YDest[i])
      {
        if ((gui[i].Y - GUI_YSpeed[i]) < GUI_YDest[i]) gui[i].Y = GUI_YDest[i];
        else gui[i].Y -= GUI_YSpeed[i];
      }
      else if (gui[i].Y < GUI_YDest[i])
      {
        if ((gui[i].Y + GUI_YSpeed[i]) > GUI_YDest[i]) gui[i].Y = GUI_YDest[i];
        else gui[i].Y += GUI_YSpeed[i];
      }
      if (gui[i].Y == GUI_YDest[i]) GUI_YDest[i] = -1;
    }
    i++;
  }
}


Just over a hundred lines of completely untested code... but then again I made it completely generic and allowed you to run simultaneous movements across every GUI at once. If you strictly needed it only for one GUI then it could be optimized by stripping out the arrays.

I hate the Tween module. I don't like the way it's coded. But that's just me.

cat

I love the tween module and I recommend to use it whenever possible. At least it is tested  :P

Baron

Hmmmm....  The control freak in me likes monkey_05_06's approach, but that's probably because I'm naturally distrustful of novelty.  Poking around the Tween Module demo reveals some flashy (Flash-y?) visual effects and the mechanism for moving a phantom cursor GUI without much effort, however.  Are there any other arguments against the Tween Module besides its coding style?  I had some issues with a pluggin once that didn't work on newer machines....

monkey0506

The only real concern that I would expect you to have in this situation would be the size and efficiency of the code. The Tween module is overkill if this is the only thing you'd be using it for. If you'll use other aspects of it, then go for it. Don't mind me. :P

MurrayL

In my experience the Tween module is so indispensably useful for a variety of things that it's silly not to import it into any AGS game of reasonable scope.

Ghost

#7
I am using Tween all the time and never ran into any problems. It's convenient to have around. The coding may be messy or not, the result is stable and useful as hell. Never got any reports of it breaking, and I usually test on XP and W7.

Clarvalon

Alternative to Tween:  Set up some code to record the cursor position whenever it changes, stamped with the frames elapsed.  Use this to record yourself perform the cursor actions and dump this data into a file (x, y, elapsedFrames).  Then load the data in for the tutorial and play it back, updating the mouse position at the required frames.

A more advanced version would capture and simulate mouse clicks.  One drawback is that any GUI changes would require you re-record your cursor movements again, though in theory you could manually edit the data file.
XAGE - Cross-Platform Adventure Game Engine (alpha)

SMF spam blocked by CleanTalk