How do I find if the cursor is in a segment of the screen?

Started by Scavenger, Mon 15/07/2013 12:02:28

Previous topic - Next topic

Scavenger

I'm trying to do another interface for my game, as switching to the keyboard becomes a bit cumbersome even when you are switching playstyles and I want to throw the player a bit of a bone.

I know how to get the mouse cursor if it's in one of four segments around the screen (it's easy - you just check whether the player's screen coords are above or below the mouse.x and y.) but I'm at a loss as to how to do 8 segments.


Here's a crude depiction of what I'm trying to achieve. Is there a math-only way to do this? The player will be walking across the screen and could be at any arbitrary point on it, and I'm just not sure how to find this. I was thinking I could make an image and reference a pixel on that (by transposing it to an array - not using GetPixel, which is slow as hell) to see which segment the player is in, but that seems really wasteful, memory wise.

Any ideas?

Snarky

Basically, calculate the mouse position relative to the center of the screen character. Then -y/x = tan(theta), so calculate arctan(-y/x) to give you the angle. (Use negative Y because y goes downwards on the screen, unlike on a conventional coordinate system. I'm assuming the AGS ArcTan function doesn't already compensate for this.)

Oh, and to find the segment... you have 8 segments, each taking up 2*pi/8 radians, but shifted 2*pi/16 from the horizontal, so take the angle (in radians), subtract pi/8 and multiply by pi/4 to give you the number of the segment you're in.

Code: AGS

int player_height = 100; // I can't be bothered to figure out how to calculate this dynamically right now

int x_diff = mouse.x - player.x;
int y_diff = mouse.y - player.y + player_height/2;
if(x_diff == 0 && y_diff == 0)
{
    // Clicked in the exact center... Do whatever you want to do, I guess
}
else
{
  float theta = Maths.ArcTan2(Maths.IntToFloat(-y_diff), Maths.IntToFloat(x_diff));
  int segment = Maths.FloatToInt( (theta - Maths.Pi/8.0) * (Maths.Pi/4.0) );
}


(Not tested.)

Scavenger

Ah, thankyou! I was trying to write it out in AGSScript before you edited in the code, yours looks a lot more efficient! I will implement it immediately!

DoorKnobHandle

#3
Another solution would be to create a 2d vector from the center of your character to the mouse cursor, normalize that vector, then calculate the dot product of that vector with normalized directional vectors ([1,0], [0,1], 1/sqrt(2)*[1,1] etc., your eight directions [NOTE: precalculate these to be normalized of course]) and keep track of which dot product yielded the lowest result. That one is the sector the mouse is in.

This substitutes the expensive trigonometry operation arctan with (granted, many more) additions and multiplications. If it's faster in AGS I don't know! Of course, you're doing this arctan call only once every frame so it's not going to be a big deal anyways.

Khris

While we're adding ways to do this: one could draw a mask of the zones, import it as sprite, then translate the coordinates and use DrawingSurface.GetPixel() to find the zone. This is also the best way in case the zones aren't easily expressed by math.

Phemar

For a character's height, get their current Viewframe*, then use Game.SpriteHeight[Viewframe.Graphic].

You might have to multiply it by Room.GetScalingAt(x,y)/100 for it work with scaling.

SMF spam blocked by CleanTalk