Change Cursor Graphic Depending on Screen Location...(Solved)

Started by J.E.S., Sun 14/09/2008 16:26:58

Previous topic - Next topic

J.E.S.

I want to have the cursor graphic change depending on where it is in relation to the player. For example, it the cursor is on the right side of the player, the cursor will point to the right or whatever direction. I can easily code the basic 4 directions (up,down,left,right) but it gets a bit more complicated trying to code all the directions in between. Another to point out is, it appears that the character can move in a possible 16 different directions, so sometimes it doesn't walk exactly on a 45 degree angle, but on a 22.5. Any help would be appreciated.

Khris

First you need to calculate the angle of the vector from the player's position to the mouse position.

vdir = (mouse.x - player.x, mouse.y - player.y);
v2 = (0, -1);    v2 is a reference vector pointing upwards.

vdir . v2 = |vdir| |v2| cos θ

θ = arccos ( (player.y - mouse.y) / |vdir| )

Code: ags
  float dx = IntToFloat(mouse.x - player.x);
  float dy = IntToFloat(player.y - mouse.y);
  float len = Maths.Sqrt(dx*dx+dy*dy);
  float angle = Maths.RadiansToDegrees(Maths.ArcCos(dy/len));
  if (dx<0.0) angle = 360.0-angle;


Now we have the angle, where 0 is above the player, 90 to the right, 180 below and 270 to the left.
To convert this to 16 cursors, we need to do
Code: ags
  int curs = FloatToInt((angle+11.25)/22.5);
  if (curs == 16) curs = 0;

The variable curs will hold 0 for above the player, 4 to their right, 8 below them aso.
Now assign 16 consecutive numbers to the cursor sprites and add curs to the first sprite's slot #.

J.E.S.

Wow, thanks Khris! It took me awhile to understand exactly what the code was doing, but I was able to make it work thanks to you. Here is what my working code looks like, but it is only for 8 directions since I haven't created the cursor graphics for the 22.5 degree angles yet.

Code: ags

function repeatedly_execute()
{
//--------------------------------------Cursors------------------------------------------------
float dx = IntToFloat(mouse.x - player.x);
float dy = IntToFloat(player.y - mouse.y);
float len = Maths.Sqrt(dx*dx+dy*dy);
float angle = Maths.RadiansToDegrees(Maths.ArcCos(dy/len));
if (dx<0.0) angle = 360.0-angle;
int curs = FloatToInt((angle+11.25)/22.5);
  
if (curs == 2) mouse.ChangeModeGraphic(eModeWalkto, 132);
else if (curs == 4) mouse.ChangeModeGraphic(eModeWalkto, 130);
else if (curs == 6) mouse.ChangeModeGraphic(eModeWalkto, 136);
else if (curs == 8) mouse.ChangeModeGraphic(eModeWalkto, 135);
else if (curs == 10) mouse.ChangeModeGraphic(eModeWalkto, 137);
else if (curs == 12) mouse.ChangeModeGraphic(eModeWalkto, 129);
else if (curs == 14) mouse.ChangeModeGraphic(eModeWalkto, 133);
else if (curs == 16) mouse.ChangeModeGraphic(eModeWalkto, 131);
}

J.E.S.

After testing the cursor function for awhile, I got a "Floating point divide by zero" error. I tried to duplicate the error and from what I can see, it happens when I don't move the cursor after I click to make my character walk. In other words, I get the error when I let my character walk to the same point my cursor is sitting at. Can this be fixed?

Gilbert

I suppose you don't need to change the cursor if it wasn't moved right?

In that case just change the following part:
Code: ags

float angle = Maths.RadiansToDegrees(Maths.ArcCos(dy/len));
if (dx<0.0) angle = 360.0-angle;
int curs = FloatToInt((angle+11.25)/22.5);
  
if (curs == 2) mouse.ChangeModeGraphic(eModeWalkto, 132);
else if (curs == 4) mouse.ChangeModeGraphic(eModeWalkto, 130);
else if (curs == 6) mouse.ChangeModeGraphic(eModeWalkto, 136);
else if (curs == 8) mouse.ChangeModeGraphic(eModeWalkto, 135);
else if (curs == 10) mouse.ChangeModeGraphic(eModeWalkto, 137);
else if (curs == 12) mouse.ChangeModeGraphic(eModeWalkto, 129);
else if (curs == 14) mouse.ChangeModeGraphic(eModeWalkto, 133);
else if (curs == 16) mouse.ChangeModeGraphic(eModeWalkto, 131);


to:

Code: ags

if (len>0.01) {
  float angle = Maths.RadiansToDegrees(Maths.ArcCos(dy/len));
  if (dx<0.0) angle = 360.0-angle;
  int curs = FloatToInt((angle+11.25)/22.5);
  
  if (curs == 2) mouse.ChangeModeGraphic(eModeWalkto, 132);
  else if (curs == 4) mouse.ChangeModeGraphic(eModeWalkto, 130);
  else if (curs == 6) mouse.ChangeModeGraphic(eModeWalkto, 136);
  else if (curs == 8) mouse.ChangeModeGraphic(eModeWalkto, 135);
  else if (curs == 10) mouse.ChangeModeGraphic(eModeWalkto, 137);
  else if (curs == 12) mouse.ChangeModeGraphic(eModeWalkto, 129);
  else if (curs == 14) mouse.ChangeModeGraphic(eModeWalkto, 133);
  else if (curs == 16) mouse.ChangeModeGraphic(eModeWalkto, 131);
}


(Note that because of precision problems in floating point computations, it is not recommended to use (len==0) or (len!=0) to check whether the variable equals zero. Instead it is more advisable to check whether it is close to zero.)

J.E.S.

Thanks Gilbot, I tried your code also. I'm not quite satisfied with how the cursor jumps all over the place as it dynamically updates while the character is moving, then the cursor would be facing some obscure direction when the character stops. I have also considered tweaking this code to check the mouse coords in relation to screen coords instead. I'm not sure how I could do that though.

How can I change...

Code: ags

float dx = IntToFloat(mouse.x - player.x);
float dy = IntToFloat(player.y - mouse.y);


...to reflect the location of the mouse compared to the center of the screen?

Khris

Yes, I meant to incorporate a division by zero check while writing the entire post and still forgot it in the end :)
Thanks, Gilbot.

Code: ags
  float dx = IntToFloat(mouse.x - 320);
  float dy = IntToFloat(200 - mouse.y);


(Assuming you're using 640x400.)

J.E.S.

Thanks again Khris, I'm serious thinking about just switching back to a static cursor. Either way I try to code this function I still get little undesirable effects. Accuracy is the main problem, sometimes my character will stop before he even gets to the mouse location. I notice my hotspots don't work as well as they used to either when you mouse over them. I'm sure this has something to do with the cursor hotspot itself, and I don't think you can change that with script, or am I wrong?

Khris

You've got to make sure that all the cursor sprites are of the same size and the arrow is centered within the sprite's borders, plus the cursor hotspot should be in the exact center, too.

Another idea I had is to elevate the character's reference point from his feet to e.g. his waist.

J.E.S.

Yea good point Khris, I went back to check how my sprites were cropped and noticed that the auto crop feature in AGS didn't do a good job, so I had to crop each one seperately...I'll mark this one as solved.

SMF spam blocked by CleanTalk